Понедельник, 9 утра. В поддержку пишут: «Браузер говорит, что ваш сайт небезопасен». Вы открываете его и видите красный экран с ошибкой NET::ERR_CERT_DATE_INVALID. SSL-сертификат истёк в воскресенье ночью. Автопродление было настроено год назад, и всё это время, как казалось, работало.
Этот сбой обиднее всех остальных: дата окончания сертификата известна за месяцы вперёд, и предотвратить его можно почти бесплатно. Разберём, почему автопродление ломается, как проверить сертификат за минуту, что делать, если он уже истёк, и как настроить контроль, чтобы такое не повторилось.
Что ломается, когда сертификат истекает
Многие думают, что посетители просто увидят предупреждение и нажмут «Всё равно перейти». На деле последствия шире.
Браузеры блокируют сайт. На сайтах с HSTS кнопки «перейти всё равно» нет вовсе. Большинство обычных посетителей уходит сразу.
Ломаются интеграции. Платёжные системы, CRM, службы доставки и мобильные приложения обращаются к вашему API и получают ошибку проверки сертификата. Оплата прошла, а уведомление о ней до сайта не дошло: заказ висит неоплаченным.
Перестают приходить вебхуки. Telegram-боты, платёжные шлюзы и сервисы рассылок не отправляют данные на адрес с невалидным сертификатом.
Страдает SEO. Поисковый робот не может нормально обойти сайт. Короткий сбой переживётся, но несколько дней ошибок уже заметны в позициях.
Падает доверие. Красный экран с надписью «злоумышленники могут украсть ваши данные» запоминается надолго.
Срок жизни сертификатов становится короче
Если вы до сих пор продлеваете сертификат руками раз в год, этот способ заканчивается. Индустрия браузеров и удостоверяющих центров (CA/Browser Forum) приняла поэтапное сокращение максимального срока жизни публичных TLS-сертификатов:
| С какой даты | Максимальный срок сертификата |
|---|---|
| до 15 марта 2026 | 398 дней |
| с 15 марта 2026 | 200 дней |
| с 15 марта 2027 | 100 дней |
| с 15 марта 2029 | 47 дней |
Бесплатные сертификаты Let's Encrypt и так живут 90 дней, и сам Let's Encrypt тоже объявил о переходе на более короткие сроки. Вывод простой: продление должно быть автоматическим, а за автоматикой должен кто-то следить. Чем короче срок, тем чаще продление и тем больше шансов, что однажды оно молча сломается.
Почему автопродление ломается
Certbot, acme.sh, Caddy и Traefik продлевают сертификаты сами. Но «настроил один раз и забыл» работает до первого изменения инфраструктуры. Вот самые частые причины.
Сертификат продлился, а сервер его не подхватил
Самая коварная ситуация. Certbot успешно получил новый сертификат и положил его на диск, но nginx продолжает отдавать старый из памяти, потому что его никто не перезагрузил. В логах certbot всё зелёное, а у посетителей ошибка.
Решение: deploy-hook, который перезагружает веб-сервер после каждого успешного продления.
certbot renew --deploy-hook "systemctl reload nginx"Чтобы хук применялся всегда, а не только при ручном запуске, положите скрипт в специальную папку. Certbot выполняет всё, что в ней лежит, после каждого продления:
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/sh
nginx -t && systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shЗакрыт 80-й порт или сломан редирект
Обычная проверка Let's Encrypt (HTTP-01) обращается к сайту по адресу http://ваш-домен/.well-known/acme-challenge/... на 80-м порту. Если вы закрыли 80-й порт в файрволе «для безопасности» или настроили редирект, который ломает этот путь, продление падает.
server {
listen 80;
server_name example.ru www.example.ru;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}Сайт переехал, а certbot остался на старом сервере
Переносите сайт на новый VPS, копируете файлы и базу, переключаете DNS. Сертификат скопировали вместе с конфигом, и сайт работает. Через два месяца сертификат истекает: таймер продления остался на старом сервере, который уже ничего не обслуживает.
Wildcard-сертификат и токен DNS-провайдера
Сертификат на *.example.ru подтверждается через DNS-запись (DNS-01). Для этого у certbot есть API-токен DNS-провайдера. Токены истекают, отзываются, провайдер меняет API, а домен переносят к другому регистратору. Продление падает, а узнаёте вы об этом через три месяца.
Запись CAA запрещает удостоверяющий центр
CAA-запись в DNS указывает, каким удостоверяющим центрам разрешено выпускать сертификаты для домена. Если там указан только один центр, а вы перешли на другой, выпуск будет отклонён. Проверить запись можно так:
dig +short CAA example.ruПустой ответ означает, что ограничений нет. Если записи есть, в них должен быть ваш центр, например 0 issue "letsencrypt.org".
Несколько серверов за балансировщиком
Сертификат продлился на одном сервере, а запрос проверки пришёл на другой. Или продлился на одном, а остальные три продолжают отдавать старый. Посетители видят ошибку примерно в трёх случаях из четырёх, и проблема выглядит «плавающей».
Сертификат вшит в Docker-образ
Если сертификат копируется в образ при сборке, контейнер будет отдавать ту версию, что была на момент сборки. Сертификаты и ключи нужно монтировать томом, а не копировать в образ.
Таймер продления выключен
После обновления системы, переустановки certbot из snap или смены способа установки таймер может оказаться отключённым. Проверьте, что он есть и когда сработает в следующий раз:
systemctl list-timers | grep -i certbot
certbot renew --dry-runКоманда --dry-run проходит продление целиком на тестовом сервере Let's Encrypt, ничего не меняя. Если она падает, настоящее продление тоже упадёт.
Как проверить сертификат за минуту
Проверять нужно снаружи, тем же путём, каким к сайту приходят посетители. Файл на диске сервера ничего не говорит о том, что на самом деле отдаётся клиентам.
Дата окончания, владелец и издатель:
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -subject -issuer -datesНа какие домены выдан сертификат. Частая ошибка: сертификат выпущен на example.ru, но не на www.example.ru.
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -ext subjectAltNameСколько дней осталось, одной цифрой. Удобно для скриптов:
end=$(echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -enddate | cut -d= -f2)
echo $(( ($(date -d "$end" +%s) - $(date +%s)) / 86400 ))Если серверов несколько, проверьте каждый по его IP, подставив имя домена:
curl -sv --resolve example.ru:443:203.0.113.10 https://example.ru/ -o /dev/null 2>&1 \
| grep -E "expire date|subject:"Неполная цепочка: работает в Chrome, не работает у интеграций
Отдельный вид проблемы, который часто не замечают месяцами. Сертификат действителен, в браузере всё хорошо, но:
curl и wget выдают
unable to get local issuer certificate;часть Android-устройств показывает ошибку;
1С, Java-сервисы и платёжные системы не могут отправить запрос.
Причина: сервер отдаёт только сам сертификат, без промежуточного сертификата удостоверяющего центра. Настольные браузеры умеют сами докачать недостающее звено, а большинство библиотек и устройств нет.
В nginx нужно указывать файл с полной цепочкой. У certbot это fullchain.pem, а не cert.pem:
ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;Проверить цепочку снаружи можно так: если в выводе только один сертификат (только 0 s: без 1 s:), цепочка неполная.
echo | openssl s_client -connect example.ru:443 -servername example.ru -showcerts 2>/dev/null \
| grep -E "^ *[0-9] s:"Если сертификат уже истёк: план на 10 минут
Посмотрите, какой сертификат лежит на диске. Возможно, новый уже получен, и нужно только перезагрузить веб-сервер.
Bashcertbot certificatesЕсли на диске свежий сертификат, проверьте конфиг и перезагрузите nginx:
nginx -t && systemctl reload nginx.Если сертификат на диске тоже старый, запустите продление вручную и прочитайте ошибку. В ней почти всегда прямо написано, что не так: недоступен 80-й порт, неверная DNS-запись, превышен лимит запросов.
Bashcertbot renew --force-renewalПроверьте результат снаружи командой из раздела выше, а не браузером: браузер может закешировать старый результат.
Если сайт за Cloudflare, проверьте и сертификат на вашем сервере. В режиме Full (strict) Cloudflare отказывается работать с истёкшим сертификатом источника и показывает посетителям ошибку 526.
Найдите причину по списку выше и исправьте её, иначе через 90 дней всё повторится.
Если вы упёрлись в лимиты Let's Encrypt на количество выпусков, подождите или временно выпустите сертификат у другого бесплатного центра, например ZeroSSL, который тоже работает по протоколу ACME.
Российские сертификаты: что нужно знать
С 2022 года Минцифры выпускает сертификаты Национального удостоверяющего центра для российских сайтов. Им доверяют Яндекс Браузер и Атом, а также устройства, на которые пользователь вручную установил корневой сертификат. Chrome, Firefox и Safari по умолчанию им не доверяют.
Поэтому для публичного сайта, открытого всем, российский сертификат обычно ставят не вместо международного, а дополнительно, если это требуется. Мониторить при этом нужно оба, у них разные сроки и разные процедуры продления.
Как настроить контроль, чтобы это не повторилось
Хороший мониторинг сертификатов отвечает на три вопроса: когда истекает, валиден ли сейчас и работает ли продление.
Проверяйте каждый домен и поддомен отдельно.
api.example.ru,admin.example.ruи почтовый сервер часто имеют свои сертификаты и свои сроки.Получайте предупреждения заранее и несколько раз: за 21, 14 и 7 дней и ещё раз за сутки. Одно письмо легко пропустить.
Следите за сроком, а не только за датой. Let's Encrypt по умолчанию продлевает сертификат, когда до конца остаётся 30 дней. Если осталось 20 дней, а сертификат не обновился, автопродление уже сломано, хотя до сбоя ещё почти три недели. Это лучший момент, чтобы спокойно разобраться.
Проверяйте валидность, а не только дату: совпадение имени домена, полноту цепочки, отсутствие самоподписанного сертификата.
Следите, что продление вообще запускается.
certbot renewзавершается без ошибки, даже когда продлевать пока нечего. Повесьте сигнал heartbeat на успешный запуск: если certbot перестал запускаться или падает, сигнал не придёт, и вы узнаете об этом за недели до истечения сертификата.
0 4 * * 1 certbot renew --quiet && curl -fsS -m 10 --retry 3 https://getdevpulse.ru/ping/ВАШ_КОД > /dev/nullДля такого монитора подойдёт период в неделю и запас в один день. Если certbot у вас уже запускается через systemd-таймер, лишний запуск из cron ничего не сломает: сертификат продлится только тогда, когда это нужно.
Не забудьте про срок регистрации домена. Он ломает всё так же, как истёкший сертификат, только сильнее: перестаёт работать не только HTTPS, но и сайт целиком, вместе с почтой.
Чек-лист
Продление автоматическое: certbot, acme.sh, Caddy или Traefik.
certbot renew --dry-runпроходит без ошибок.После продления веб-сервер перезагружается через deploy-hook.
80-й порт открыт, путь
/.well-known/acme-challenge/работает.В nginx указан
fullchain.pem.Сертификат покрывает и домен, и
www, и все нужные поддомены.CAA-записи разрешают ваш удостоверяющий центр.
Сертификаты не вшиты в Docker-образы.
Внешний мониторинг следит за сроком и валидностью каждого сертификата.
Продление отправляет heartbeat-сигнал.
Срок регистрации домена тоже под контролем.
DevPulse проверяет сертификат и срок регистрации домена у каждого сайта в мониторинге и заранее предупреждает в Telegram, MAX, ВКонтакте, Discord или на почту: о сертификате за 21, 14 и 7 дней и за сутки, о домене за 30, 14 и 7 дней. Если сертификат выдан Let’s Encrypt и не продлился вовремя, в уведомлении будет прямо сказано, что сломалось автопродление. Запуски certbot можно отслеживать heartbeat-монитором. До 10 мониторов бесплатно: начните здесь.