# теория · шаг 2 из 5
Нативный ACME-модуль nginx
Коротко
С версии 1.29.0 nginx умеет выпускать и продлевать сертификаты сам: ни certbot, ни таймера, ни перезагрузки после продления.
- Ставится пакетом
nginx-module-acmeи подключается директивойload_moduleв самом началеnginx.conf(вне всех блоков). - Обязателен
resolver- без него конфиг не соберётся:acme_issuer: "resolver" is not configured. - А вот забытый
state_path, отсутствиеssl_certificate_cacheи маска вserver_nameпроверку конфига проходят и ломаются уже в работе. - Wildcard модуль не умеет: для них по-прежнему certbot с dns-01.
Если знаешь, что такое acme_issuer и зачем ему state_path - листай до «Теперь сам».
Сначала ответь сам
Модуль подключён, конфиг написан, nginx -t говорит successful. Сколько из
четырёх типовых ошибок ниже он поймал?
acme_issuer le {
uri https://acme-v02.api.letsencrypt.org/directory;
contact mailto:admin@shop.local;
# state_path не указан
}
server {
server_name *.shop.local; # маска
acme_certificate le;
ssl_certificate $acme_certificate;
ssl_certificate_key $acme_certificate_key;
# ssl_certificate_cache не указан
}
Ни одной. Проверка конфига ловит только отсутствие resolver; остальные три
всплывут в работе - первая при перезапуске сервера, вторая под нагрузкой, третья
при первом же выпуске. Это стоит помнить: у модуля nginx -t проверяет
синтаксис, а не осмысленность.
На что это похоже
Разница между «нанять курьера, который раз в квартал ездит за справкой» и «поставить в офисе аппарат, который печатает справку сам». Курьера надо помнить, оплачивать и проверять; аппарат работает молча, но у него свои требования - его надо подключить к сети и не выключать из розетки, иначе всё, что он напечатал, исчезнет.
state_path - это и есть розетка.
Механизм: кто и когда ходит в центр сертификации
Правило
resolver 127.0.0.53; # DNS-сервер: модуль сам ходит в сеть, и ему нужно имя разрешать в адрес
acme_issuer letsencrypt {
uri https://acme-v02.api.letsencrypt.org/directory;
contact mailto:admin@shop.local;
state_path /var/cache/nginx/acme-letsencrypt;
accept_terms_of_service;
}
server {
listen 443 ssl;
server_name shop.local www.shop.local;
acme_certificate letsencrypt;
ssl_certificate $acme_certificate;
ssl_certificate_key $acme_certificate_key;
ssl_certificate_cache max=2; # держать в памяти до 2 сертификатов (RSA и EC), не разбирая файл на каждое соединение
root /var/www/shop;
}
server {
listen 80; # нужен для проверки http-01
server_name shop.local www.shop.local;
return 301 https://$host$request_uri;
}
acme_issuer описывает центр, acme_certificate заказывает сертификат для имён
из server_name, переменные подставляют выпущенное. ssl_certificate_cache
обязателен: при сертификате из переменной без него он разбирается заново на
каждое соединение.
Обрати внимание на блок на 80-м порту: путь /.well-known/acme-challenge/
модуль обрабатывает сам, отдельный location не нужен. Редирект на https ему тоже
не мешает - челлендж модуль перехватывает раньше. Это ровно та ловушка, которая
в предыдущем уроке ломала certbot, и здесь её нет.
Разбор: что ловит проверка конфига, а что нет
Прогон по стенду с настоящим модулем, каждый раз убираем одну строку:
| что убрали | nginx -t |
когда всплывёт |
|---|---|---|
resolver |
[emerg] acme_issuer: "resolver" is not configured |
сразу |
state_path |
successful | при перезапуске сервера: всё выпускается заново |
ssl_certificate_cache |
successful | под нагрузкой: разбор сертификата на каждое соединение |
accept_terms_of_service |
successful | при первом обращении к центру |
маска в server_name |
successful | при выпуске: имена нужны явные |
Первая строка - единственная, ради которой стоит помнить точный текст ошибки.
Остальные четыре - причина, по которой конфиг модуля стоит один раз прогнать не
только через nginx -t, но и через реальный старт со --staging-центром.
Разбор: почему state_path не мелочь
Без него аккаунтный ключ и выпущенные сертификаты живут только в памяти. Они
переживают reload, но теряются при рестарте - и после каждой перезагрузки
сервера всё выпускается заново.
Несколько таких рестартов подряд (обновление ядра, отладка, автоматический перезапуск по сбою) - и упираешься в недельный лимит Let's Encrypt, после чего сайт остаётся без сертификата до конца недели. Каталог содержит приватные ключи, права на него ставят соответствующие.
Что ломается без этого
Две системы на один домен. Если раньше домен вёл certbot, а теперь его ведёт модуль, старый таймер надо выключить. Иначе обе системы выпускают сертификаты на одни и те же имена, съедая лимит вдвое быстрее, а в конфиге остаются пути к файлам, которые уже никто не обновляет.
Первые секунды после старта. Пока сертификат не выпущен, сайт по https не
отвечает. Для боевого сервера это несколько секунд, для тестов - повод не
удивляться, что сразу после docker compose up соединение не устанавливается.
Зачем это в работе
Правило выбора получается простое. Модуль - когда сайтов немного, имена известны и хочется убрать из системы одну движущуюся часть: ни таймера, ни хуков, ни отдельного пользователя с правами на конфиг. certbot - когда нужны wildcard (это только dns-01), когда сертификаты используются не одним nginx (почтовый сервер, база) или когда инфраструктура уже построена вокруг него.
Что происходит, видно в обычном логе ошибок:
[notice] 914#914: ACME: certificate for shop.local, www.shop.local issued,
expires Nov 5 16:02:10 2026 GMT
Теперь сам
Сервер с модулем перезагружали трижды за вечер во время отладки, и теперь сайт не поднимается: сертификата нет, в логе ошибка от центра сертификации. Что произошло и что делать?
Скорее всего, в конфиге нет state_path: при каждом рестарте модуль выпускал
сертификат заново, и три-четыре выпуска подряд выбрали недельный лимит на домен.
Делать: добавить state_path, а на время ожидания лимита переключить uri на
--staging-адрес центра, чтобы отладку можно было продолжать. Сертификат оттуда
браузер не примет, но сайт хотя бы поднимется.
Главное
Нативный ACME-модуль (1.29.0, пакет nginx-module-acme) выпускает и продлевает
сертификаты внутри nginx: acme_issuer описывает центр, acme_certificate
заказывает сертификат для имён из server_name, $acme_certificate подставляет
его в ssl_certificate вместе с обязательным ssl_certificate_cache.
Перезагрузка после продления не нужна, а путь челленджа модуль обрабатывает сам.
Из четырёх типовых ошибок nginx -t ловит только отсутствие resolver;
забытый state_path теряет всё при рестарте и съедает лимиты, а wildcard модуль
не умеет вовсе.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий