Если при поиске решения вы набрали в логе или в запросе что-то вроде «ACME TLSALPN01 : 80», вы, скорее всего, столкнулись с ключевой особенностью протокола: проверка tls-alpn-01 не работает на порту 80. Этот тип челленджа по стандарту ACME всегда проходит через TLS на 443-м порту и использует ALPN-протокол acme-tls/1. Попытки «поднять» его на 80-м завершатся отказом валидации. В этой статье разберём, как грамотно организовать выпуск сертификатов через tls-alpn-01 за обратным прокси (Nginx, HAProxy), как автоматизировать продление и как диагностировать типовые ошибки.
Что такое tls-alpn-01 и почему «:80» — мимо кассы
ACME поддерживает несколько способов подтверждения владения доменом. В веб-инфраструктуре чаще всего используют http-01 или tls-alpn-01:
http-01— запрос кhttp://example.com/.well-known/acme-challenge/...на порту 80.tls-alpn-01— короткое TLS-соединение кexample.com:443с ALPNacme-tls/1, где клиент поднимает временный сертификат со специальным расширением.
Если у вас закрыт порт 80, либо вы хотите принципиально выпускать сертификаты «через HTTPS», tls-alpn-01 — отличный выбор. Но у него два жёстких требования:
- снаружи должен быть доступен TCP 443 (и по IPv4, и по IPv6, если публикуете AAAA);
- на пути не должно быть TLS-терминации, «ломающей» ALPN, — либо прокси должен уметь прозрачно прокидывать соединение к локальному ACME-серверу, который отдаёт временный сертификат.
Коротко:
tls-alpn-01— только порт 443, с ALPNacme-tls/1. Для порта 80 есть другой челлендж —http-01.
Схема трафика и минимальные требования
Типовая схема такова: внешний 443-й приходит на ваш обратный прокси. Прокси, увидев в ClientHello ALPN acme-tls/1, пересылает соединение на локальный порт, где ACME-клиент (например, Certbot в режиме standalone для tls-alpn-01) поднимает временный TLS-сервер. Всё остальное время обычный HTTPS-трафик уходит на ваш штатный TLS-терминатор/веб-сервер.
Проверьте перед стартом:
- Открыт ли порт 443 на фаерволе и на внешнем периметре (NAT, облачный Security Group).
- Правильно ли резолвятся A/AAAA-записи и нет ли расхождений IPv4/IPv6 по маршрутизации.
- Не ставит ли внешний балансировщик собственный TLS-терминатор, который вы не контролируете.
Если публичного сервера ещё нет или требуется изолировать сервисы, поднимайте прокси и бэкенды на VDS с гибкой маршрутизацией и IPv4/IPv6 — так проще контролировать 443-й порт и стек TLS.

Маршрутизация ALPN через Nginx (stream) + Certbot
Ключевая идея — пусть Nginx слушает 443 в модуле stream, «нюхает» ALPN и SNI на уровне ClientHello и решает, куда отправить TCP-поток:
- если это
acme-tls/1— на локальный порт, где Certbot временно поднимет standalone TLS; - иначе — на обычный HTTPS-бекенд (ваш текущий Nginx http-блок, Apache или другой терминатор TLS), слушающий не 443, а, например, 4443 на localhost.
Пример конфигурации Nginx
1) Включаем stream и настраиваем маршрутизацию по ALPN:
stream {
map $ssl_preread_alpn_protocols $target {
~\bacme-tls/1\b acme_backend;
default https_backend;
}
upstream acme_backend {
server 127.0.0.1:10443; # сюда будет слушать Certbot standalone для tls-alpn-01
}
upstream https_backend {
server 127.0.0.1:4443; # ваш обычный TLS-терминатор/веб-сервер
}
server {
listen 443 reuseport;
proxy_pass $target;
ssl_preread on;
}
}
2) Переводим вашу текущую HTTPS-конфигурацию на локальный порт 4443, чтобы stream прокидывал на неё обычные HTTPS-сессии. Пример для Nginx http:
server {
listen 127.0.0.1:4443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# остальная конфигурация сайта
}
3) Настраиваем Certbot для tls-alpn-01 так, чтобы он слушал на локальном порту 10443:
sudo apt-get update
sudo apt-get install -y certbot
sudo certbot certonly --standalone --preferred-challenges tls-alpn-01 --tls-alpn-01-port 10443 -d example.com -d www.example.com
В момент проверки Certbot запустит встроенный временный TLS-сервер на 127.0.0.1:10443. Ваш Nginx в stream поймает acme-tls/1 и прокинет соединение туда. Обычный трафик уйдёт на 4443.
Проверка ALPN и диагностика
Проверьте, что снаружи ALPN корректно маршрутизируется. Для этого достаточно инициировать клиентское соединение с требуемым ALPN:
openssl s_client -alpn acme-tls/1 -connect example.com:443 -servername example.com -brief
openssl s_client -connect example.com:443 -servername example.com -brief
В первом случае вы должны увидеть короткое рукопожатие и закрытие соединения (Certbot отдаёт временный сертификат). Во втором — обычный сертификат вашего сайта.
Маршрутизация через HAProxy (TCP passthrough)
HAProxy удобно использовать как L4/L7-прокси. Для tls-alpn-01 нам нужен режим TCP и роутинг по ALPN на этапе ClientHello.
global
log /dev/log local0
defaults
mode tcp
log global
timeout connect 5s
timeout client 30s
timeout server 30s
frontend ft_https
bind :443 alpn h2,http/1.1,acme-tls/1
tcp-request inspect-delay 5s
use_backend bk_acme if { req.ssl_alpn -i acme-tls/1 }
default_backend bk_https
backend bk_acme
server acme 127.0.0.1:10443
backend bk_https
server local 127.0.0.1:4443
Далее — аналогично Nginx-сценарию: ваш веб-сервер/терминатор TLS слушает 127.0.0.1:4443, а Certbot — временно на 127.0.0.1:10443 только на время проверки.
Автопродление: systemd-таймер и безопасный reload
По умолчанию Certbot ставит cron/systemd-таймер. Если вы сами управляете режимом tls-alpn-01 и локальным портом, явно задайте параметры и аккуратно перезагрузите прокси/веб-сервер после обновления сертификата.
# Сервис для обновления
# /etc/systemd/system/certbot-renew-alpn.service
[Unit]
Description=Renew Let's Encrypt certificates via tls-alpn-01 and reload Nginx
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --preferred-challenges tls-alpn-01 --tls-alpn-01-port 10443 --deploy-hook "nginx -t && systemctl reload nginx"
[Install]
WantedBy=multi-user.target
# Таймер на два запуска в сутки
# /etc/systemd/system/certbot-renew-alpn.timer
[Unit]
Description=Twice daily Certbot renew via tls-alpn-01
[Timer] 03,15:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renew-alpn.timer
В deploy-hook мы валидируем конфигурацию (nginx -t) и только потом делаем reload. Аналогично можно перезагружать HAProxy или любой другой терминатор.
Альтернатива Certbot: acme.sh с режимом ALPN
Популярный легковесный клиент acme.sh поддерживает tls-alpn-01 из коробки и позволяет слушать альтернативный порт, если вы прокидываете ALPN через прокси.
curl https://get.acme.sh | sh
. ~/.acme.sh/acme.sh.env
acme.sh --issue --alpn -d example.com -d www.example.com --tlsport 10443
acme.sh --install-cert -d example.com --fullchain-file /etc/letsencrypt/live/example.com/fullchain.pem --key-file /etc/letsencrypt/live/example.com/privkey.pem --reloadcmd "nginx -t && systemctl reload nginx"
Опция --tlsport указывает локальный порт standalone-сервера для ALPN-челленджа — вы уже прокинули до него 443 на внешнем уровне.
Частые ошибки и как их найти
- «connection refused/timeout на 443»: проверьте фаервол (локальный и облачный), NAT и что процесс реально слушает 443. Используйте
ss -ltnpиjournalctl -u nginx -u haproxy -u certbot. - «wrong validation method: 80 vs 443»: если вы видите попытки идти на 80-й при
tls-alpn-01, значит клиент/прокси сконфигурированы подhttp-01, либо вы не передаёте ALPN. Убедитесь в наличииacme-tls/1в трассе и корректном роутинге. - Терминация TLS на внешнем балансировщике: если внешний LB завершает TLS и не умеет пересылать ALPN
acme-tls/1дальше,tls-alpn-01не сработает. Используйтеhttp-01на 80-м или перенесите termination к себе. - IPv6-рассинхронизация: если AAAA указывает на другой узел или на нём закрыт 443, валидация может проходить по IPv6 и падать. Проверьте доступность по обеим семействам или временно уберите AAAA до исправления.
- Неверный SNI/мультидомен: прокси должен учитывать SNI при маршрутизации. В Nginx
streamдоступна переменная$ssl_preread_server_name— используйте её, если разводите трафик по доменам. - Конкуренция портов: один процесс должен слушать 443. Если у вас одновременно слушают http-блок Nginx и stream-блок, скорректируйте: 443 — только в
stream, а обычный HTTPS переведите на 4443 на localhost.

Когда лучше выбрать http-01 вместо tls-alpn-01
tls-alpn-01 прекрасно подходит, когда порт 80 закрыт намеренно, а вы контролируете TLS-стек на 443. Но в случаях, когда у вас жёсткая TLS-терминация на внешней стороне (CDN/LB без прозрачного TCP passthrough) или сложный L7-маршрутизатор, быстрее и проще настроить http-01 на 80-м с обычной раздачей токена через веб-сервер. Для коммерческих проектов также уместно рассмотреть SSL-сертификаты с расширенными гарантиями.
Особые случаи
- Wildcard-домены: выпуск
*.example.comне поддерживается ниhttp-01, ниtls-alpn-01. Нуженdns-01с управлением DNS-записями. См. разбор и автоматизацию в статье Wildcard через dns-01: автоматизация. - HTTP/3 (QUIC):
tls-alpn-01— TCP-443. QUIC использует UDP-443 и не мешает челленджу. Подробнее про конфигурацию читайте в материале Терминация HTTP/3 в HAProxy. - Kubernetes/Ingress: идея та же — фронтовой Ingress/Proxy должен уметь роутить ALPN
acme-tls/1на standalone-порт ACME-клиента. Либо используйте контроллер, который сам решает задачу авто-TLS.
Безопасность и эксплуатационные советы
- Давайте минимальные права файлам ключей (
0600) и храните их вне зон бэкапа общего доступа. - Включайте строгую валидацию конфигураций перед reload, чтобы не уронить прод при обновлении сертификата.
- Журналируйте каждую попытку валидации и держите метрики количества успешных/неуспешных обновлений.
- Обновляйте ACME-клиент и прокси до актуальных версий — ALPN/SSL-стек активно развивается.
Чеклист внедрения tls-alpn-01 за прокси
- Откройте TCP 443 на внешнем периметре и локальном фаерволе.
- Настройте прокси (Nginx stream или HAProxy) для роутинга по ALPN
acme-tls/1на локальный порт ACME-клиента. - Переведите обычный HTTPS-терминатор на localhost:4443 и убедитесь, что 443 слушается только на уровне L4-прокси.
- Выпустите первый сертификат:
sudo certbot certonly --standalone --preferred-challenges tls-alpn-01 --tls-alpn-01-port 10443 -d example.com. - Настройте автопродление через systemd-таймер и безопасный reload прокси.
- Проверьте
openssl s_client -alpn acme-tls/1 -connect example.com:443 -servername example.comи обычный TLS. - Заведите мониторинг срока действия сертификатов и алерты.
Итог: tls-alpn-01 — отличный инструмент для полностью «HTTPS-ориентированных» инфраструктур и для случаев, когда 80-й порт закрыт. Главное — корректно маршрутизировать ALPN acme-tls/1 на standalone-порт ACME-клиента и не пытаться заставить этот челлендж работать на 80-м. С правильно настроенным Nginx/HAProxy и автоматизацией через systemd вы получаете надёжный беспростойный выпуск и продление сертификатов в продакшне.


