В рабочем чате появляется сообщение: «Сайт не открывается, сертификат истёк». Следом присылают скриншот с ошибкой 502. Администратор запускает команду продления certbot renew и перезагружает nginx. Иногда сайт возвращается, а иногда перестаёт отвечать совсем.

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

Чтобы диагностика и команды были такими же, как на реальном проде, а не только в теории, материал сверили с тем, кто эксплуатирует инфраструктуру каждый день:

Владимир Отт

Руководитель отдела инфраструктуры и эксплуатации в Нетологии

TL;DR
  • Сначала определите тип сбоя: предупреждение о сертификате, 502 и отказ в соединении требуют разных проверок.

  • Сравните сертификат, который получает браузер, с сертификатом на сервере: проверьте срок действия и серийный номер.

  • Если на сервере старый сертификат, проверяйте Certbot, подтверждение домена и расписание запуска.

  • Если на сервере сертификат новый, а сайт отдаёт старый, проверьте пути в nginx, перезагрузку конфигурации, CDN и балансировщик.

  • Перед перезагрузкой конфигурации запускайте nginx ‑t. Затем снова проверяйте сертификат из внешней сети.

  • Let’s Encrypt больше не присылает письма об истечении. Нужен собственный мониторинг сертификатов.

Перед началом

  1. В примерах используется домен example.com. Везде замените его на адрес своего сайта.

  2. Команды для проверки внешнего сертификата выполняйте с ноутбука или другого компьютера вне сервера. Команды с sudo, systemctl, journalctl, nginx и certbot, а также проверку работы локального приложения выполняйте по SSH на сервере, где установлен nginx.

  3. sudo запускает команду с правами администратора. Если таких прав нет, передайте инструкцию тому, кто отвечает за сервер.

  4. Основной сценарий статьи — Linux, nginx и Certbot. Здесь nginx работает как обратный прокси: принимает запросы пользователей и передаёт их приложению. Если HTTPS раньше него принимает CDN (сеть доставки контента), панель хостинга, облачный балансировщик или ingress‑контроллер Kubernetes, сертификат нужно проверять и обновлять там.

Продление сертификата — частный случай большой темы: автоматизации и эксплуатации инфраструктуры. Системно её разбирают на курсе «DevOps‑инженер» в Нетологии — от настройки веб‑серверов и балансировки до мониторинга и CI/CD.

Разберитесь с симптомом

TLS — протокол, который шифрует данные между браузером и сервером. Браузер сначала устанавливает защищённое соединение и проверяет сертификат. Только после этого сервер может вернуть HTTP‑код. Поэтому просроченный сертификат обычно вызывает предупреждение браузера, а не страницу с ошибкой 502.

502 — это ответ прокси по протоколу HTTP. По RFC 9110 он означает, что прокси не получил нормальный ответ от приложения за ним. Просроченный сертификат приложения вызовет 502 только в особом случае: nginx подключается к приложению по HTTPS и проверяет его сертификат. В простых схемах nginx часто обращается к приложению по обычному HTTP, поэтому сертификат приложения здесь ни при чём. Проверкой управляет параметр proxy_ssl_verify; по умолчанию она выключена.

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

Поэтому не начинайте с продления сертификата. Сначала выясните, где заканчивается внешнее HTTPS‑соединение. В простой схеме его принимает nginx на сервере. Если перед nginx стоят CDN, облачный балансировщик, панель хостинга или ingress‑контроллер Kubernetes, браузер может видеть сертификат именно этого сервиса.

Диагностика за десять минут

1. Посмотрите сертификат снаружи

Запустите команду из внешней сети, а не с самого сервера. Так вы увидите сертификат, который пользователям действительно отдаёт CDN, балансировщик или сам сервер.

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

Пример вывода:

serial=2DEE9E1F91C7E19412937B962AF0D3C4
notBefore=Aug 5 20:42:25 2026 GMT
notAfter=Oct 28 20:42:24 2026 GMT
subject=CN=example.com
issuer=C=US, O=SOME Trust Services, CN=YR1

Что смотреть в результате:

  • notAfter — дата окончания сертификата.

  • serial — серийный номер сертификата.

  • subject — основное имя сертификата; полный список доменов хранится в поле subjectAltName и этой командой не выводится. Совпадение домена проверит команда с -verify_hostname ниже.

  • issuer — центр сертификации, который его выпустил.

Если notAfter уже прошла, сертификат, который видят пользователи, просрочен.

Параметр -servername передаёт серверу имя домена. Это нужно, когда на одном IP‑адресе работает несколько сайтов: по имени сервер выбирает правильный сертификат. Механизм называется SNI — расширение TLS для передачи имени сайта. Лучше указывать домен явно, особенно при проверке конкретного IP‑адреса.

Чтобы проверить не только срок, но и всю цепочку сертификатов и совпадение доменного имени, выполните:

echo | openssl s_client \
  -connect example.com:443 \
  -servername example.com \
  -verify_hostname example.com \
  -verify_return_error

В конце вывода найдите строку Verify return code: 0 (ok). Она означает, что цепочка сертификатов и доменное имя прошли проверку. Любой другой код — повод прочитать сообщение об ошибке выше.

2. Посмотрите, что лежит на сервере

Уточните, какие сертификаты зарегистрированы в Certbot:

sudo certbot certificates

В выводе важны три строки:

  1. Certificate Name — имя сертификата внутри Certbot.

  2. Expiry Date — дата окончания и пометка VALID или INVALID.

  3. Certificate Path и Private Key Path — точные пути к сертификату и приватному ключу.

Скопируйте точный Certificate Path из вывода Certbot. Не собирайте путь вручную: имя каталога может отличаться от домена, например заканчиваться на -0001. Затем проверьте файл:

CERT_PATH=/etc/letsencrypt/live/example.com/fullchain.pem  # вставьте точный Certificate Path
sudo openssl x509 -in "$CERT_PATH" \
  -noout -serial -dates -subject -issuer

Сравните внешний и локальный результаты. notAfter — дата окончания сертификата, serial — его серийный номер. Если номера различаются, пользователи получают не тот файл, который вы проверили на сервере.

Если локальный сертификат новее внешнего, переходите к сценарию 2. Если оба просрочены — к сценарию 1. Если оба действуют, причина не в сроке: проверьте цепочку и совпадение домена командой с -verify_hostname, затем вернитесь к исходному симптому.

3. Проверьте, какие файлы читает nginx

sudo nginx -T 2>/dev/null \
  | grep -E 'server_name|ssl_certificate|ssl_certificate_key'

В нужном разделе директива server_name должна содержать ваш домен. ssl_certificate и ssl_certificate_key должны вести к актуальным файлам сертификата и ключа.

Команда nginx -T проверяет и выводит всю конфигурацию, включая подключённые файлы. Фильтр grep помогает быстро найти server_name, ssl_certificate и ssl_certificate_key, но не показывает границы разделов. Затем откройте полный вывод nginx -T и убедитесь, что домен, сертификат и ключ находятся в одном блоке server { }. Так можно обнаружить второй блок того же сайта, старый путь или сертификат другого домена.

После проверки станет понятно, какой из двух сценариев перед вами.

Сценарий 1. На сервере старый сертификат

Значит, Certbot не выпустил новый сертификат. Ручной certbot renew может временно решить проблему, но причину сбоя всё равно нужно найти.

Почему certbot renew не выпускает сертификат сразу

Команда certbot renew проверяет все сертификаты, но обновляет только те, для которых уже наступил срок продления. В актуальных версиях Certbot этот порог зависит от срока жизни сертификата: обычно продление начинается, когда остаётся меньше трети срока, а для сертификатов сроком десять дней или меньше — когда остаётся меньше половины. Универсального правила «обновлять за 30 дней» в новых версиях нет. 

Если сайт уже показывает просроченный сертификат, а Certbot сообщает, что срок продления не наступил, он, скорее всего, проверяет другой сертификат. Сверьте Certificate Name, Certificate Path и список доменов.

Проверить процедуру без выпуска рабочего сертификата можно с помощью тестового запуска:

sudo certbot renew --dry-run

Параметр --dry-run запускает пробное продление через тестовую среду Let’s Encrypt и не расходует рабочие лимиты выпуска. Успешный результат показывает, что Certbot сейчас может пройти все этапы продления, но не подтверждает, что задача запускается по расписанию.

Certbot не запускается по расписанию

В Linux Certbot обычно запускает таймер systemd — встроенное расписание для системных служб. Проверьте время следующего запуска, состояние таймера и журнал:

systemctl list-timers --all | grep -E 'certbot|snap.certbot'
systemctl status certbot.timer
journalctl -u certbot.service

Что должно быть в норме:

  • list-timers показывает время следующего запуска в столбце NEXT;

  • status certbot.timer показывает active (waiting);

  • journalctl не содержит ошибок последнего продления.

Название таймера зависит от способа установки. Для системного пакета это обычно certbot.timer и certbot.service. Для Snap — snap.certbot.renew.timer и snap.certbot.renew.service. Используйте имена, которые нашли через list-timers. Если вместо systemd используется cron (отдельный планировщик команд), проверьте само задание, пользователя и сообщения об ошибках.

Не проходит проверка HTTP-01

HTTP-01 — способ доказать, что вы управляете доменом. Let’s Encrypt запрашивает специальный файл по обычному HTTP через порт 80. Перенаправление на HTTPS обычно не мешает. Проверка не пройдёт, если порт 80 закрыт, указан неверный корневой каталог сайта, служебный путь требует входа, перенаправление зациклено или DNS ведёт на другой сервер.

Проверяйте служебный путь /.well-known/acme-challenge/, а не главную страницу. Если в DNS указано несколько серверов, файл должен открываться на каждом из них, либо все запросы проверки должны идти на один сервер.

Сначала найдите реальный webroot — корневой каталог сайта — в конфигурации nginx или файле /etc/letsencrypt/renewal/ИМЯ_СЕРТИФИКАТА.conf. Первые три команды выполните на сервере, curl — с внешнего компьютера, последнюю команду — снова на сервере:

WEBROOT=/var/www/example.com  # замените на каталог своего сайта
sudo mkdir -p "$WEBROOT/.well-known/acme-challenge"
echo ok | sudo tee "$WEBROOT/.well-known/acme-challenge/test.txt"
curl -i http://example.com/.well-known/acme-challenge/test.txt
sudo rm "$WEBROOT/.well-known/acme-challenge/test.txt"

Нормальный результат — HTTP 200 и строка ok в ответе. Последняя команда удаляет тестовый файл.

Let’s Encrypt отклонил повторный выпуск

У Let’s Encrypt действует несколько лимитов. Например, для одного и того же набора доменных имён можно получить не больше пяти сертификатов за семь дней. Возможность выпуска восстанавливается постепенно — примерно по одному сертификату каждые 34 часа.

Сам по себе повторный certbot renew обычно не расходует лимит. Если срок продления не наступил, новый сертификат не выпускается. Проблемы возникают после повторных успешных выпусков, принудительного перевыпуска с --force-renewal или пересоздания одного и того же сертификата.

Поэтому сначала проверяйте процедуру в тестовой среде и читайте ответ центра сертификации. Certbot общается с ним по протоколу ACME, который автоматизирует выпуск и продление сертификатов.

Сертификат продлевает другой сервис

На одном сервере сертификатами могут одновременно управлять панель хостинга и Certbot, а nginx — читать файл из третьего каталога. Панель может использовать собственный таймер или продлевать сертификат через интерфейс, поэтому не считайте certbot renew единственным механизмом.

Сначала выясните, кто продлевает сертификат домена: Certbot, панель, CDN, балансировщик или другой сервис автоматического выпуска по протоколу ACME. Затем проверьте расписание, журнал и каталог, в который этот инструмент сохраняет сертификат.

DevOps‑инженер — от сертификатов до мониторинга в одном процессе

Соберите рабочий процесс на трёх проектах в облаке. Нужен Linux на уровне администрирования.

Посмотреть программу →

Сценарий 2. На сервере сертификат новый, а сайт отдаёт старый

Значит, сертификат выпущен, но nginx, CDN или балансировщик продолжает использовать старый.

nginx не применил новый сертификат

Сначала проверьте конфигурацию, затем перезагрузите её без остановки nginx:

sudo nginx -t && sudo systemctl reload nginx

Команда nginx -t должна завершиться сообщениями syntax is ok и test is successful. Если проверка не пройдена, часть после && не выполнится, поэтому nginx не будет перезагружен.

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

После перезагрузки конфигурации снова запустите openssl s_client из внешней сети и сравните серийный номер. Так вы убедитесь, что nginx использует нужный файл.

nginx читает копию сертификата

Certbot хранит все версии сертификатов в /etc/letsencrypt/archive/. В каталоге /etc/letsencrypt/live/ лежат символические ссылки — файлы‑указатели на текущую версию. Если просто скопировать fullchain.pem в /etc/nginx/ssl/, Certbot обновит оригинал, а nginx продолжит читать старую копию.

Поэтому в конфигурации nginx лучше указывать файлы из /etc/letsencrypt/live/:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Подключён cert.pem вместо fullchain.pem

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

Процесс не может прочитать ключ

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

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

HTTPS обрабатывает другой сервер

Если после перезагрузки серийные номера всё ещё не совпадают, HTTPS, вероятно, принимает другой сервис: CDN, облачный балансировщик, ingress‑контроллер Kubernetes или другой сервер из DNS.

Проверяйте сертификат там, где завершается внешнее HTTPS‑соединение.

Проверьте DNS‑записи. Запись A указывает на IPv4-адрес, AAAA — на IPv6-адрес. Если у домена есть CNAME‑запись, она указывает на другое доменное имя. Тогда A‑ и AAAA‑записи нужно искать уже для этого имени.

Затем проверьте каждый найденный IP‑адрес, настройки CDN и сертификаты на балансировщике. Если серверов несколько, подключайтесь к каждому IP отдельно, но передавайте домен через SNI. Иначе исправный сервер может скрыть проблему на другом узле.

Чтобы проверить один IP‑адрес и всё равно передать домен, выполните:

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

Замените IP‑адрес и домен. Повторите команду для каждого адреса из DNS.

Почему после обновления сертификата появляется 502 или отказ в соединении

Обычно причина уже не в сертификате.

Если nginx перестал принимать соединения после изменения конфигурации, проверьте синтаксис, путь к ключу и права на файл. Затем посмотрите состояние сервиса, журнал и список слушающих портов.

Проверьте nginx тремя командами:

systemctl status nginx
journalctl -u nginx --since "30 minutes ago"
sudo ss -ltnp | grep ':443'

В норме nginx имеет состояние active (running), а последняя команда показывает, что процесс слушает порт 443.

Если nginx возвращает 502, посмотрите, может ли он подключиться к приложению: верны ли адрес и порт, запущен ли процесс, отвечает ли DNS и не истекло ли время ожидания.

Начните с журнала nginx. Сертификат приложения важен только тогда, когда nginx обращается к нему по HTTPS и включён параметр proxy_ssl_verify. В большинстве простых схем внутри сервера используется HTTP, и эта настройка не нужна.

Затем проверьте приложение за nginx:

sudo tail -n 50 /var/log/nginx/error.log
curl -v http://127.0.0.1:8080/

Замените протокол, адрес и порт значениями из proxy_pass. Если там указан HTTPS, используйте https://. Если приложение подключено через Unix‑сокет — локальный файл вместо сетевого порта, — эта команда не подходит: проверяйте сокет и само приложение отдельно. Если curl не соединяется или возвращает ошибку, проблема между nginx и приложением, а не в публичном сертификате.

Ошибка 502 после обновления сертификата не доказывает, что новый сертификат сломал nginx. Она означает только одно: прокси не получил нормальный ответ от приложения. Точную причину ищите в журнале nginx и настройках подключения к приложению.

Wildcard‑сертификаты продлеваются через DNS-01

Wildcard‑сертификат — сертификат с маской *.example.com. Его можно подтвердить только через DNS-01 — проверку с помощью специальной DNS‑записи. HTTP-01 для него не подходит. Маска покрывает поддомены вроде shop.example.com, но не сам example.com, поэтому при необходимости оба имени указывают в заявке.

Для автоматического продления обычно нужен DNS‑провайдер с API — программным интерфейсом, через который Certbot меняет DNS‑записи. Certbot подключается к нему через плагин, то есть дополнение для конкретного провайдера. Токену доступа дают только необходимые права. Режим --manual без скрипта --manual-auth-hook требует ручного подтверждения при каждом выпуске; для постоянной работы надёжнее готовый DNS‑плагин.

Перед внедрением проверьте четыре вещи:

  1. DNS‑плагин соответствует вашему провайдеру.

  2. Токен имеет права создавать, изменять и удалять TXT‑записи только в нужной DNS‑зоне и хранится как секрет.

  3. Тестовое продление проходит без ручного ввода.

  4. После выпуска сервис начинает отдавать новый сертификат.

Что хранится в файлах Certbot

Файл

Что содержит

Как использовать

fullchain.pem

Сертификат сайта и промежуточная цепочка

ssl_certificate в nginx

privkey.pem

Приватный ключ

ssl_certificate_key в nginx

cert.pem

Только сертификат сайта

Диагностика или сервис с отдельной цепочкой

chain.pem

Промежуточные сертификаты без сертификата сайта

Обычно не указывают в nginx отдельно

Для nginx обычно нужны fullchain.pem и privkey.pem. Файл cert.pem содержит только сертификат сайта, а chain.pem — промежуточную цепочку.

Как избежать повторения проблемы

Определите, кто отвечает за продление

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

Не запускайте одновременно панель, ручной сценарий и несколько программ автоматического выпуска без понятной схемы.

Перезагружайте nginx только после успешного продления

Certbot умеет запускать команду только после успешного выпуска или продления сертификата. Для этого используют параметр --deploy-hook; для nginx его можно настроить так:

sudo certbot renew \
  --deploy-hook 'nginx -t && systemctl reload nginx'

Если сертификат создавали с дополнением Certbot для nginx, Certbot может сам установить его и перезагрузить конфигурацию.

Проверьте настройки, чтобы не запускать одно действие дважды. Параметр --deploy-hook вызывает команду только после успешного выпуска или продления. Параметр --post-hook запускает её после всех попыток, даже если сертификат не обновился.

Автоматический reload после продления — маленький пример того, из чего складывается работа DevOps‑инженера: настройка автоматического развёртывания и восстановления серверов, а не разовая починка руками.

Проверяйте сертификат снаружи

Let’s Encrypt больше не присылает письма об истечении. Настройте внешний мониторинг, который проверяет каждый публичный домен, срок действия и цепочку сертификата.

Одного предупреждения за 30 дней недостаточно: срок действия публичных сертификатов сокращается, а Let’s Encrypt переходит с 90 на 64, а затем на 45 дней. Настройте несколько предупреждений и отдельно проверяйте, обновился ли сертификат после планового продления.

Проверяйте автоматику, а не только команду

Запускайте certbot renew --dry-run после изменений DNS, межсетевого экрана, обратного прокси или плагинов. Для постоянного контроля проверяйте расписание, журнал и сертификат, который сайт отдаёт пользователям.

Контроль должен отвечать на три вопроса:

  1. Запустилось ли задание по расписанию?

  2. Завершилось ли оно успешно?

  3. Начал ли сайт отдавать новый сертификат?

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

Шпаргалка по симптомам

Симптом

Вероятная причина

Что проверить

Браузер ругается на сертификат

Просрочен сертификат, нарушена цепочка или доменное имя не совпадает

Вывод OpenSSL: срок, цепочка и домен

Ошибка 502

Приложение за прокси недоступно или ответило некорректно; сертификат влияет только при проверке TLS

Журнал nginx, адрес и порт приложения

Соединение отклонено

nginx не слушает порт или соединение заблокировано

Статус nginx, слушающие порты, межсетевой экран

На сервере новый, на сайте старый

Старый путь, конфигурация не перезагружена, CDN, балансировщик или другой сервер

nginx -T, серийный номер и каждый IP‑адрес

Тестовое продление завершается ошибкой

Не проходит проверка домена или не работает дополнение Certbot

Ответ центра сертификации и служебный путь проверки

Тестовое продление проходит, но сертификат истёк

Не запускается системный таймер или проверяется другой сервер

Расписание запуска, журнал и внешний мониторинг

Финальный чек‑лист

  1. Определили тип сбоя и сервис, который принимает HTTPS‑соединение.

  2. Сравнили внешний и локальный сертификаты по серийному номеру и дате окончания.

  3. Проверили пути nginx командой nginx -T, расписание продления и выполнили тестовый запуск certbot renew --dry-run.

  4. Проверили, что HTTP-01 доступен на порту 80 либо DNS-01 работает через программный интерфейс провайдера.

  5. После nginx -t перезагрузили конфигурацию, проверили все IP из внешней сети и настроили мониторинг с ответственным за продление.


❯ Что дальше

Если чек‑лист выше вы прошли по памяти, а автопродление у вас давно настроено — курс не нужен, вы и так в теме. Если часть пунктов оказалась новой — вот куда двигаться.

Системно эксплуатацию инфраструктуры разбирают на курсе «DevOps‑инженер PRO». Он рассчитан на тех, кто уже в ИТ, и его можно совмещать с работой. На выходе — диплом о профессиональной переподготовке.

Если хочется сначала попробовать формат, начните с чего‑то бесплатного: 

➊ Записи вебинара «Секретный рецепт DevSecOps, или почему его используют 90% компаний» — занятия о том, как безопасность встраивают прямо в процесс эксплуатации, а не прикручивают потом.

➋ Практического курса «ИИ в деле: ускорьте свою работу» — про то, что сейчас спрашивают на любой инженерной позиции. 

➌ Вводного курса бакалавриата НИУ ВШЭ «Программные системы и автоматизация процессов разработки» — если думаете про высшее в ИТ.