До основного вмісту

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 проти Nginx і 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.

Чи була стаття корисною?
← Назад до бази знань Поставити питання підтримці