NoctisNode
← ГайдыБезопасность2026-10-2310 мин

Автоматический HTTPS в Caddy: как работает auto TLS и как чинить ошибки

Caddy получает и продлевает TLS-сертификаты через ACME для каждого домена в конфиге. Разбираем HTTP-01, TLS-ALPN-01, wildcard через DNS-01, on-demand TLS и типичные сбои.

Коротко: Caddy автоматически включает HTTPS для любого адреса сайта, который является публичным доменным именем. Он запрашивает сертификат по ACME (по умолчанию Let's Encrypt или ZeroSSL), подтверждает контроль над доменом через challenge HTTP-01 или TLS-ALPN-01 на портах 80 и 443, перенаправляет HTTP на HTTPS и продлевает сертификат до истечения срока — без дополнительной настройки.

Reverse proxy на Caddy — это просто Caddy, который терминирует HTTPS-соединение и пересылает запрос приложению на другом порту, в контейнере или на другом хосте с помощью директивы `reverse_proxy`. Именно это сочетание — TLS плюс проксирование в несколько строк — главная причина, по которой выбирают Caddy.

Reverse proxy с SSL в три строки

Если DNS указывает на сервер, а порты 80 и 443 доступны, этот Caddyfile — полноценный HTTPS reverse proxy для двух имён хостов. Caddy при запуске получает сертификаты для обоих имён, обслуживает HTTP/1.1, HTTP/2 и HTTP/3 и передаёт бэкенду `X-Forwarded-For`, `X-Forwarded-Proto` и `X-Forwarded-Host`. Опция `email` необязательна, но позволяет CA связаться с вами по поводу истекающих или отозванных сертификатов.

Установка из официального apt-репозитория и основы systemd описаны в руководстве по Caddy как reverse proxy; для контейнеров см. Caddy как reverse proxy для Docker. Применяйте изменения командой `sudo systemctl reload caddy`.

# /etc/caddy/Caddyfile
{
	email [email protected]
}

example.com, www.example.com {
	reverse_proxy 127.0.0.1:8080
}

Как auto TLS в Caddy устроен внутри

При загрузке конфига Caddy собирает все имена хостов из адресов сайтов и решает, кто должен выпустить каждый сертификат. Публичные домены уходят к публичным ACME-издателям; `localhost`, IP-адреса и внутренние имена получают сертификаты от собственного локального CA Caddy (то же, что написать `tls internal`). Сертификаты, ключи и ACME-аккаунт хранятся в каталоге данных Caddy: `/var/lib/caddy/.local/share/caddy` для apt-пакета, `/data` в официальном Docker-образе.

Продление происходит в фоне задолго до истечения срока, а там, где CA это поддерживает, Caddy прикрепляет OCSP-ответы (stapling). Если выпуск не удался, Caddy повторяет попытки с экспоненциальной задержкой и использует staging-эндпоинт CA для повторов, чтобы не расходовать боевые лимиты. Несколько экземпляров Caddy с общим хранилищем координируются, так что конкретный сертификат запрашивает только один из них.

ChallengeЧто проверяет CAЧто нужноWildcard?
HTTP-01Токен по адресу `http://domain/.well-known/acme-challenge/`Порт 80, доступный из интернетаНет
TLS-ALPN-01Специальный сертификат, предъявленный при TLS-рукопожатииПорт 443, доступный из интернетаНет
DNS-01TXT-запись `_acme-challenge.domain`API-токен DNS-провайдера и сборка Caddy с модулем этого провайдераДа

Wildcard-сертификаты через DNS-01

Wildcard-сертификаты вроде `*.example.com` можно выпустить только через challenge DNS-01. Стандартный бинарник Caddy не содержит плагинов DNS-провайдеров, поэтому соберите его с помощью xcaddy (или выберите провайдера на официальной странице загрузки) и выдайте Caddy API-токен, ограниченный редактированием DNS этой зоны. DNS-01 работает и тогда, когда порты 80 и 443 недоступны из интернета, например на внутреннем сервере.

Не держите токен в Caddyfile: положите его в файл окружения, который использует unit systemd (`sudo systemctl edit caddy`, затем `EnvironmentFile=/etc/caddy/caddy.env` в секции `[Service]`), и ограничьте доступ к файлу через `chmod 600`.

# Build Caddy with a DNS provider module (example: Cloudflare)
xcaddy build --with github.com/caddy-dns/cloudflare

# Caddyfile: one wildcard certificate for all subdomains
*.example.com {
	tls {
		dns cloudflare {env.CF_API_TOKEN}
	}

	@app host app.example.com
	handle @app {
		reverse_proxy 127.0.0.1:3000
	}

	handle {
		respond "Unknown host" 404
	}
}

On-demand TLS и staging

On-demand TLS заставляет Caddy получать сертификат во время первого TLS-рукопожатия для имени хоста, которое он ещё не видел. Это нужно платформам, где клиенты направляют на ваш сервер собственные домены. Всегда настраивайте эндпоинт `ask`: Caddy вызывает его с `?domain=name` и продолжает только при ответе 200. Без него кто угодно может направить на ваш IP случайные имена и довести вас до лимитов.

Во время экспериментов переключитесь на staging CA Let's Encrypt через глобальную опцию `acme_ca`. Браузеры не доверяют staging-сертификатам, но лимиты там гораздо выше, так что можно спокойно ломать и чинить. Когда закончите, удалите опцию и, при желании, staging-сертификаты из каталога данных.

{
	on_demand_tls {
		ask http://127.0.0.1:5555/allowed
	}
}

https:// {
	tls {
		on_demand
	}
	reverse_proxy 127.0.0.1:8080
}

# Global options block for testing
{
	email [email protected]
	# Test against Let's Encrypt staging; remove when everything works
	acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

Типичные ошибки TLS в Caddy и как их исправить

  1. 01.DNS не указывает на сервер: A- или AAAA-записи нет, она всё ещё указывает на старый сервер или закэширована. Устаревшая AAAA-запись — классическая ловушка, ведь CA предпочитает IPv6, если он есть. Проверьте обе через `dig`.
  2. 02.Закрыт порт 80 или 443: хостовый файрвол, облачный файрвол или роутер блокирует входящий трафик, и ни HTTP-01, ни TLS-ALPN-01 не проходят. Откройте 80/tcp и 443/tcp (и 443/udp для HTTP/3).
  3. 03.Порт уже занят: Apache, nginx или другой контейнер слушает 80 или 443, и Caddy не может занять порт. Остановите другой сервис или поставьте его за Caddy.
  4. 04.Впереди CDN-прокси: прокси в стиле «оранжевого облака» терминирует TLS до Caddy, что может сломать TLS-ALPN-01. Используйте DNS-01 или переключите запись в режим «только DNS» на время выпуска.
  5. 05.Лимиты: повторные неудачные попытки или очистка каталога данных приводят к лимитам CA (Let's Encrypt ограничивает неудачные валидации на имя хоста в час и дубликаты сертификатов в неделю). Устраните первопричину, используйте staging и сохраняйте каталог данных постоянным.
  6. 06.CAA-запись: CAA-запись, разрешающая только другой CA, блокирует выпуск. Разрешите `letsencrypt.org` и `sectigo.com` (используется ZeroSSL) или уберите ограничение.
# Does the name resolve to this server (both IPv4 and IPv6)?
dig +short A example.com
dig +short AAAA example.com
curl -4 -s https://ifconfig.me ; echo

# Are ports 80 and 443 open in the host firewall?
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp

# Is something else already bound to 80/443?
sudo ss -ltnp '( sport = :80 or sport = :443 )'

# What does Caddy say?
sudo journalctl -u caddy --no-pager -n 100

HTTPS и до бэкенда

Большинство бэкендов на том же хосте говорят по обычному HTTP на localhost, и это нормально. Если апстрим на другой машине или требует TLS, используйте апстрим `https://` и укажите Caddy, какое имя проверять и какому CA доверять. Не используйте `tls_insecure_skip_verify` вне быстрых тестов: это убирает защиту от перехвата между прокси и бэкендом. Для трафика между серверами приватный туннель WireGuard часто проще, чем управление сертификатами бэкендов.

На VPS NoctisNode с полным root и выделенным IPv4-адресом обычная схема такая: направьте A-запись на сервер (без AAAA, если у сервера нет IPv6), откройте 80 и 443, а остальное сделает Caddy. Если нужно пересылать не-HTTP-трафик, см. проксирование TCP и SSH в Caddy.

example.com {
	reverse_proxy https://10.0.0.5:8443 {
		transport http {
			tls_server_name backend.internal
			tls_trust_pool file /etc/caddy/backend-ca.pem
		}
	}
}

FAQ

QЧто такое reverse proxy на Caddy?

AЭто веб-сервер Caddy, который принимает клиентские соединения, обычно терминирует HTTPS и пересылает запросы одному или нескольким бэкенд-сервисам директивой `reverse_proxy`. TLS-сертификаты для этого Caddy получает и продлевает автоматически.

QCaddy продлевает сертификаты автоматически?

AДа. Caddy продлевает сертификаты в фоне задолго до истечения и подгружает их без перезапуска — при условии, что домен по-прежнему указывает на сервер, а порты для challenge доступны.

QПочему Caddy не получает сертификат?

AЧаще всего DNS-записи указывают в другое место (включая устаревшую AAAA-запись), порты 80 и 443 заблокированы, их занимает другая программа или сработали лимиты после повторных неудач. `journalctl -u caddy` покажет точную ошибку ACME.

QМожет ли Caddy выпустить wildcard-сертификат?

AДа, но только через challenge DNS-01 — для этого нужна сборка Caddy с модулем вашего DNS-провайдера и API-токен для этой зоны.

QКак отключить автоматический HTTPS в Caddy?

AИспользуйте адрес сайта `http://` для отдельного сайта или задайте глобальную опцию `auto_https off`. Можно также указать `auto_https disable_redirects`, чтобы оставить сертификаты, но убрать редирект с HTTP на HTTPS.

Автоматический HTTPS в Caddy: как работает auto TLS и как чинить ошибки · NoctisNode