===== Настройка автоматического обновления SSL сертификатов Let's Encrypt в NGINX с помощью Certbot на Debian Linux 13 ===== {{.:pasted:20250905-134232.png }} Базовую настройку веб-сервера **NGINX** для поддержки **HTTPS** мы рассматривали ранее в заметке [[web-server-nginx:how-to-install-lemp-web-server-on-ubuntu-14-04:how-to-install-ssl-certificate-for-https-on-nginx-for-wordpress-phpbb-dokuwiki-sites|Настройка веб-сервера на базе стека LEMP в Ubuntu Server 14.04 LTS. Часть 11. Настройка поддержки HTTPS в Nginx, Wordpress и phpBB]]. В этой заметке мы немного расширим эту тему и рассмотрим то, как можно автоматизировать процесс регулярного обновления SSL сертификатов, привязанных к сайтам nginx. Бесплатные криптографические сертификаты **X.509** будем получать в центре сертификации [[https://letsencrypt.org/ru/|Let's Encrypt]], а с помощью пакета **certbot** настроим автоматизацию обновления этих сертификатов с интеграцией в конфигурацию веб-сервера nginx. ---- ==== Установка Certbot ==== Устанавливаем пакет **certbot** из стандартных репозиториев Debian Linux
# apt install certbot
Создаём каталог для временных файлов Let's Encrypt и делаем его владельцем пользователя и группу, в контексте которых работает веб-сервер:
# mkdir /var/www/letsencrypt
# chown www-data:www-data /var/www/letsencrypt
---- ==== Подготовка NGINX ==== Выносим текущую конфигурацию SSL из /etc/nginx/nginx.conf в отдельный файл /etc/nginx/snippets/ssl.conf
# nano /etc/nginx/snippets/ssl.conf
ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+ECDSA+AESGCM:AES128+EECDH:AES128+EDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!CAMELLIA:!ADH"; ssl_session_cache shared:TLS:20m; #ssl_stapling on; #ssl_stapling_verify on; resolver 77.88.8.8 77.88.8.1 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 10s; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; ssl_dhparam /etc/ssl/dhparams.pem; ssl_certificate /etc/ssl/mydomain.crt; ssl_certificate_key /etc/ssl/private/mydomain.key; Создаём конфигурацию Let's Encrypt для работы certbot:
# nano /etc/nginx/snippets/letsencrypt.conf
location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /var/www/letsencrypt; } location = /.well-known/acme-challenge/ { return 404; } Включаем конфиги ''ssl.conf'' и ''letsencrypt.conf'' в секцию ''server'' для конфигураций сайтов nginx в файлы ''/etc/nginx/sites-available/*.conf'' Например:
# nano /etc/nginx/sites-available/mydomain.conf
... server { listen 443 ssl; include snippets/ssl.conf; include snippets/letsencrypt.conf; ... } ---- ==== Регистрация Certbot ==== Регистрируем экземпляр certbot. В ходе регистрации будет задана пара вопросов.
# certbot register -m petya@mydomain.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at: https://letsencrypt.org/documents/LE-SA-v1.5-February-24-2025.pdf You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Yes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: No Account registered.
Регистрационные файлы попадут в подкаталог ''/etc/letsencrypt/accounts'':
# tree /etc/letsencrypt/
/etc/letsencrypt/ ├── accounts │   └── acme-v02.api.letsencrypt.org │   └── directory │   └── 4f50a3d608bead7e9ae31a15b605af4a │   ├── meta.json │   ├── private_key.json │   └── regr.json ├── cli.ini └── renewal-hooks ├── deploy ├── post └── pre 9 directories, 4 files
---- ==== Запрос сертификатов ==== Перед тестированием следует убедиться в том, что сайты, для которых будут запрашиваться сертификаты, доступны из Интернета. Тестируем работу certbot без фактической генерации сертификатов Let's Encrypt ("холостой" запуск):
# certbot certonly --dry-run --webroot -w /var/www/letsencrypt -d mydomain.ru \
-d blog.mydomain.ru -d forum.mydomain.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log Simulating a certificate request for mydomain.ru and 2 more domains The dry run was successful.
Фактически запрашиваем сертификаты Let's Encrypt:
# certbot certonly --webroot -w /var/www/letsencrypt -d mydomain.ru \
-d blog.mydomain.ru -d forum.mydomain.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log Requesting a certificate for mydomain.ru and 2 more domains Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/mydomain.ru/fullchain.pem Key is saved at: /etc/letsencrypt/live/mydomain.ru/privkey.pem This certificate expires on 2025-11-15. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. ...
---- ==== Конфигурация NGINX ==== Добавляем полученные сертификаты в ''ssl.conf'', закомментировав ссылки на используемые ранее сертификаты длительного срока действия:
# nano /etc/nginx/snippets/ssl.conf
... #ssl_certificate /etc/ssl/mydomain.crt; #ssl_certificate_key /etc/ssl/private/mydomain.key; ssl_certificate /etc/letsencrypt/live/mydomain.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mydomain.ru/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/mydomain.ru/chain.pem; Перезапускаем nginx и проверяем результат:
# systemctl restart nginx
---- ==== Автоматизация обновления ==== Срок действия SSL сертификатов Let's Encrypt - 3 месяца. Настроим автоматическое обновление сертификатов, чтобы не следить за истечением срока и не обновлять вручную каждый раз эти сертификаты. Выполним проверку обновления ("холостой" запуск):
# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/mydomain.ru.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Simulating renewal of an existing certificate for mydomain.ru and 2 more domains - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/mydomain.ru/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Если проверка прошла без ошибок, то можем выполнить фактическое обновление:
# certbot renew
Если срок действия сертификата не близок к окончанию, то он обновлён не будет. Если требуется выполнить форсированное обновление, безотносительно строка действия сертификата, то выполняем такой запуск:
# certbot renew --force-renewal
В конфиг ''/etc/letsencrypt/renewal/mydomain.ru.conf'' можно добавить хук для перезапуска веб-сервера после обновления сертификатов renew-hook = systemctl reload nginx.service Но более простым вариантом передачи хука является запуск certbot с передачей хуков в качестве параметра. Этим мы и воспользуемся для того, чтобы настроить автоматическое применение обновлённых сертификатов службой веб-сервера. В нашем случае после установки пакета **certbot** в системе появляются два новых юнита **systemd**, поэтому создавать собственные юниты, как это описано, например, [[https://internet-lab.ru/certbot_debian|здесь]], у нас необходимости нет. Проверим наличие этих юнитов:
# systemctl list-unit-files | grep certbot
UNIT FILE STATE PRESET ... certbot.service static - certbot.timer enabled enabled ...
Как видим, есть два юнита: * Юнит **certbot.service** отвечает за конфигурацию запуска certbot * Юнит **certbot.timer** отвечает за автоматический запуск юнита certbot.service по определённому расписанию. По умолчанию юниты сконфигурированы следующим образом:
# systemctl cat certbot.service
# /usr/lib/systemd/system/certbot.service [Unit] Description=Certbot Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html Documentation=https://certbot.eff.org/docs [Service] Type=oneshot ExecStart=/usr/bin/certbot -q renew --no-random-sleep-on-renew PrivateTmp=true
# systemctl cat certbot.timer
# /usr/lib/systemd/system/certbot.timer [Unit] Description=Run certbot twice daily [Timer] OnCalendar=*-*-* 00,12:00:00 RandomizedDelaySec=43200 Persistent=true [Install] WantedBy=timers.target
Таким образом, в конфигурации по умолчанию этими двумя юнитами настроен запуск команды "''certbot -q renew --no-random-sleep-on-renew''" с расписанием дважды в сутки с рандомизированным сдвигом (RandomizedDelaySec) чтобы избежать DDoS Let's Encrypt. Если по какой-то причине таймер не включен, то включаем и запускаем его
# systemctl enable --now certbot.timer
Убедимся в том, что таймер появился в списке активных таймеров:
# systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES ... 2025-08-22 20:43:01 10h 2025-08-22 09:58:30 2min 42s ago certbot.timer certbot.service ...
В такой конфигурации обновление сертификатов с помощью certbot произойдёт автоматически тогда, когда до окончания срока действия сертификата останется меньше 30 дней. И всё что нам остаётся - настроить применение новых сертификатов в конфигурации ngix. В Debian пакетный certbot кладёт хуки в каталог ''/etc/letsencrypt/renewal-hooks/deploy/''. Создадим хук в виде простого скрипта:
# nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/sh systemctl reload nginx Сделаем файл исполняемым
# chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Созданный нами хук ''reload-nginx.sh'' не должен срабатывать при каждом запуске службы **certbot.service** инициированном таймером **certbit.timer** (в нашем случае ~ каждые 12 часов), но должен сработать только в момент, когда Let’s Encrypt реально выпустит новый сертификат (раз в ~60–90 дней, если срок жизни стандартный). Обратите внимание на то, что созданный нами хук в каталоге ''/etc/letsencrypt/renewal-hooks/deploy/'' имеет глобальный характер. То есть он будет выполняться при каждой процедуре обновления certboot вне зависимости от того, каким приложением внутри нашей системы эти сертификаты используются. В некоторых случаях в рамках одного сервера могут работать разные приложения, использующие разные сертификаты Let’s Encrypt. В таких ситуациях можно использовать иной подход к управлению хуками и конфигурация перезапуска приложений может настраиваться не глобально в ''/etc/letsencrypt/renewal-hooks/deploy/'', а персонально для каждого сайта через редактирование файлов вида ''/etc/letsencrypt/renewal/mydomain.ru.conf''. В этом файле можно добавить директиву перезапуска нужного приложения в секцию ''[renewalparams]'' ... [renewalparams] ... renew_hook = systemctl reload nginx ---- ==== Удаление ненужных сертификатов ==== Сертификаты используемые в конфигурации веб-сервера хранятся в каталоге ''/etc/letsencrypt/live/'', но иногда бывают ситуации, когда мы изменили состав альтернативных имён в сертификате и тогда получается, что в этом каталоге создаётся новая цепочка хранения. Например, в нашем случае, ранее это был подкаталог ''mydomain.ru'', а после изменения состава имён образовалась новая структура в виде подкаталога ''mydomain.ru-0001''.
# tree /etc/letsencrypt/live/
/etc/letsencrypt/live/ ├── mydomain.ru │   ├── cert.pem -> ../../archive/mydomain.ru/cert2.pem │   ├── chain.pem -> ../../archive/mydomain.ru/chain2.pem │   ├── fullchain.pem -> ../../archive/mydomain.ru/fullchain2.pem │   ├── privkey.pem -> ../../archive/mydomain.ru/privkey2.pem │   └── README ├── mydomain.ru-0001 │   ├── cert.pem -> ../../archive/mydomain.ru-0001/cert1.pem │   ├── chain.pem -> ../../archive/mydomain.ru-0001/chain1.pem │   ├── fullchain.pem -> ../../archive/mydomain.ru-0001/fullchain1.pem │   ├── privkey.pem -> ../../archive/mydomain.ru-0001/privkey1.pem │   └── README └── README
И если мы забыли откорректировать конфигурацию SSL в nginx, то могут возникнуть проблемы с работой сайта. В этом случае, может потребоваться удаление неиспользуемых сертификатов. Однако, руками просто так удалять подкаталог в ''/etc/letsencrypt/live/'' не следует. Certbot устроен так, что ''live/'' содержит лишь символические ссылки на файлы из ''archive/'', а ещё есть метаданные в ''renewal/''. Если удалить только в ''live/'', то конфигурация поломается. Как же правильно удалить более ненужные сертификаты в Certbot? Посмотрим список сертификатов:
# certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Found the following certs: Certificate Name: mydomain.ru-0001 Serial Number: 674520824f3d4bf6c2f3125899466351d8f Key Type: ECDSA Domains: mydomain.ru blog.mydomain.ru forum.mydomain.ru wiki.mydomain.ru Expiry Date: 2025-11-20 06:24:03+00:00 (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/mydomain.ru-0001/fullchain.pem Private Key Path: /etc/letsencrypt/live/mydomain.ru-0001/privkey.pem Certificate Name: mydomain.ru Serial Number: 5010a32577f823b796c290d3192cf898642 Key Type: ECDSA Domains: mydomain.ru blog.mydomain.ru forum.mydomain.ru Expiry Date: 2025-11-15 11:25:20+00:00 (VALID: 85 days) Certificate Path: /etc/letsencrypt/live/mydomain.ru/fullchain.pem Private Key Path: /etc/letsencrypt/live/mydomain.ru/privkey.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Удалим ненужный сертификат, указав в параметре ''--cert-name'' значение из ''Certificate Name'' в выводе предыдущей команды:
# certbot delete --cert-name mydomain.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The following certificate(s) are selected for deletion: * mydomain.ru WARNING: Before continuing, ensure that the listed certificates are not being used by any installed server software (e.g. Apache, nginx, mail servers). Deleting a certificate that is still being used will cause the server software to stop working. See https://certbot.org/deleting-certs for information on deleting certificates safely. Are you sure you want to delete the above certificate(s)? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Deleted all files relating to certificate mydomain.ru.
Такой метод удаления сертификата безопасный, так как certbot уберёт ссылки из ''live/'', файлы из ''archive/'' и соответствующий .conf в ''renewal/''. После этого проверяем список сертификатов повторно:
# certbot certificates
При необходимости можно удалить все ранее запрошенные сертификаты, после чего запросить заново свежий сертификат. ---- Проверено на следующих конфигурациях: ^ Версия ОС ^ Версия certbot ^ Версия NGINX ^ | Debian GNU/Linux 13.0 (Trixie) | certbot 4.0.0-2 | nginx 1.26.3-3 | ---- {{:user:blogroot.png?50&nolink |}} Автор первичной редакции:\\ [[user:blogroot|Алексей Максимов]] \\ Время публикации: 05.09.2025 11:50 {{tag>"Let's Encrypt" "Debian 13" "Debian Trixie" NGINX certbot }} ~~DISCUSSION~~