Истёкший сертификат не предупреждает о себе. Вчера сайт работал, сегодня браузер показывает предупреждение, посетители уходят, а поисковые системы начинают сомневаться в надёжности адреса. У сертификата нет свойства напоминать, и единственная защита от простоя это рутина: регулярная проверка сроков скриптом и автоматическое продление там, где оно возможно. Хорошая новость в том, что вся механика укладывается в один скрипт и один таймер, а плохая в том, что без этой рутины даже автоматика остаётся без страховки. Статья разбирает ручную проверку, скрипт для парка хостов, автоматическое продление и порядок, при котором истечение перестаёт быть событием.

Цена забытого сертификата и роль рутинной проверки

Арифметика простоя не радует. Для коммерческого сайта предупреждение браузера это потеря почти всех новых посетителей на период от восстановления до повторного прихода. Для внутренних сервисов истёкший сертификат это каскад отказов интеграций: клиенты с проверкой цепочки перестают подключаться, мониторинг фиксирует волну сбоев, а разбор занимает часы. И во всех сценариях причина одна: срок, о котором никто не вспомнил.

Сертификаты живут разной жизнью. Платные выдаются на год и требуют ручной закупки и установки. Бесплатные через автоматизированную утилиту выдаются на короткие сроки, обычно несколько месяцев, и продлеваются сами. Короткий срок бесплатных это одновременно и стресс, и дисциплина: продление происходит часто, и сбой автоматики виден быстро. Годовые платные расслабляют, и именно они истекают чаще всего, потому что за год о них забывают все.

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

Порог предупреждения выбирается с запасом на bureaucracy: платный сертификат требует закупки, согласования и установки, и недели до истечения может не хватить. Практика парков сходится на пороге в месяц для предупреждения первого уровня и в неделю для тревожного. Месяц покрывает любой процесс закупки, неделя отделяет тех, кто просто забыл, от тех, кому уже горит.

Ручная проверка сроков одной командой

Базовая проверка умещается в одну строку. Утилита запроса соединения отдаёт сертификат сервера, а утилита разбора сертификата печатает даты действия:

openssl s_client -connect example.local:443 </dev/null 2>/dev/null | openssl x509 -noout -dates
notBefore=Mar  1 12:00:00 2026 GMT
notAfter=May 31 12:00:00 2026 GMT

Две даты отвечают на все вопросы: с какого числа сертификат действителен и когда он перестаёт быть действительным. Читается вывод глазами, сравнение с текущей датой занимает секунды, и для одного адреса этого достаточно. Вариант с портом для внутренних сервисов указывается после двоеточия, а имя хоста при необходимости задаётся отдельной опцией запроса, когда один адрес обслуживает несколько имён.

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

openssl x509 -checkend 2592000 -noout -in cert.pem && echo "больше месяца" || echo "меньше месяца"

Такая форма удобна для скриптов: число в опции это секунды, месяц это примерно две с половиной тысячи тысяч, и код возврата прямо ложится в условия. Ручная проверка остаётся разведкой и учебной формой, а для парка адресов проверка собирается в скрипт.

Скрипт для парка хостов с порогами предупреждения

Скрипт мониторинга держит три части: список хостов, цикл проверки и пороги. Список живёт отдельным файлом по одному адресу на строку, с опциональным портом, и правится без самого скрипта. Цикл обходит список, для каждого адреса получает дату окончания и сравнивает с порогами, формируя отчёт:

#!/usr/bin/env bash
set -euo pipefail
WARN_DAYS=30
while read -r host; do
  end=$(openssl s_client -connect "$host" </dev/null 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
  days=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
  status="ок"
  (( days < WARN_DAYS )) && status="предупреждение"
  (( days < 7 )) && status="тревога"
  echo "$days дней | $status | $host"
done < cert-hosts.txt

Скелет намеренно прост: без зависимостей, без внешних сервисов, вывод читается глазами и годится для планировщика. Обогащения добавляются по надобности: сортировка по остатку дней, сводка вверху, разные пороги для разных групп хостов через вторую колонку списка.

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

Список хостов это самостоятельная единица гигиены: новые адреса вносятся при развёртывании, убираются при списании, и аудит списка входит в регулярное обслуживание парка. Скрипт с неполным списком создаёт ложное спокойствие, и половина историй о внезапном истечении начинается словами "а этот адрес мы в список не добавили".

Автоматическое продление через certbot и его таймер

Утилита бесплатных сертификатов закрывает продление целиком. Режим продления проверяет сроки всех установленных сертификатов и перевыпускает те, что подходят к концу, оставляя свежие на месте старых:

certbot renew

Команда идемпотентна: не подошедшие к концу сроки не трогаются, а подошедшие продлеваются за секунды. Режим рассчитан на регулярный запуск, и регулярность обеспечивается таймером менеджера системы, который устанавливается вместе с утилитой и работает из коробки. Проверить работу таймера входит в чек-лист развёртывания: статус таймера и журнал последнего запуска отвечают, жива ли автоматика.

Автоматика закрывает рутину, но не отменяет наблюдение. Прерванное продление из-за смены записей подтверждения владения, недоступности сервиса выдачи или изменившейся конфигурации остаётся незамеченным до истечения, и именно поэтому скрипт проверки сроков из предыдущего раздела остаётся в системе даже при полностью автоматическом продлении. Автоматика без наблюдения это надежда, а надежда не является стратегией.

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

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

Хуки после продления и перезагрузка веб-сервера

Продление без перезагрузки это обновлённый файл, который продолжает лежать мёртвым грузом: веб-сервер держит старый сертификат в памяти и отдаёт его до перезагрузки. Утилита продления решает это хуками: команды, выполняемые после успешного перевыпуска, указываются в настройке или в файлах каталога хуков, и плавная перезагрузка веб-сервера в хуке закрывает цикл целиком:

certbot renew --deploy-hook "nginx -s reload"

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

Для нескольких веб-серверов за балансировщиком хук усложняется порядком: продление на всех, перезагрузка по одному, проверка на каждом шаге. Хук на одной машине не знает о соседях, и синхронизация порядка либо выносится в отдельный сценарий, либо упрощается до продления в один день с немедленной перезагрузкой каждого по расписанию с запасом.

Диагностика хуков проста: журнал утилиты продления содержит и факт продления, и вывод хуков. Ошибка хука в журнале видна строкой с ненулевым кодом, и еженедельный взгляд в журнал продления входит в ту же рутину понедельника вместе с отчётом скрипта.

Расписание проверок и интеграция с уведомлениями

Расписание мониторинга строится по принципу двух частот. Еженедельный прогон скрипта по всему списку фиксирует состояние и даёт отчёт. Ежедневный прогон в сезон риска, когда у кого-то из парка осталось меньше недели, выполняется автоматически и отправляет уведомление только при тревоге. Часть парков ограничивается еженедельным отчётом с двумя порогами, и для небольших списков этого достаточно.

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

Интеграция с закупкой платных сертификатов замыкает цикл: предупреждение первого уровня создаёт задачу на закупку, задача проходит свой цикл, установка сертификата попадает в план, и скрипт на следующей неделе подтверждает новый срок. Процесс без связей между шагами остаётся кучей напоминаний, а процесс со связями становится конвейером с контролем на входе.

Списание сертификатов завершает гигиену: адрес ушёл из парка, строка уходит из списка, и отчёт остаётся чистым. Список хостов без чистки со временем превращается в отчёт о призраках, и регулярный аудит списка спасает его от этой судьбы.

Рабочая процедура мониторинга сертификатов

Свод процедур, при которых истечение перестаёт быть событием, выглядит так:

  1. Ручная проверка нового адреса в момент развёртывания и внесение в список;
  2. Еженедельный прогон скрипта по списку с двумя порогами;
  3. Автоматическое продление с таймером и хуком перезагрузки для бесплатных;
  4. Еженедельный взгляд в журнал продления на ошибки хуков;
  5. Задача на закупку по первому порогу для платных сертификатов;
  6. Аудит списка хостов на мёртвые строки раз в квартал.

За списком стоит экономика спокойствия: час настройки скрипта и таймера закрывает класс инцидентов целиком, и каждый следующий месяц монотонно дешевле любого единичного простоя из-за забытого срока.

Итоговое суждение по рутине доброе. Мониторинг сертификатов это редкий случай, когда надёжность покупается дешево: скрипт на пятьдесят строк, таймер из коробки и привычка читать отчёт по понедельникам. Автоматическое продление снимает девять десятых рутины, скрипт страхует автоматику и покрывает платные сертификаты, а пороги дают время на любой процесс закупки. Сертификат, истёкший в парке с такой рутиной, это уже не забывчивость, а статистическая неизбежность, и даже она встречается предупреждением за месяц, а не страницей браузера с предупреждением для посетителя.
Мелкая привычка с большим эффектом: строка каждого нового сертификата вносится в список в момент установки, а не в момент первого предупреждения. Список, который растёт вместе с парком, не требует корпусов и чисток, и отчёт всегда покрывает всё живое.
Последний практический совет: в отчёте скрипта держать верхнюю строку с числом проверенных адресов и датой прогона. Пустой отчёт без шапки выглядит одинаково и со списком, и без него, и шапка снимает двусмысленность навсегда.