Выберите продукт

Let's Encrypt renewal runbook: что делать при ошибках на 80/443

Сертификат Let’s Encrypt не продлился: «renewal failed», «acme challenge failed», 80/443 заняты или закрыты. Этот runbook помогает быстро восстановить выпуск через certbot или acme.sh: проверить DNS, IPv6, порты, выбрать webroot/standalone/tls-alpn-01 и разобрать логи.
Let's Encrypt renewal runbook: что делать при ошибках на 80/443

Зачем нужен runbook по продлению Let’s Encrypt

Автопродление Let’s Encrypt обычно «просто работает», пока не наступает день X: сертификат истёк, пользователи видят предупреждения, мониторинг горит, а в логах — letsencrypt renewal failed или acme challenge failed. Почти всегда корень проблемы сводится к двум вещам: валидатор не смог достучаться до домена по нужному порту/пути или ACME-клиент не смог корректно поднять обработчик challenge и сохранить файлы.

Ниже — практический runbook с упором на 80/443 и три базовых метода проверки домена: webroot, standalone, tls-alpn-01. Формат — «как в дежурке»: быстро найти причину, воспроизвести вручную, починить и вернуть сервис.

Краткая карта: какой challenge и какой порт

Перед дебагом зафиксируйте, какой тип challenge используется при продлении — от этого зависит, куда именно должен попасть Let’s Encrypt.

  • HTTP-01 — нужен доступ извне на 80/tcp к http://DOMAIN/.well-known/acme-challenge/.... Реализация: webroot (файл в директории сайта) или standalone (временный мини-вебсервер).
  • TLS-ALPN-01 — нужен доступ извне на 443/tcp. Проверка идёт на уровне TLS/ALPN; полезно, когда 80 закрыт, но 443 доступен.
  • DNS-01 — порты не важны, но нужна автоматизация DNS. Здесь не разбираем (фокус на 80/443).

Практическое правило: если у вас живой сайт на Nginx/Apache и открыт 80 — чаще всего проще и надёжнее использовать webroot. Если 80 закрыт политикой — чаще спасает tls-alpn-01 или DNS-01.

Схема соответствия ACME challenge и портов 80/443 для HTTP-01 и TLS-ALPN-01

Шаг 0. Быстрая диагностика: что именно сломалось

1) Проверяем сроки и какой сертификат реально отдаётся

Сначала убедитесь, что проблема именно в продлении, а не в том, что веб-сервер смотрит на другой файл сертификата или не делал reload.

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

Если даты старые — продление не применилось или не удалось. Если даты свежие, но браузер ругается — часто это «не тот vhost по SNI» или цепочка (fullchain) подключена неверно.

2) Определяем, чем выпускаем: certbot или acme.sh

  • certbot — обычно /etc/letsencrypt и systemd timer или cron.
  • acme.sh — обычно ~/.acme.sh и пользовательский cron.

3) Ищем последнюю ошибку в логах

Если используется systemd timer (часто на Debian/Ubuntu), начинайте с journal:

systemctl list-timers --all | grep -E 'certbot|acme' || true
systemctl status certbot.timer --no-pager || true
journalctl -u certbot.service -u certbot.timer -n 200 --no-pager

Для acme.sh проверьте cron и где оседает вывод:

crontab -l
ls -la ~/.acme.sh/*.log 2>/dev/null || true

Если логов нет — ищите запуск acme.sh в системных cron-логах, но учитывайте, что путь и настройки логирования зависят от дистрибутива.

Шаг 1. Проверяем доступность домена и маршрутизацию до сервера

Большая доля acme challenge failed — это не «сломался certbot», а Let’s Encrypt физически не попал на ваш сервер (DNS, IPv6, фаервол, балансировщик, дефолтный vhost).

1) DNS: A/AAAA указывают на правильный IP

getent ahosts example.com

Важный нюанс: если есть AAAA (IPv6), Let’s Encrypt может идти по IPv6. Если IPv6 на сервере не настроен или 80/443 на IPv6 закрыты, будет таймаут и падение валидации даже при «идеальном» IPv4.

2) Проверяем, что 80 и 443 слушаются на сервере

ss -ltnp | grep -E ':(80|443)\b' || true

И что фаервол не режет вход:

nft list ruleset 2>/dev/null | grep -E 'dport (80|443)' || true
ufw status verbose 2>/dev/null || true

Если используете HTTP-01, порт 80 должен быть доступен извне. Редирект 80→443 допустим, но путь /.well-known/acme-challenge/ должен доходить до нужного vhost.

3) Проверяем, что на 80 отвечает правильный vhost

Частый сценарий после миграций: на 80 отвечает «дефолтный» сайт, редирект на другой домен или заглушка. Быстрый чек на сервере:

curl -I -H 'Host: example.com' http://127.0.0.1/.well-known/acme-challenge/test 2>/dev/null | head

Если ответ не похож на ваш vhost, разберитесь с приоритетами server_name/ServerName и тем, какой конфиг является default.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Шаг 2. Выбираем правильный метод: webroot, standalone или tls-alpn-01

Вариант A: webroot (рекомендуется, если сайт уже работает на 80)

webroot — самый спокойный способ: ACME-клиент кладёт challenge-файл в директорию сайта, а веб-сервер сам его отдаёт. Плюсы: не нужно останавливать Nginx/Apache и освобождать порт.

Ключевое: указанный webroot должен соответствовать тому vhost, который реально обслуживает домен по HTTP.

Тестовый ручной выпуск (certbot):

certbot certonly --webroot -w /var/www/example.com/public -d example.com -d www.example.com

Проверьте, что в renewal-конфигах прописан актуальный путь:

grep -R "webroot_path" -n /etc/letsencrypt/renewal 2>/dev/null || true

Типовые причины падения webroot:

  • поменяли деплой/DocumentRoot, а renewal-конфиг остался старым;
  • веб-сервер запрещает доступ к /.well-known;
  • редиректы/rewrites уводят запрос на другой домен или ломают путь.

Вариант B: standalone (когда нет веб-сервера или нужен «точечный» выпуск)

standalone поднимает временный сервер. Для HTTP-01 ему нужен 80/tcp, значит порт 80 должен быть свободен. Это классическая причина ошибок: Nginx уже занимает 80.

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

ss -ltnp | grep ':80\b' || true

Если 80 занят, обычно быстрее перейти на webroot. Альтернатива — hooks: остановить веб-сервер на время challenge и поднять обратно (но это риск простоя и лишняя сложность).

Разовый запуск standalone:

certbot certonly --standalone -d example.com -d www.example.com

Вариант C: tls-alpn-01 (когда 80 недоступен, но 443 открыт)

tls-alpn-01 полезен, когда 80 закрыт политикой. Проверка проходит через TLS/ALPN на 443. На практике это значит: 443 должен быть доступен извне, а ваш сценарий должен позволять certbot «подцепиться» к 443 на время проверки.

Если у вас 443 занят жёстко (например, внешним балансировщиком без возможности временной подмены обработки ALPN), обычно проще и надёжнее уходить в DNS-01. Для таких схем пригодится разбор автоматизации DNS-валидации: DNS-01 через acme-dns: как устроить выпуск без открытия 80/443.

Шаг 3. Запускаем renew в режиме отладки

certbot renew: как правильно воспроизвести проблему

Для диагностики используйте сухой прогон и подробный вывод:

certbot renew --dry-run
certbot renew -v

Если падает конкретный домен, проще воспроизвести выпуск точечно через certonly с тем же методом (webroot или standalone) — так быстрее локализуется причина.

acme.sh: принудительный renew и повторный issue

acme.sh хранит параметры выпуска по домену. Для принудительного продления:

acme.sh --renew -d example.com --force

Если используется webroot и нужно переиздать:

acme.sh --issue -d example.com -d www.example.com -w /var/www/example.com/public

Шаг 4. Типовые ошибки «acme challenge failed» и быстрые фиксы

Сценарий 1: 80 закрыт фаерволом или внешней политикой

Симптомы: таймауты или connection refused для HTTP-01. Решение: открыть 80, либо сменить метод на tls-alpn-01 (443) или DNS-01.

Сценарий 2: порт занят (standalone на 80 или tls-alpn-01 на 443)

Симптомы: клиент не может забиндиться на порт. Решение: не использовать standalone на работающем веб-сервере (лучше webroot), либо корректно останавливать сервис на время проверки.

ss -ltnp | grep -E ':(80|443)\b' || true

Сценарий 3: неверный webroot или запрет на .well-known

Симптомы: Let’s Encrypt получает 404/403 вместо токена. Проверьте:

  • путь webroot совпадает с root/DocumentRoot именно для этого домена;
  • в конфиге нет запретов на /.well-known;
  • редиректы не уводят запрос на другой домен.

Быстрый локальный тест: положите файл и запросите его по домену.

mkdir -p /var/www/example.com/public/.well-known/acme-challenge
printf 'ok' > /var/www/example.com/public/.well-known/acme-challenge/fastfox-test
curl -sS http://example.com/.well-known/acme-challenge/fastfox-test

Должно вернуть ok без редиректа на «чужой» домен.

Сценарий 4: IPv6 ломает валидацию

Симптомы: по IPv4 всё доступно, но challenge падает. Причина: есть AAAA, а по IPv6 нет маршрутизации или закрыты 80/443.

  • Надёжный вариант: настроить IPv6 так же, как IPv4, и открыть 80/443.
  • Временная мера (если политика допускает): убрать AAAA до исправления.
  • Альтернатива: DNS-01, если сетевой доступ нестабилен.

Сценарий 5: сменился vhost/прокси/балансировщик

После установки панели, переезда или добавления reverse proxy часто меняются правила на 80/443. В итоге Let’s Encrypt попадает в другой виртуальный хост и видит не тот контент.

Практика: на время инцидента удобно включить отдельный access_log для /.well-known/acme-challenge/ и убедиться, что запросы приходят именно туда, куда вы ожидаете. Если есть несколько уровней прокси — проверьте, что путь /.well-known не переписывается и не кэшируется.

Проверка занятости портов 80/443 и доступности /.well-known/acme-challenge через curl

Шаг 5. Автопродление: systemd timer или cron, чтобы «больше не падало»

certbot + systemd timer: проверка состояния

Проверяйте три вещи: таймер включён, сервис отрабатывает без ошибок, лог читаемый.

systemctl is-enabled certbot.timer || true
systemctl status certbot.timer --no-pager
systemctl status certbot.service --no-pager
journalctl -u certbot.service -n 200 --no-pager

Если используете хуки (reload Nginx/Apache), убедитесь, что они не зависят от интерактивного окружения и не падают из-за PATH.

acme.sh + cron: убеждаемся, что cron реально работает

Типовые проблемы: cron-сервис выключен, пользовательский crontab удалён, скрипт переехал, окружение отличается от интерактивной сессии.

systemctl status cron --no-pager 2>/dev/null || systemctl status crond --no-pager 2>/dev/null || true
crontab -l

После любых изменений прогоняйте ручной cron-режим:

acme.sh --cron --home ~/.acme.sh
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Шаг 6. Частые вопросы про 80/443 и продление

Можно ли держать 80 закрытым и всё равно продлевать?

Да. Но тогда HTTP-01 не подходит. Нужен tls-alpn-01 на 443 (если ваш сценарий позволяет) или DNS-01. Если политика безопасности требует закрытого 80 — уберите попытки HTTP-01 из конфигурации, иначе будете периодически ловить letsencrypt renewal failed.

Редирект 80→443 мешает?

Обычно нет, но Let’s Encrypt должен суметь получить challenge по конечному URL. Если редирект ведёт на другой домен, другой хост или ломает путь — будет acme challenge failed. Для webroot лучше обеспечить прямую отдачу /.well-known/acme-challenge/ без нестандартных переписываний.

Почему «вчера работало», а сегодня нет?

  • изменился DNS (переезд, добавили AAAA);
  • поменяли конфиг веб-сервера/прокси и закрыли доступ к /.well-known;
  • обновление пакетов заменило/отключило unit/cron;
  • порт 80/443 занял другой сервис;
  • ужесточили фаервол/группы безопасности.

Если вы одновременно настраиваете HTTPS-политику (HSTS, редиректы, цепочки), полезно свериться с практиками из материала: Certbot, HTTPS и HSTS: как не сломать доступность и продление.

Чеклист восстановления (коротко, как в дежурке)

  1. Проверить, какой сертификат реально отдаётся, через openssl s_client.
  2. Понять, чем продлеваем: certbot или acme.sh.
  3. Посмотреть логи: journalctl для certbot, cron/логи для acme.sh.
  4. Проверить DNS (A/AAAA), что домен указывает на нужный сервер, и что IPv6 не ломает доступ.
  5. Проверить, что 80/443 доступны и слушаются, и нет конфликта портов.
  6. Если HTTP-01: проверить отдачу /.well-known/acme-challenge/ и корректность webroot.
  7. Запустить ручной прогон: certbot renew --dry-run или acme.sh --renew --force.
  8. После успеха убедиться, что веб-сервер подхватил новые файлы (reload/restart по вашей схеме).

Что стоит зафиксировать в инфраструктуре после инцидента

Чтобы история не повторялась, оформите минимум «операционных гарантий»:

  • мониторинг истечения сертификата заранее (с запасом);
  • единый выбранный метод challenge (не мешать standalone и webroot без причины);
  • документация по портам: должен ли быть открыт 80 и почему;
  • где смотреть результат: systemd timer/cron, кто получает алерты;
  • для multi-domain сертификатов — помнить про лимиты и планировать изменения SAN; при частых перевыпусках пригодится разбор: лимиты Let’s Encrypt для SAN и как автоматизировать перевыпуск.

Если вы разворачиваете новые проекты, проще не доводить до инцидента: держите прозрачную схему HTTPS и продления, а для изоляции сервисов и предсказуемых правил фаервола часто удобнее использовать VDS под конкретные роли (веб, прокси, балансировщик).

Поделиться статьей

Вам будет интересно

Rsync over SSH: ускоряем передачу и держим нагрузку под контролем (cipher, compression, bwlimit, IO) OpenAI Статья написана AI (GPT 5)

Rsync over SSH: ускоряем передачу и держим нагрузку под контролем (cipher, compression, bwlimit, IO)

Разберём, как разогнать rsync over SSH и не «положить» прод: как выбрать быстрый cipher (chacha20-poly1305 или aes128-gcm), когда ...
Reverse DNS (PTR): как работает rDNS, зачем нужен и как настроить без боли OpenAI Статья написана AI (GPT 5)

Reverse DNS (PTR): как работает rDNS, зачем нужен и как настроить без боли

Reverse DNS (PTR, rDNS) — запись, которая сопоставляет IP-адрес с hostname. Разберём, где живёт PTR, как проверить через dig -x, з ...
Postfix: deferred и bounce из‑за DNS и TLS — разбор очереди и быстрый план ремонта OpenAI Статья написана AI (GPT 5)

Postfix: deferred и bounce из‑за DNS и TLS — разбор очереди и быстрый план ремонта

Если письма в Postfix зависают со status=deferred или уходят в bounce, чаще всего причина в DNS (резолвинг, MX/A/AAAA, rDNS PTR, H ...