Зачем вообще контролировать срок действия SSL
Истекший SSL — это мгновенная потеря доверия и конверсии: браузеры показывают красные экраны, API-клиенты роняют соединения, платёжные виджеты прекращают работу. При этом проблема полностью предсказуема: у каждого сертификата есть срок действия, а даты выпуска и продления — под вашим контролем. Ключ к надёжности — инвентаризация всех имен, мониторинг срока действия, своевременные алерты и отработанные процедуры автообновления с безостановочной перезагрузкой веб- и балансирующих сервисов.
Зрелая схема выглядит так: вы заранее видите, что истекает, автоматом продлеваете в удобное окно, атомарно перегружаете процессы и проверяете факт раздачи нового сертификата. Без сюрпризов и ночных дежурств.
Быстрые проверки вручную
Когда нужно «прямо сейчас» понять, что у хоста за сертификат и когда он истекает, используйте openssl:
# Сводка по удалённому хосту (лист, issuer, subject, даты)
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates
# Сколько секунд осталось до истечения (0 — уже истёк)
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate | awk -F= '{print $2}' | xargs -I{} date -d "{}" +%s | awk -v now=$(date +%s) '{print $1-now}'
# Проверка «истечёт ли в ближайшие 30 дней» (число секунд: 30*24*3600 = 2592000)
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -checkend 2592000 -noout
Если инфраструктура фронтируется балансировщиком, он и определяет цепочку, которую видит клиент. Проверяйте именно внешнюю точку входа, а не внутренние бэкенды.
Инвентаризация доменов и точек входа
Главная причина внезапных истечений — забытые домены, поддомены и альтернативные имена (SAN), которые живут на отдельных виртуальных хостах, CDN, API-шлюзах или почтовых фронтах. Сделайте реестр: домен, роль, где и как выпускается сертификат, кто владелец, способ валидации (HTTP-01/DNS-01), способ деплоя и перезагрузки, где мониторится. При добавлении имен сразу оформляйте и продляйте их через регистрацию доменов.
- Соберите список с помощью конфигураций веб-серверов, Ingress-манифестов, Terraform/Ansible и DNS-зон.
- Убедитесь, что wildcard-домены дополняются SAN-записями для «голого» домена при необходимости.
- Проверьте, что все внешние endpoints покрыты мониторингом (включая API и мобильные бэкенды).
Автоматизированный мониторинг срока действия
Prometheus + Blackbox Exporter
Для наблюдаемости на уровне инфраструктуры используйте blackbox-зонд TLS. Он экспортирует метрику времени до истечения цепочки. Конфигурация модуля и таргетов в blackbox:
# blackbox.yml (фрагмент)
modules:
tls_expiry:
prober: tcp
tcp:
tls: true
tls_config:
insecure_skip_verify: false
preferred_ip_protocol: ip4
# prometheus.yml (jobs фрагмент)
scrape_configs:
- job_name: ssl_expiry
metrics_path: /probe
params:
module: [tls_expiry]
static_configs:
- targets:
- example.com:443
- api.example.com:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox-exporter:9115
Правило алерта (измеряем, сколько осталось до конца цепочки):
# alerting rule (фрагмент)
- alert: SSLCertExpiresSoon
expr: probe_ssl_last_chain_expiry_timestamp_seconds - time() < 86400 * 14
for: 15m
labels:
severity: warning
annotations:
summary: "SSL истекает менее чем через 14 дней"
description: "{{ $labels.instance }}: осталось {{ printf "%.0f" ((probe_ssl_last_chain_expiry_timestamp_seconds - time()) / 86400) }} дн."
- alert: SSLCertExpiresCritical
expr: probe_ssl_last_chain_expiry_timestamp_seconds - time() < 86400 * 7
for: 10m
labels:
severity: critical
annotations:
summary: "SSL истекает менее чем через 7 дней"
description: "{{ $labels.instance }}: срочно продлить"
Преимущество такого подхода: вы ловите и истечение промежуточных сертификатов (chain), а не только листа, что критично при ротации корней.
Лёгкая проверка cron-скриптом
Если полноценного мониторинга нет, начните с простого bash-скрипта, который раз в день проверяет остаток дней и шлёт уведомление:
#!/usr/bin/env bash
set -euo pipefail
HOSTS=(example.com api.example.com)
THRESHOLD_DAYS=${THRESHOLD_DAYS:-30}
ALERT_EMAIL=${ALERT_EMAIL:-admin@example.com}
secs_left() {
local host=$1
echo | openssl s_client -servername "$host" -connect "$host":443 2>/dev/null | openssl x509 -noout -enddate | awk -F= '{print $2}' | xargs -I{} date -d "{}" +%s | awk -v now=$(date +%s) '{print $1-now}'
}
days_left() {
local host=$1
local s=$(secs_left "$host")
if ; then echo -1; else echo $(( s / 86400 )); fi
}
ALERTS=()
for h in "${HOSTS[@]}"; do
d=$(days_left "$h")
if (( d < 0 )); then
ALERTS+=("$h: ошибка проверки")
elif (( d < THRESHOLD_DAYS )); then
ALERTS+=("$h: осталось $d дн")
fi
done
if (( ${#ALERTS[@]} > 0 )); then
printf '%s\n' "${ALERTS[@]}" | mail -s "SSL expiry warnings" "$ALERT_EMAIL"
fi
Добавьте в crontab запуск раз в день, например в 09:00 локального времени.
Пороговые значения и эскалации
- 30 дней — предупреждение владельцу сервиса, старт проверки автообновления.
- 14 дней — эскалация в дежурную смену, проверка успешности автообновления на стенде.
- 7 дней — критический алерт с подтверждением действий по продлению (ручной фолбэк).

Автообновление: Certbot и альтернативы
Certbot с systemd timers
В современных дистрибутивах certbot ставит таймер certbot.timer, который запускает обновление дважды в день и продлевает сертификаты при остатке срока менее 30 дней. Проверьте статус и сухой прогон. На собственном VDS вы полностью контролируете таймеры и хуки.
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
Добавьте хук деплоя, который будет без простоев перегружать веб-сервер только при действительном обновлении:
# /etc/letsencrypt/cli.ini (фрагмент)
post_hook = /usr/local/bin/deploy-ssl-reload.sh
#!/usr/bin/env bash
set -euo pipefail
# deploy-ssl-reload.sh: вызывается certbot'ом, когда сертификат был обновлён
if nginx -t; then
systemctl reload nginx
fi
# для Apache
# apachectl -t && apachectl graceful
# для HAProxy (master-worker)
# systemctl reload haproxy
Важно: используйте reload/graceful, а не restart, чтобы не ронять активные соединения. Подробный гайд по Certbot и безопасным редиректам — в статье «HTTPS, Certbot и HSTS: безопасная настройка».
acme.sh: минималистичная альтернатива
acme.sh — лёгкий клиент ACME на shell. Он удобен, когда нужна гибкость (например, DNS-01 с API провайдера). Базовый сценарий:
# установка в домашний каталог
curl https://get.acme.sh | sh
~/.acme.sh/acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html
~/.acme.sh/acme.sh --install-cert -d example.com --key-file /etc/ssl/private/example.com.key --fullchain-file /etc/ssl/certs/example.com.fullchain.pem --reloadcmd "nginx -t && systemctl reload nginx"
Клиент сам создаст планировщик (cron) и будет вызывать --reloadcmd только при смене файлов сертификата.
HTTP-01 vs DNS-01 и zero-downtime
Для wildcard-нужд чаще востребован DNS-01. Следите, чтобы доступ к DNS API был ограничен и ключи не попадали в логи. Для HTTP-01 убедитесь, что /.well-known/acme-challenge не блокируется редиректами/авторизацией и отдается с фронтового хоста. Подробнее про выпуск wildcard через DNS-01 — в материале автоматизация wildcard-SSL по DNS-01. Если упираетесь в лимиты SAN/Let’s Encrypt, смотрите заметки про оптимизацию заявок и кэш — лимиты и автоматизация SAN.
Коммерческие и wildcard SSL-сертификаты помогут, когда нужен EV/OV, нестандартные алгоритмы или длительная валидация.
Zero-downtime перезагрузки: нюансы по софту
Nginx
nginx -tпроверяет конфиг без перезапуска.systemctl reload nginxпосылает HUP: старые воркеры заканчивают сессии, новые стартуют с новым ключом и цепочкой.- Подтвердите, что пути к
ssl_certificateиssl_certificate_keyодинаковы и читаемы пользователем Nginx; меняйте только содержимое файлов.
Apache
apachectl -tиapachectl graceful— безопасная перезагрузка.- Если используется
mod_md, проверьте автопродление и события хука.
HAProxy
- Режим master-worker позволяет делать
systemctl reload haproxyбез потери соединений. - Храните полный chain в PEM-файле фронтенда, чтобы клиенты всегда получали актуальную цепочку.
Контейнеры и оркестраторы
Docker Compose
Сертификаты монтируйте как тома только для чтения, а перезагрузку делайте командой внутри контейнера:
# пример релоуда Nginx в контейнере
docker compose exec nginx nginx -t
docker compose exec nginx nginx -s reload
Если certbot крутится в отдельном контейнере, используйте общий volume для /etc/letsencrypt и post-hook, который вызовет reload соседнего контейнера (через docker exec или сокет Docker).
Kubernetes
С cert-manager обновление секретов с сертификатами происходит автоматически. Убедитесь, что:
- Ingress-контроллер отслеживает изменения секретов и пересобирает конфиг без рестартов.
- На non-prod кластере заранее проверьте ротацию сертификата: клиенты должны видеть новый chain без потерь трафика.

Проверка результата: что увидеть после релоуда
После продления проверьте, что наружу действительно отдаётся новый сертификат, а не кешированный старый:
openssl s_client -servername example.com -connect example.com:443— смотримnotAfter.curl -vkI https://example.com— убеждаемся, что TLS установился без ошибок, проверяем дату в выдаваемом листе.- Снимите с нескольких точек (например, из разных датацентров), чтобы исключить кэш CDN/edge.
OCSP, цепочки и «скрытые» причины сбоев
Падение TLS возможно даже с неистёкшим листом, если истёк промежуточный сертификат или если у клиента жёсткие требования к OCSP. Несколько практических правил:
- Раздавайте полноценную цепочку (
fullchain.pem), а не только лист. - Проверяйте метрику «время до истечения цепочки», а не только листа.
- При включённом OCSP stapling после ротации сертификата делайте reload, чтобы процесс подтянул свежие ответы.
Системные хуки: reload по факту изменения файла
Помимо post-hook у клиента ACME, можно настроить systemd.path, чтобы отслеживать изменение файлов сертификата и автоматически делать безопасный reload:
# /etc/systemd/system/nginx-cert-reload.service
[Unit]
Description=Reload Nginx after certificate update
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'nginx -t && systemctl reload nginx'
# /etc/systemd/system/nginx-cert-reload.path
[Unit]
Description=Watch cert changes
[Path]
PathChanged=/etc/letsencrypt/live/example.com/fullchain.pem
PathChanged=/etc/letsencrypt/live/example.com/privkey.pem
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now nginx-cert-reload.path
Этот подход удобно масштабировать на множество доменов, создавая шаблонные юниты или используя маски на директории.
Алерты: каналы и шумоподавление
Полезные каналы: e-mail дежурным, webhook в командный чат, события в централизованный syslog/SIEM. Главное — эскалации и дедупликация, чтобы не утонуть в «шторме» однотипных сообщений.
# пример простого webhook-уведомления
WEBHOOK_URL="https://example.chat/api/hook/XYZ"
TEXT="[SSL] example.com expires in 5 days"
curl -X POST -H "Content-Type: application/json" -d "{\"text\":\"$TEXT\"}" "$WEBHOOK_URL"
Для e-mail используйте SMTP-агент, уже настроенный на хосте, и разные темы письма под warning/critical, чтобы MTA/фильтры раскладывали сообщения по нужным папкам.
Процесс и ответственность
Даже идеальная автоматизация ломается, если нет владельца. Назначьте ответственных за домены/сервисы и заведите регламент:
- Как часто аудит доменов и тест автообновления.
- Где хранится контакт на случай ручного продления.
- Какой фолбэк, если ACME недоступен (например, запасной коммерческий сертификат).
- Как оформляется Change и как проходит постфактум-проверка.
Типичные сбои и их устранение
- «Сертификат обновился, но клиент видит старый» — забыли reload/ingress не пересобрал конфиг; проверьте хуки, права на файлы, тома в контейнере.
- «Валидация HTTP-01 не проходит» — редирект на HTTPS с принудительной авторизацией, закрытые порты, кеш CDN; добавьте исключение для
/.well-known/acme-challenge. - «Истёк промежуточный» — проверьте, что используете fullchain от CA, а не вручную собранную цепочку.
- «Слетел CRON/systemd» — проверьте таймеры, логи
journalctl -u certbotили логи cron, уведомляйте об ошибках.
Контроль качества: конечные проверки
Внедрите финальную проверку после каждого релоуда: синтетический тест из внешнего мониторинга, который устанавливает TLS, валидирует цепочку и сравнивает дату истечения с ожидаемым порогом. Успешный тест закрывает инцидент, неуспешный — эскалирует на дежурного.
Итоговая схема «без простоев»
- Инвентаризируйте все публичные имена и точки входа.
- Включите мониторинг срока действия (Prometheus/скрипт) по внешним endpoint.
- Настройте алерты с порогами 30/14/7 дней и эскалациями.
- Включите автообновление (certbot/acme.sh) и проверку
--dry-runна стенде. - Сделайте безопасные reload-хуки или systemd.path по факту смены файлов.
- Автоматизируйте валидацию результата и зафиксируйте процесс в регламенте.
Следуя этому плану, вы превратите риск «ночного» истечения SSL в рутинную и бесшовную процедуру, которую система делает за вас и прозрачно подсвечивает в мониторинге.


