К основному содержимому

Caddy Server: авто-HTTPS и reverse proxy без боли

Облако и DevOps · 19.04.2026 · 3 мин чтения
Иллюстрация к статье «Caddy Server: авто-HTTPS и reverse proxy без боли»

Caddy Server: современный веб-сервер

Caddy автоматически получает и обновляет SSL-сертификаты через Let's Encrypt без какой-либо ручной настройки. Это главное преимущество перед Nginx — не нужен Certbot.

Установка на Ubuntu/Debian

apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install caddy

Базовая конфигурация (Caddyfile)

# /etc/caddy/Caddyfile

yourdomain.com {
    root * /var/www/html
    file_server
    encode gzip
}

api.yourdomain.com {
    reverse_proxy localhost:3000
}

PHP-FPM с Caddy

yourdomain.com {
    root * /var/www/html
    encode gzip
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
    try_files {path} {path}/ /index.php?{query}
}

Заголовки безопасности

yourdomain.com {
    root * /var/www/html
    file_server
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        -Server
    }
}

Балансировка нагрузки

yourdomain.com {
    reverse_proxy {
        to localhost:8001 localhost:8002 localhost:8003
        lb_policy round_robin
        health_uri /ping
        health_interval 15s
    }
}

Управление сервисом

systemctl reload caddy
caddy validate --config /etc/caddy/Caddyfile
caddy fmt --overwrite /etc/caddy/Caddyfile
HTTP/3: Caddy включает HTTP/3 (QUIC) по умолчанию — ускоряет загрузку на мобильных сетях. Убедитесь, что порт UDP 443 открыт в firewall.

Разбор реальных ошибок Caddy

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

Permission denied при старте

{"level":"fatal","msg":"listen tcp :443: bind: permission denied"}

Порты ниже 1024 требует прав root или capability CAP_NET_BIND_SERVICE. Официальный systemd-юнит Caddy уже включает эту capability через AmbientCapabilities, поэтому проблема обычно возникает при запуске бинарника вручную (caddy run от обычного пользователя) или в контейнере без --cap-add=NET_BIND_SERVICE. Решение: запускать через systemctl start caddy или добавить capability явно через setcap 'cap_net_bind_service=+ep' /usr/bin/caddy.

ACME challenge не проходит

{"level":"error","msg":"job failed","error":"leaf certificate creation failed for yourdomain.com: ... [400] urn:ietf:params:acme:error:connection: Fetching http://yourdomain.com/.well-known/acme-challenge/xxxx: Connection refused"}

Let's Encrypt не смог достучаться до вашего сервера по порту 80 для HTTP-01 challenge. Причины почти всегда одни и те же: порт 80 закрыт в firewall, DNS-запись домена ещё не обновилась, или порт 80 занят другим процессом (проверьте ss -tlnp | grep :80). Пока challenge не проходит, Caddy отдаёт self-signed сертификат вместо настоящего.

Caddy vs Nginx vs Traefik

Все три сервера решают задачу reverse proxy, но по-разному расставляют приоритеты.

КритерийCaddyNginxTraefik
Авто-HTTPS из коробкиЕстьНет, нужен CertbotЕсть
Формат конфигаCaddyfile, декларативныйnginx.conf, императивныйYAML или Docker-лейблы
Родная поддержка PHP-FPMЕсть, php_fastcgiЕсть, fastcgi_passНет напрямую
Лучше всего подходит дляНебольшие и средние проекты с авто-SSLВысоконагруженная статика и проксиDocker и Kubernetes окружения

Когда Caddy не подходит

  • Нужна экосистема зрелых сторонних модулей — ModSecurity, njs-скрипты, десятилетия готовых рецептов конфигурации, которые есть у Nginx.
  • Команда уже держит сотни строк отлаженных nginx.conf и миграция обойдётся дороже пользы от авто-HTTPS.
  • Нужен raw TCP/UDP проксинг на уровне L4 без сборки кастомного бинарника через xcaddy с плагином layer4.
  • Инфраструктура целиком в Docker/Kubernetes с service discovery по лейблам — там нативнее выглядит Traefik.
  • Нужна тонкая настройка кэширования на диске (proxy_cache в стиле Nginx) — в Caddy это требует стороннего модуля cache-handler.

Проверка результата

# Проверить синтаксис перед применением
caddy validate --config /etc/caddy/Caddyfile

# Убедиться, что сервис поднялся и слушает порты
systemctl status caddy
ss -tlnp | grep -E ':(80|443)'

# Проверить, что сертификат настоящий, а не self-signed
curl -vI https://yourdomain.com 2>&1 | grep -i "subject\|issuer"

# Посмотреть последние строки лога при проблеме
journalctl -u caddy -n 50 --no-pager

Если issuer в выводе curl показывает CN=Caddy Local Authority вместо Let's Encrypt — значит ACME challenge не прошёл и сайт работает на самоподписанном сертификате. Смотрите логи через journalctl и проверяйте DNS с портом 80 отдельно, до перезапуска Caddy. Если Caddy стоит перед несколькими бэкендами, сверьте распределение нагрузки с материалом про Docker Swarm, а мониторинг живости бэкендов удобно вынести в Uptime Kuma.

Статья помогла?
← Назад в базу знаний Задать вопрос поддержке