# теория · шаг 1 из 5
ACME и certbot
Коротко
Сертификат живёт 90 дней. Продлевать руками четыре раза в год - гарантия однажды забыть, поэтому выпуск автоматизируют по протоколу ACME.
- Проверка http-01 идёт снаружи, по 80-му порту, на путь
/.well-known/acme-challenge/. - Этот путь отдают явным location.
return 301на уровнеserverсрабатывает раньше выбора location и уводит проверку в редирект - замер: 200 против 301. - Продление автоматическое, но новые файлы nginx не подхватит сам: сертификат
живёт в памяти, нужен
reloadчерез--deploy-hook. - Эксперименты гоняют с
--staging: лимит на боевом сервере расходуется быстро.
Если знаешь, почему челлендж отдают отдельным location, и помнишь про --deploy-hook - листай до «Теперь сам».
Сначала ответь сам
server {
listen 80;
server_name shop.local;
return 301 https://$host$request_uri;
location /.well-known/acme-challenge/ { root /var/www/certbot; }
}
Location для проверки написан. Отдаст ли этот блок файл челленджа?
301 https://shop.local/.well-known/acme-challenge/abc
Нет. return на уровне server выполняется на фазе перезаписиРазбирается в разделе 13, глава «return против rewrite»: Фазы: кто и когда решает -
раннем шаге обработки, до того, как выбран location. Ниже, в «Правиле», редирект
перенесён внутрь location /, и тогда тот же путь отдаётся честно - 200 вместо
301. (Два замера сняты с двух блоков стенда на разных портах, поэтому во второй
команде другой порт; на боевом порт один.)
Коварство в том, что Let's Encrypt следует за редиректами и сертификат на том
конце при этом не проверяет: файл он заберёт с https-сервера. Такая схема
работает, пока блок на 443 сам отдаёт /.well-known/acme-challenge/ из того же
каталога, - а он обычно целиком уходит в proxy_pass. И не работает вовсе при
первом выпуске: сертификата ещё нет, и на 443 отвечать некому. Явный location
на 80-м порту ни от чего этого не зависит.
На что это похоже
Заказное письмо с уведомлением. Почтальон приходит по адресу и должен вручить конверт лично, а не оставить записку. Если на двери висит табличка «мы переехали, все вопросы в новый офис», письмо поедет туда - и вручат его, только если в новом офисе есть кому расписаться. А в самый первый раз нового офиса ещё нет вовсе.
Проверку домена надёжнее принимать ровно там, куда она приходит, и не переадресовывать.
Механизм: как проходит http-01
Правило
server {
listen 80;
server_name shop.local www.shop.local;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
shop.local - имя учебного стенда, а не домен для Let's Encrypt
Публичный центр на shop.local сертификат не выдаст: зона .local отведена под
локальное обнаружение (mDNS), проверить такое имя из интернета нельзя. Чтобы
команда ниже сработала, нужен свой публичный домен, запись A или AAAA,
указывающая на этот сервер, и открытый снаружи 80-й порт - имена в -d
и в server_name показанного конфига замени на свои. Для практики без домена берут локальный центр ACME
(например, Pebble) или свой удостоверяющий центр: процедура та же, но
сертификат будет доверенным только у тебя.
certbot certonly --webroot -w /var/www/certbot -d shop.local -d www.shop.local
certonly - только выпустить сертификат, не трогая конфиг; --webroot -w -
каталог, из которого nginx отдаёт файлы челленджа; -d - имя (можно повторять).
Редирект живёт внутри location /, а не на уровне server. Порядок между двумя
блоками решается длиной префикса (четвёртый раздел): путь челленджа длиннее и
побеждает.
Второй способ - certbot --nginx: плагин временно настраивает проверку
домена, затем устанавливает сертификат и сохраняет изменения конфига.
Режим certbot certonly --nginx получает сертификат без постоянной установки
в конфиг. Выбирай режим осознанно и проверяй получившийся diff.
Разбор: почему продление «прошло», а сертификат старый
Замер из прошлой главы: файлы на диске подменили, сервер продолжает отдавать
прежний серийный номер, и только reload меняет картину. Сертификат живёт в
памяти процесса с момента загрузки конфига.
certbot renew --deploy-hook "nginx -s reload"
Пакетные установки часто кладут готовый хук в
/etc/letsencrypt/renewal-hooks/deploy/. Проверить стоит: симптом «сертификат
продлился, а браузер показывает старый и просроченный» - ровно это.
Сравнить файл и то, что реально отдаётся, - две команды:
openssl x509 -in /etc/letsencrypt/live/shop.local/fullchain.pem -noout -enddate
openssl s_client -connect shop.local:443 -servername shop.local </dev/null 2>/dev/null | openssl x509 -noout -enddate
Даты разошлись - не было перезагрузки.
Разбор: что проверять до поломки
certbot renew --dry-run
Прогоняет всю процедуру на тестовом сервере ACME (staging): получает настоящий
по процедуре, но недоверенный тестовый сертификат и не сохраняет его - рабочие
файлы остаются прежними. Побочные действия при этом бывают: certbot может
временно поправить конфиг веб-сервера и перезагрузить его, а --pre-hook и
--post-hook выполняются (не выполняется только --deploy-hook). Это
единственный способ узнать, что продление сломано, до того, как оно
сломается по-настоящему: закрыли 80-й порт файрволом, переписали конфиг, увели
DNS на другой сервер - всё это всплывёт здесь, а не за неделю до истечения.
Таймер продления - это системный планировщик задач (управляется командой
systemctl): его ставит пакет certbot, он ходит дважды в день и обновляет
сертификат, когда до конца остаётся меньше 30 дней.
systemctl list-timers | grep certbot
Что ломается без этого
Лимиты. Let's Encrypt ограничивает число сертификатов на домен в неделю.
Пока эксперименты идут с боевым сервером ACME, лимит расходуется за десяток
попыток, и дальше приходится ждать несколько дней. Для отладки берут
--staging: сертификат оттуда браузер не примет, но всю процедуру проверки
прогонит честно.
Закрытый 80-й порт. Схема «наружу торчит только 443, http закрыт» выглядит разумно и ломает http-01 полностью: центр не сможет забрать файл. Либо открывают 80-й ровно под этот путь, либо переходят на проверку dns-01.
Зачем это в работе
Продление ломается не в день установки, а через два-три месяца, когда все уже
забыли, как настраивали. Поэтому после первого выпуска стоит сделать три вещи:
прогнать --dry-run, убедиться, что хук на месте, и завести мониторинг на срок
сертификата - тот, который смотрит на живое соединение, а не на файл.
Проверка снаружи занимает одну строку:
echo | openssl s_client -connect shop.local:443 -servername shop.local 2>/dev/null | openssl x509 -noout -enddate
Теперь сам
Сайт переехал на новый сервер, DNS переключили, старый сервер пока жив. Через два месяца certbot на новом сервере не может продлить сертификат: проверка http-01 не проходит, хотя 80-й порт открыт и location на месте. Что случилось?
Скорее всего, DNS указывает не туда, куда ты думаешь: часть записей осталась на
старый сервер, и центр сертификации забирает файл именно оттуда, а certbot
кладёт его на новый. Проверяется тем же путём, что использует центр, - запросом
из интернета: curl http://shop.local/.well-known/acme-challenge/тест с чужой
машины, а не с самого сервера.
Главное
Для http-01 проверь доступность файла проверки снаружи по порту 80. После продления сертификата nginx должен начать использовать новые файлы, поэтому нужен успешный reload. Проверяй весь цикл через тестовое продление заранее: наличие таймера ещё не доказывает успешный выпуск и применение.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий