Автоматическое обновление SSL-сертификатов Let's Encrypt в Nginx с Certbot: полное руководство | AdminWiki

Автоматическое обновление SSL-сертификатов Let's Encrypt в Nginx с Certbot: полное руководство

07 августа 2026 10 мин. чтения

Почему автоматизация продления сертификатов критически важна

Сертификаты Let's Encrypt действительны 90 дней. Это осознанное решение центра сертификации, стимулирующее автоматизацию. Ручное обновление четырежды в год кажется простым, пока вы не пропустите срок. Просроченный сертификат означает, что браузеры клиентов покажут предупреждение о небезопасном соединении. Пользователи уйдут, API-интеграции оборвутся, репутация пострадает.

Человеческий фактор - главный враг стабильности. Отпуск администратора, болезнь, высокая загрузка или сбой в почтовом напоминании от Let's Encrypt приводят к простою. Автоматизация решает эту проблему радикально: сертификаты продлеваются без участия человека. Certbot предоставляет два встроенных механизма - cron и systemd timer. Оба запускают certbot renew по расписанию и перезагружают Nginx для применения новых сертификатов. После настройки вы можете забыть о рутине и сосредоточиться на задачах, которые требуют вашей экспертизы.

В этом руководстве мы настроим автоматическое продление двумя способами, настроим безопасную перезагрузку Nginx без разрыва соединений и наладим мониторинг. Все команды проверены на Ubuntu 24.04, Debian 12 и CentOS Stream 9. Если вам нужна базовая настройка HTTPS с нуля, обратитесь к полной инструкции по получению сертификатов Let's Encrypt для Nginx и Apache.

Предварительные требования и проверка окружения

Перед настройкой автоматизации убедитесь, что сертификаты уже выпущены и корректно работают. Проверьте список установленных сертификатов:

sudo certbot certificates

Вывод покажет домены, путь к файлам сертификатов и дату истечения. Если список пуст, сертификаты не выпущены. Вернитесь к первичной настройке - автоматизация без действующих сертификатов бессмысленна.

Проверьте версии ПО. Минимальные требования: Certbot 1.0 и Nginx 1.14. Более старые версии могут не поддерживать флаг --renew-hook или корректную перезагрузку. Узнать версии можно командами:

certbot --version
nginx -v

Убедитесь, что у процесса, который будет запускать продление, есть права на запись в каталог /etc/letsencrypt/. Оба способа - cron и systemd timer - мы настроим от root. Это стандартная практика, поскольку сертификаты и приватные ключи должны быть защищены от чтения непривилегированными пользователями.

Порты 80 и 443 должны быть открыты на файрволе и доступны из интернета. Certbot использует HTTP-01 верификацию, которая требует входящего соединения на порт 80. Проверьте правила iptables или ufw:

sudo ufw status verbose

Если вы используете CDN или прокси-сервер перед Nginx, метод HTTP-01 может не сработать. В таких случаях применяется DNS-01 верификация, но это тема отдельного руководства. Для стандартной конфигурации с прямым доступом к серверу HTTP-01 работает без дополнительных настроек.

Способ 1: Автоматизация через cron

Cron - классический планировщик задач в Unix-подобных системах. Он работает десятилетиями, прост в настройке и присутствует в любом дистрибутиве Linux. Для автоматического продления сертификатов мы создадим задание, которое ежедневно запускает certbot renew и перезагружает Nginx только при фактическом обновлении.

Настройка cron-задачи для certbot renew

Certbot достаточно умён, чтобы не продлевать сертификаты при каждом запуске. Команда renew проверяет срок действия всех установленных сертификатов и обновляет только те, у которых до истечения осталось менее 30 дней. Ежедневный запуск безопасен и не создаёт лишней нагрузки на инфраструктуру Let's Encrypt.

Откройте crontab пользователя root:

sudo crontab -e

Добавьте строку:

0 0 * * * certbot renew --quiet --renew-hook "systemctl reload nginx"

Разберём синтаксис. Пять полей расписания 0 0 * * * означают запуск ежедневно в полночь. certbot renew проверяет все сертификаты. Флаг --quiet подавляет стандартный вывод - cron не будет слать письма при каждом успешном запуске. --renew-hook выполняет указанную команду только после успешного обновления хотя бы одного сертификата.

Альтернативный вариант - разместить скрипт в каталоге /etc/cron.daily/. Создайте файл /etc/cron.daily/certbot-renew:

#!/bin/bash
certbot renew --quiet --renew-hook "systemctl reload nginx"

Сделайте его исполняемым:

sudo chmod +x /etc/cron.daily/certbot-renew

Скрипты в /etc/cron.daily/ выполняются анакроном - подсистемой, которая гарантирует запуск пропущенных задач, если сервер был выключен в запланированное время. Это даёт небольшое преимущество перед классическим cron, но оба варианта работают надёжно.

Безопасная перезагрузка Nginx через --renew-hook

Ключевой момент автоматизации - перезагрузка Nginx только после фактического обновления сертификатов. Если перезагружать сервер по фиксированному расписанию, вы будете зря дёргать рабочие процессы 80% времени. Хуже того, если перезагрузка совпадёт с моментом высокой нагрузки, это может вызвать кратковременную деградацию сервиса.

Флаг --renew-hook решает проблему элегантно. Хук выполняется исключительно после успешного обновления сертификата. Если продление не потребовалось, Nginx продолжает работать без вмешательства.

Почему reload, а не restart? Команда systemctl reload nginx отправляет мастер-процессу сигнал SIGHUP. Nginx перечитывает конфигурацию и применяет новые сертификаты без разрыва установленных соединений. Клиенты не замечают перезагрузки. Команда restart полностью останавливает и запускает сервер - все активные соединения обрываются. Для production-среды разница критична. Если вы углубляетесь в тему безопасности Nginx, рекомендуем готовую конфигурацию с TLS 1.3 и усиленными параметрами безопасности.

Способ 2: Автоматизация через systemd timer

Systemd timer - современная альтернатива cron в дистрибутивах с systemd (Ubuntu 16.04+, Debian 8+, CentOS 7+). Таймеры systemd предоставляют детальное логирование через journald, гарантируют запуск пропущенных задач после простоя сервера и позволяют задавать сложные расписания с точностью до секунды. Для критичных сервисов это предпочтительный метод.

Создание unit-файла сервиса certbot-renew.service

Создайте файл сервиса, который будет выполнять продление:

sudo nano /etc/systemd/system/certbot-renew.service

Содержимое файла:

[Unit]
Description=Certbot Renew Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload nginx"

Директива Type=oneshot указывает systemd, что сервис выполняет однократное действие и завершается. Это правильный тип для задач, которые не остаются в памяти. After=network.target гарантирует, что сеть доступна перед запуском - Certbot не сможет связаться с серверами Let's Encrypt без сетевого соединения.

Обратите внимание на полные пути к исполняемым файлам: /usr/bin/certbot и /bin/systemctl. Systemd требует абсолютные пути, в отличие от cron, который использует PATH пользователя.

Создание unit-файла таймера certbot-renew.timer

Таймер определяет расписание запуска сервиса. Создайте второй файл:

sudo nano /etc/systemd/system/certbot-renew.timer

Содержимое:

[Unit]
Description=Certbot Renew Timer
Requires=certbot-renew.service

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

Директива OnCalendar=daily запускает задачу раз в сутки в полночь. Можно указать точное время: OnCalendar=*-*-* 03:00:00 - ежедневно в 3 часа ночи. Persistent=true критически важна: если сервер был выключен в запланированное время, таймер запустит задачу сразу после загрузки. Без этой директивы пропущенный запуск будет проигнорирован, и сертификат может истечь.

Активируйте таймер:

sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renew.timer

Проверьте статус:

sudo systemctl status certbot-renew.timer
sudo systemctl list-timers --all | grep certbot

Вывод покажет следующее срабатывание таймера и время последнего запуска. Если таймер активен, автоматизация настроена.

Сравнение cron и systemd timer: что выбрать

Оба метода выполняют задачу. Выбор зависит от вашего окружения и требований к мониторингу.

Systemd timer выигрывает по трём параметрам. Первое - логирование. Все запуски сервиса попадают в journald, доступны через journalctl -u certbot-renew.service и не теряются при ротации логов. Cron по умолчанию пишет в syslog вперемешку с другими сообщениями. Второе - гарантия запуска пропущенных задач через Persistent=true. Cron не обрабатывает пропуски: если сервер был выключен в полночь, задача не выполнится до следующих суток. Третье - изоляция. Каждый таймер systemd - независимая единица с собственным окружением, тогда как cron-задачи разделяют общее окружение и могут конфликтовать.

Cron остаётся актуальным для legacy-систем без systemd (Alpine Linux, старые версии CentOS) и для администраторов, которые привыкли к простоте crontab. Настроить cron быстрее: одна строка против двух unit-файлов. Если у вас современный дистрибутив, используйте systemd timer. Если вы поддерживаете зоопарк серверов разных поколений, cron обеспечит единообразие.

Для комплексной защиты веб-сервера после настройки сертификатов изучите руководство по SSL/TLS и HTTPS в Nginx с настройкой HSTS и reverse proxy.

Мониторинг и уведомления о сбоях

Автоматизация без мониторинга - чёрный ящик. Вы настроили продление, но откуда вы знаете, что оно работает? Через 60 дней после настройки сертификат может истечь, если процесс незаметно сломался. Настройте наблюдение сразу, а не после инцидента.

Анализ логов Certbot и Nginx

Certbot пишет подробный лог в /var/log/letsencrypt/letsencrypt.log. Проверьте последние записи:

sudo tail -50 /var/log/letsencrypt/letsencrypt.log

Успешное продление содержит строки:

Successfully renewed certificate for example.com
Running renew-hook command: /bin/systemctl reload nginx

Ошибки выглядят иначе. Например, проблема с сетью:

Failed to connect to acme-v02.api.letsencrypt.org:443

Для systemd-таймера логи дублируются в journald:

sudo journalctl -u certbot-renew.service --since "1 week ago"

Эта команда показывает все запуски сервиса за неделю. Настройте еженедельную проверку логов вручную или автоматизируйте её.

Настройка уведомлений при ошибках продления

Пассивный просмотр логов не сработает, если вы не проверяете их регулярно. Нужно активное оповещение. Certbot поддерживает флаг --renew-hook для успешного обновления, но для ошибок прямого хука нет. Решение - обернуть вызов в скрипт, который проверяет код возврата.

Создайте скрипт /usr/local/bin/certbot-renew-notify.sh:

#!/bin/bash
/usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload nginx"
if [ $? -ne 0 ]; then
    echo "Certbot renewal failed on $(hostname) at $(date)" | mail -s "SSL Renewal FAILED" admin@example.com
fi

Замените admin@example.com на ваш email. Сделайте скрипт исполняемым и укажите его в cron или systemd-сервисе вместо прямого вызова certbot. Теперь при любой ошибке вы получите письмо.

Альтернатива для систем мониторинга - проверка срока действия сертификата. Скрипт может запрашивать дату истечения через openssl и отправлять метрику в Zabbix, Prometheus или Datadog. Настройте алерт за 14 дней до истечения - это даст запас времени на решение проблем.

Типичные ошибки и их решение

Даже правильно настроенная автоматизация иногда ломается. Разберём частые ошибки и способы их исправления.

Ошибка: не удается подключиться к порту 80

Certbot использует HTTP-01 верификацию. Временный веб-сервер certbot поднимается на порту 80 и ожидает запроса от серверов Let's Encrypt. Если порт занят другим процессом или закрыт файрволом, верификация проваливается.

Проверьте, кто слушает порт 80:

sudo ss -tlnp | grep :80

Если порт занят Nginx, это нормально. Certbot умеет работать с Nginx через плагин и временно модифицирует конфигурацию. Проблема возникает, когда на порту висит другой веб-сервер (Apache, Caddy) или кастомное приложение. Остановите конфликтующий сервис на время продления или настройте DNS-01 верификацию.

Проверьте файрвол:

sudo iptables -L -n | grep :80

Порт 80 должен быть открыт для входящих соединений с любых IP-адресов. Серверы Let's Encrypt используют разные IP, белый список невозможен.

Ошибка: недостаточно прав для записи сертификатов

Каталог /etc/letsencrypt/ и все файлы в нём принадлежат root с правами 700. Если cron-задача или systemd-сервис запущены от непривилегированного пользователя, certbot не сможет обновить файлы.

Решение - всегда запускать продление от root. Для cron используйте sudo crontab -e (не пользовательский crontab без sudo). Для systemd сервис по умолчанию запускается от root, если не указана директива User=. Проверьте, что в unit-файле нет строки User=someuser.

Если вы вынуждены использовать непривилегированного пользователя, настройте sudo с ограниченными правами. Добавьте в /etc/sudoers.d/certbot:

someuser ALL=(root) NOPASSWD: /usr/bin/certbot renew *

Это разрешит конкретному пользователю запускать certbot renew от root без пароля. Менее безопасно, но приемлемо в контролируемой среде.

Тестирование автоматического продления

Перед тем как положиться на автоматизацию, проверьте её в деле. Certbot предоставляет режим сухого прогона - --dry-run. Он симулирует полный цикл продления, включая обращение к серверам Let's Encrypt, но не сохраняет сертификаты и не учитывает лимиты на запросы.

Выполните тестовый запуск:

sudo certbot renew --dry-run

Успешный вывод содержит строку:

Congratulations, all simulated renewals succeeded

Если видите ошибку, исправьте её до настройки автоматизации. Сухой прогон проверяет достижимость серверов Let's Encrypt, корректность конфигурации плагинов и права доступа.

Для проверки хука перезагрузки Nginx запустите продление принудительно с флагом --force-renewal. Этот флаг заставляет certbot обновить сертификаты, даже если срок истечения далеко. После выполнения убедитесь, что Nginx перезагрузился и сертификаты обновились:

sudo certbot renew --force-renewal --renew-hook "systemctl reload nginx"
sudo systemctl status nginx | grep "Main PID"

PID мастер-процесса должен измениться после reload, но активные соединения сохранятся. Откройте сайт в браузере и проверьте дату сертификата - она должна обновиться.

Для systemd-таймера запустите сервис вручную:

sudo systemctl start certbot-renew.service
sudo systemctl status certbot-renew.service

Статус должен показать успешное завершение с кодом 0.

Заключение: полностью автоматизированное управление SSL

Вы настроили систему, которая продлевает сертификаты Let's Encrypt без участия человека. Выбран метод - cron для простоты и совместимости или systemd timer для детального контроля и логирования. Настроена безопасная перезагрузка Nginx через --renew-hook, которая применяет новые сертификаты без разрыва соединений. Налажен мониторинг с оповещениями о сбоях.

Проверьте логи через неделю после настройки. Убедитесь, что продление отрабатывает штатно, и письма о сбоях не приходят. Дальше система работает автономно. Единственное, что может потребовать внимания - смена доменного имени, перенос сервера или радикальное изменение сетевой конфигурации. Для дополнительного усиления защиты веб-сервера используйте полное руководство по защите Nginx и Apache с WAF и security-заголовками.

Автоматическое обновление SSL - базовая гигиена современного веб-сервера. Настроив его один раз, вы исключаете риск просрочки сертификатов навсегда.

Поделиться:
Сохранить гайд? В закладки браузера