Автоматическое обновление сертификатов Certbot для Nginx по таймеру Systemd

SSL-сертификаты от Certbot легко ставить, ими удобно пользоваться, но действуют они только 90 дней, а значит вы наверняка захотите автоматизировать их обновление.

Если вы используете Ubuntu, Debian или другую систему с предустановленным Systemd, то регулярный запуск процесса обновления вы можете организовать с помощью юнита и таймера Systemd. Каждую неделю Systemd будет запускать программу certbot, чтобы та сама обновила сертификаты и предупредила об этом сервер Nginx, а вы сможете контролировать процесс с помощью логов и journalctl.

Из этого туториала вы узнаете, как настроить автоматическое обновление SSL-сертификатов для Nginx с помощью Certbot и Systemd.

Прежде чем приступить

Чтобы суметь пройти по этоту туториалу вам понадобятся:

Обновляем сертификат вручную

Прежде, чем браться за автоматизацию, давайте проверим всю схему вручную.

К этому моменту у вас уже должен быть Linux-сервер с доменным именем, там настроены Nginx и Certbot. В туториале мы сразу перейдём к проблеме обновления сетрификата.

Обновлением SSL-сертификата занимается та же программа, что его создаёт – это certbot. Запустим программу с ключом renew:

# certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/demosite.dvmn.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
  /etc/letsencrypt/live/demosite.dvmn.org/fullchain.pem expires on 2021-08-22 (skipped)
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Вывод программы выглядит хорошо, ничего не взорвалось. Но если приглядеться внимательнее, то заметим, что certbot обновлять сертификаты даже и не пытался:

No renewals were attempted.

Не удивительно, что у Certbot всё получилось 😆.

Чтобы тестирование скриптов было надёжным, заставим certbot отключить проверку устаревания сертификатов и принудительно их обновить. Отключить эту проверку можно с помощью флага --force-renewal:

# certbot renew --force-renewal
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/demosite.dvmn.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate for demosite.dvmn.org
Running deploy-hook command: systemctl reload nginx.service

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/demosite.dvmn.org/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded: 
  /etc/letsencrypt/live/demosite.dvmn.org/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

На этот раз Certbot действительно обновил сертификат. Программа работает, можно двигаться дальше.

Перезагружаем конфигурацию Nginx

SSL-сертификат нужен для работы веб-сервера Nginx. Каждый раз, когда к нему обращается браузер или другой клиент, то общение с сервером начинается с проверки подлинности сертификата. Для этого Nginx считывает содержимое файлов, созданных Certbot:

Congratulations, all renewals succeeded: 
  /etc/letsencrypt/live/demosite.dvmn.org/fullchain.pem (success)

Однако, Nginx не будет считывать файлы при каждом новом обращении. Вместо этого он считывает сертификаты всего лишь раз, запоминает, и дальше пользуется закэшированной их версией. По этой причине Nginx не узнает об изменении сертификатов, пока вы сами ему не сообщите.

У Nginx есть как минимум два способа сбросить кэш с SSL-сертификатами: это restart и reload. Первая команда restart перезапускает Nginx целиком, и делает сайт недоступным для пользователей на время перезапуска. Вторая команда reload позволяет Nginx продолжить работу, но требует перечитать конфиги и связанные с ними файлы.

Чтобы не отлючать лишний раз сайт выберем команду reload. Проверим её работу вручную:

# systemctl reload nginx.service

В консоли нет явных подтверждений того, что перезапуск прошёл успешно, поэтому заглянем в логи Nginx.

# systemctl status nginx.service 
...
Active: active (running) since Mon 2021-05-24 08:50:33 UTC; 5 days ago
...
May 29 09:45:00 systemd[1]: Reloading A high performance web server and a reverse proxy server.
May 29 09:45:00 systemd[1]: Reloaded A high performance web server and a reverse proxy server.

По строке Active видим, что Nginx работает без остановок уже пять дней, а значит операция reload никак не мешает пользователям сайта, что здорово. Последние две строки сообщают об успешной перезагрузке конфигурации сервера. Отметки времени подтверждают, что это “свежий” Reload, случившийся буквально только что.

Теперь совместим обновление сертификата с перезагрузкой конфигов Nginx. Сделать это можно с помощью стандартного “хука” Certbot post-hook. Через эту настройку можно указать какая команда будет выполнена после обновления сертификата:

# certbot renew --force-renewal --post-hook "systemctl reload nginx.service"
...
Running post-hook command: systemctl reload nginx.service

Ещё раз заглянем в лог Nginx, проверим что перезагрузка конфигов прошла успешно:

# systemctl status nginx.service 
...
May 29 09:45:00 systemd[1]: Reloading A high performance web server and a reverse proxy server.
May 29 09:45:00 systemd[1]: Reloaded A high performance web server and a reverse proxy server.
May 29 09:59:07 systemd[1]: Reloading A high performance web server and a reverse proxy server.
May 29 09:59:07 systemd[1]: Reloaded A high performance web server and a reverse proxy server.

В логе появились две свежие записи о перезагрузке конфигов. Значит, всё в порядке.

Пишем service-файл

Теперь, когда надёжно протестирована команда обновления сертификатов, можем заняться настройкой Systemd. Он нужен для автоматизации. Systemd сам будет каждую неделю запускать обновление сертификатов на сервере.

Для регулярных запусков Systemd требует два файла файла с настройками. Это юниты *.service и *.timer. Начнём с первого.

Создадим новый файл с настройками certbot-renewal.service. Его содержимое выглядит так:

# Содержимое файла /etc/systemd/system/certbot-renewal.service
[Unit]
Description=Certbot Renewal

[Service]
ExecStart={полный путь к certbot} renew --force-renewal --post-hook "systemctl reload nginx.service"

В конфиге не хватает полного пути к certbot. Узнайте его с помощью whereis:

# whereis certbot
certbot: /usr/bin/certbot /snap/bin/certbot

Подставляем путь в certbot-renewal.service:

# Содержимое файла /etc/systemd/system/certbot-renewal.service
[Unit]
Description=Certbot Renewal

[Service]
ExecStart=/usr/bin/certbot renew --force-renewal --post-hook "systemctl reload nginx.service"

Проверим работу юнита: запустим его, дождёмся окончания работы, проверим обновились ли настройки Nginx:

# systemctl start certbot-renewal.service
# systemctl status certbot-renewal.service  
# # ... ждём завершения работы "сервиса" ...
# systemctl status nginx.service 
...
May 29 10:04:13 systemd[1]: Reloading A high performance web server and a reverse proxy server.
May 29 10:04:13 systemd[1]: Reloaded A high performance web server and a reverse proxy server.

Создаём таймер

Настройки для регулярно запускаемых программ Systemd хранит в отдельных файлах *.timer. Они являются дополнением к обычным файлам *.service и, по умолчанию, должны иметь такие же названия. Например, если файл certbot-renewal.service описывает что и как запускать, то когда это делать описано в соседнем файле certbot-renewal.timer.

Создадим новый файл certbot-renewal.timer в той же директории, где находится certbot-renewal.service. Настройки ниже будут запускать обновление SSL-сертификата раз в неделю, не раньше чем через 300 секунд с момента включения сервера:

# Файл /etc/systemd/system/certbot-renewal.timer
[Unit]
Description=Timer for Certbot Renewal

[Timer]
OnBootSec=300
OnUnitActiveSec=1w

[Install]
WantedBy=multi-user.target

Включим таймер, чтобы он начал свой отсчёт:

# sudo systemctl start certbot-renewal.timer

Настроим автоматическое включение таймера на случай перезапуска сервера:

# sudo systemctl enable certbot-renewal.timer

Заглянем в статус таймера, чтобы узнать когда было последнее обновление SSL-сертификата и когда планируется следующее:

# systemctl status certbot-renewal.timer
● certbot-renewal.timer - Timer for Certbot Renewal
     Loaded: loaded (/etc/systemd/system/certbot-renewal.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Sat 2021-05-29 10:49:24 UTC; 3min 4s ago
   Trigger: Sat 2021-06-05 10:52:07 UTC; 6 days left
  Triggers: ● certbot-renewal.service

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

Для верности заглянем ещё раз в логи Nginx и проверим, есть ли там отчёт о последней “свежей” перезагрузке конфигурации:

# systemctl status nginx.service 
...
May 29 10:52:07 systemd[1]: Reloading A high performance web server and a reverse proxy server.
May 29 10:52:07 systemd[1]: Reloaded A high performance web server and a reverse proxy server.

Значит, всё готово. Теперь сертификат будет обновляться раз в неделю, а Nginx подхватит эти изменения.

Читать дальше

Что почитать, если хочется больше деталей:


Попробуйте бесплатные уроки по Python

Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.

Переходите на страницу учебных модулей «Девмана» и выбирайте тему.