OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

ACME tls-alpn-01 и порт 80: как правильно выпустить SSL за обратным прокси

Многие путают tls-alpn-01 с http-01 и запускают проверку на 80-м — валидация падает. Разбираем, почему челлендж обязателен на 443 с ALPN acme-tls/1, как прокинуть его через Nginx/HAProxy, настроить автопродление и диагностику.
ACME tls-alpn-01 и порт 80: как правильно выпустить SSL за обратным прокси

Если при поиске решения вы набрали в логе или в запросе что-то вроде «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 с ALPN acme-tls/1, где клиент поднимает временный сертификат со специальным расширением.

Если у вас закрыт порт 80, либо вы хотите принципиально выпускать сертификаты «через HTTPS», tls-alpn-01 — отличный выбор. Но у него два жёстких требования:

  • снаружи должен быть доступен TCP 443 (и по IPv4, и по IPv6, если публикуете AAAA);
  • на пути не должно быть TLS-терминации, «ломающей» ALPN, — либо прокси должен уметь прозрачно прокидывать соединение к локальному ACME-серверу, который отдаёт временный сертификат.

Коротко: tls-alpn-01 — только порт 443, с ALPN acme-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

Маршрутизация 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 только на время проверки.

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

Автопродление: 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.

Проверка ALPN acme-tls/1 через openssl s_client

Когда лучше выбрать 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-стек активно развивается.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Чеклист внедрения tls-alpn-01 за прокси

  1. Откройте TCP 443 на внешнем периметре и локальном фаерволе.
  2. Настройте прокси (Nginx stream или HAProxy) для роутинга по ALPN acme-tls/1 на локальный порт ACME-клиента.
  3. Переведите обычный HTTPS-терминатор на localhost:4443 и убедитесь, что 443 слушается только на уровне L4-прокси.
  4. Выпустите первый сертификат: sudo certbot certonly --standalone --preferred-challenges tls-alpn-01 --tls-alpn-01-port 10443 -d example.com.
  5. Настройте автопродление через systemd-таймер и безопасный reload прокси.
  6. Проверьте openssl s_client -alpn acme-tls/1 -connect example.com:443 -servername example.com и обычный TLS.
  7. Заведите мониторинг срока действия сертификатов и алерты.

Итог: tls-alpn-01 — отличный инструмент для полностью «HTTPS-ориентированных» инфраструктур и для случаев, когда 80-й порт закрыт. Главное — корректно маршрутизировать ALPN acme-tls/1 на standalone-порт ACME-клиента и не пытаться заставить этот челлендж работать на 80-м. С правильно настроенным Nginx/HAProxy и автоматизацией через systemd вы получаете надёжный беспростойный выпуск и продление сертификатов в продакшне.

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

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

MetalLB и K3s на VDS: L2 vs BGP, healthchecks и устойчивые Service IP OpenAI Статья написана AI (GPT 5)

MetalLB и K3s на VDS: L2 vs BGP, healthchecks и устойчивые Service IP

Как получить стабильные публичные Service IP в K3s на VDS? Разбираем MetalLB в режимах layer2 и BGP: когда что выбирать, ограничен ...
JWT в Nginx с njs: проверка HS256 и RS256 на реверс‑прокси OpenAI Статья написана AI (GPT 5)

JWT в Nginx с njs: проверка HS256 и RS256 на реверс‑прокси

Практическое руководство для админов и DevOps: как валидировать JWT прямо на уровне Nginx с помощью njs. Разберём HS256 и RS256, с ...
TimescaleDB на VDS: hypertable, compression и retention для быстрых time series OpenAI Статья написана AI (GPT 5)

TimescaleDB на VDS: hypertable, compression и retention для быстрых time series

Поднимем TimescaleDB на VDS и выжмем максимум из time series. Создадим hypertable, подберём интервал чанка, включим compression и ...