lenec ru

← все посты

Let's Encrypt и certbot: автообновление сертификатов на nginx

10K

Сертификат Let's Encrypt живёт 90 дней. Если ты один раз настроил его руками и забыл — через три месяца сайт встретит пользователей предупреждением о просроченном сертификате. Поэтому автообновление я делаю сразу, в тот же день, когда ставлю TLS.

Расскажу, как у меня это устроено на типичном Ubuntu-сервере с nginx. Конфигурация устойчивая: пережила два миграта, обновление nginx и переезд между хостерами.

Установка certbot

В свежих Ubuntu я ставлю certbot из snap, потому что в обычных репозиториях он отстаёт от апстрима. Но в большинстве рабочих кейсов и apt-овой версии хватает. Покажу обе.

sudo apt update
sudo apt install certbot python3-certbot-nginx

Через snap:

sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Получение сертификата

Если nginx уже отвечает на 80 порту по нужному домену, проще всего использовать webroot или плагин nginx. Я предпочитаю --webroot, потому что он не лезет в конфиг nginx и не перезагружает его в самые неудобные моменты.

Готовим директорию для ACME-челленджа:

sudo mkdir -p /var/www/certbot

В nginx-конфиге обязательно должен быть блок:

server {
    listen 80;
    server_name example.com www.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://example.com$request_uri;
    }
}

Дальше выпускаем сертификат:

sudo certbot certonly \
  --webroot -w /var/www/certbot \
  -d example.com -d www.example.com \
  --email admin@example.com \
  --agree-tos --no-eff-email

В случае успеха ключ и цепочка лежат в /etc/letsencrypt/live/example.com/. Подключаешь их в nginx и делаешь sudo systemctl reload nginx.

Автообновление: systemd-таймер

Современный certbot из коробки ставит systemd-таймер certbot.timer. Проверить можно так:

systemctl list-timers | grep certbot

Вывод — что-то вроде certbot.timer с расписанием два раза в день. Это нормально: certbot реально продлевает сертификат не каждый запуск, а только когда до окончания меньше 30 дней. Просто чаще проверяет.

Если таймера нет (например, ты ставил из снэпа очень старой версии или из самописных deb), легко поднять руками.

# /etc/systemd/system/certbot-renew.service
[Unit]
Description=Certbot renew

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
# /etc/systemd/system/certbot-renew.timer
[Unit]
Description=Run certbot renew twice a day

[Timer]
OnCalendar=*-*-* 03,15:14:00
RandomizedDelaySec=3600
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renew.timer

Самое важное: deploy-hook

Сертификат сам по себе обновляется без проблем. Но nginx продолжит держать в памяти старый файл, пока его не попросишь перечитать. Поэтому хук --deploy-hook "systemctl reload nginx" — это не косметика, а обязательная часть. Без него сертификат на диске свежий, а nginx по-прежнему отдаёт старый, и через 89 дней сайт ляжет с warning'ом.

Можно прописать хук глобально в файле /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh:

#!/bin/sh
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Тогда любой certbot renew после удачного апдейта будет вызывать reload автоматически.

Проверка, что всё реально работает

Главный тест — --dry-run:

sudo certbot renew --dry-run

Эта команда повторяет всю процедуру обновления, но запрашивает у Let's Encrypt тестовый сертификат и не пишет его на диск. Если она прошла без ошибок — настоящий рестарт через 60 дней тоже пройдёт.

Проверка дат сертификатов на сервере:

sudo certbot certificates

А ещё я люблю смотреть из-вне:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates

Что чаще всего ломается

80 порт закрыт фаерволом или отдан другому сервису

ACME-челлендж ходит ровно туда: http://example.com/.well-known/acme-challenge/.... Если 80 закрыт фаерволом или его слушает не nginx, обновление упадёт. Лечится либо открытием порта, либо переходом на --dns-плагин.

nginx не reload-ится после продления

Самая частая причина — забытый deploy-hook. Симптомы простые: сертификат на диске обновился (видно по certbot certificates), а в браузере всё ещё старый. После добавления хука всё лечится.

Просрочили — что делать

Если сертификат уже просрочен, обычный certbot renew может не сработать в зависимости от срока. В таком случае запускаю выпуск заново certbot certonly --webroot ... с теми же доменами и форсю перевыпуск:

sudo certbot certonly --webroot -w /var/www/certbot \
  -d example.com -d www.example.com \
  --force-renewal

Что я делаю на каждом новом сервере

Чтобы потом не возвращаться:

  • ставлю certbot;
  • выпускаю сертификат через webroot;
  • добавляю файл в renewal-hooks/deploy/ с reload nginx;
  • гоняю certbot renew --dry-run и смотрю, что прошло;
  • проверяю, что таймер активен.

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

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.