С Nginx нужно установить certbot, написать конфиг виртуального хоста, настроить cronjob для обновления сертификата, вернуться через 90 дней и убедиться что всё работает. С Caddy весь этот список заменяет одна строка. Не потому что Caddy «умнее» — а потому что HTTPS в нём встроен на уровне архитектуры, а не добавлен сверху.
Установка
Debian / Ubuntu — официальный репозиторий:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy
Проверить версию:
caddy version
Caddy автоматически создаёт systemd-юнит при установке из пакета. Проверить статус:
systemctl status caddy
Как работает автоматический HTTPS
Caddy использует протокол ACME (тот же что использует Let's Encrypt) напрямую — без certbot как посредника. При первом запуске с доменным именем Caddy:
- Генерирует приватный ключ
- Проходит ACME challenge (HTTP-01 или TLS-ALPN-01)
- Получает сертификат от Let's Encrypt или ZeroSSL
- Сохраняет его в
~/.local/share/caddy/(или/var/lib/caddy/) - За 30 дней до истечения — автоматически обновляет
Никаких cron, никаких certbot renew. Сертификат живёт сам.
Важно для VPS: порт 80 должен быть открыт для HTTP-01 challenge, и DNS должен указывать на сервер до первого запуска Caddy с доменом.
Caddyfile: язык конфигурации
Caddyfile — декларативный формат. Блок начинается с адреса, внутри — директивы.
Простейший статический сайт с автоматическим HTTPS:
example.com {
root * /var/www/html
file_server
}
Это всё. Caddy сам получит сертификат, настроит редирект с HTTP на HTTPS и будет раздавать файлы.
Несколько доменов в одном файле:
example.com {
root * /var/www/example
file_server
}
blog.example.com {
root * /var/www/blog
file_server
}
Применить новый конфиг без перезапуска (graceful reload):
sudo systemctl reload caddy
Или напрямую:
caddy reload --config /etc/caddy/Caddyfile
Reverse proxy: самый частый сценарий на VPS
Приложение на Node.js / Python / Go слушает на localhost:3000 — Caddy проксирует снаружи с HTTPS:
api.example.com {
reverse_proxy localhost:3000
}
Две строки. Caddy добавит заголовки X-Forwarded-For, X-Real-IP автоматически.
С балансировкой между несколькими бэкендами:
app.example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002
}
По умолчанию — round-robin. Можно добавить health check:
app.example.com {
reverse_proxy localhost:3000 localhost:3001 {
health_uri /health
health_interval 10s
health_timeout 2s
}
}
Несколько сервисов на одном сервере
Классическая задача на VPS — несколько проектов на одном IP. С Nginx нужен отдельный конфиг и сертификат для каждого. С Caddy:
site1.example.com {
reverse_proxy localhost:8001
}
site2.example.com {
reverse_proxy localhost:8002
}
api.example.com {
reverse_proxy localhost:4000
header {
Access-Control-Allow-Origin *
}
}
Каждый домен получит свой сертификат автоматически. Caddy запрашивает их параллельно при старте.
Базовая аутентификация
Защитить приватный сервис паролем:
Сгенерировать хеш пароля:
caddy hash-password --plaintext "mypassword"
Добавить в конфиг:
private.example.com {
basicauth {
admin JDJhJDE0JHBxZ3...хеш...
}
reverse_proxy localhost:8080
}
Caddy в Docker
docker-compose.yml для Caddy с автоматическим HTTPS:
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
app:
image: myapp:latest
expose:
- "3000"
volumes:
caddy_data:
caddy_config:
Caddyfile рядом:
example.com {
reverse_proxy app:3000
}
caddy_data — том для сертификатов. Важно сохранять его между перезапусками контейнера, иначе Caddy будет запрашивать новый сертификат при каждом старте и упрётся в rate limit Let's Encrypt (50 сертификатов на домен в неделю).
Локальная разработка: HTTPS без Let's Encrypt
Для localhost и внутренних доменов Caddy создаёт собственный локальный CA и выдаёт сертификаты от него:
caddy run --config Caddyfile
localhost {
reverse_proxy localhost:3000
}
Добавить локальный CA в доверенные (один раз):
caddy trust
После этого браузер принимает https://localhost без предупреждений. Это работает через mkcert-подобный механизм встроенный прямо в Caddy.
Сравнение с Nginx для типичных задач VPS
| Задача | Nginx | Caddy |
|---|---|---|
| Статический сайт с HTTPS | конфиг + certbot + cron | 2 строки в Caddyfile |
| Reverse proxy | 10+ строк конфига | 3 строки |
| Обновление сертификата | вручную или cron | автоматически |
| Несколько доменов | отдельный файл на каждый | один Caddyfile |
| HTTP/2 | включить вручную | по умолчанию |
| HTTP/3 (QUIC) | экспериментально | по умолчанию |
| Конфиг через API | нет | встроенный REST API |
| Потребление памяти | ~5–10 МБ | ~20–30 МБ |
Nginx быстрее при очень высоких нагрузках и имеет больше модулей. Caddy выигрывает когда нужно быстро поднять сервис без операционных затрат на управление сертификатами.
API управления: менять конфиг без файлов
Caddy имеет встроенный REST API на localhost:2019. Изменить конфигурацию без редактирования файлов:
Посмотреть текущую конфигурацию:
curl localhost:2019/config/
Добавить новый маршрут на лету:
curl -X POST localhost:2019/load \
-H "Content-Type: application/json" \
-d @new-config.json
Это полезно в автоматизации — например в скриптах деплоя которые добавляют новые поддомены без перезагрузки сервера.
Шпаргалка
| Задача | Команда / конфиг |
|---|---|
| Статический сайт с HTTPS | example.com { root * /path; file_server } |
| Reverse proxy | example.com { reverse_proxy localhost:3000 } |
| Перезагрузить конфиг | sudo systemctl reload caddy |
| Проверить конфиг | caddy validate --config /etc/caddy/Caddyfile |
| Хеш пароля | caddy hash-password --plaintext "pass" |
| Доверять локальному CA | caddy trust |
| Текущий конфиг через API | curl localhost:2019/config/ |
| Где хранятся сертификаты | /var/lib/caddy/.local/share/caddy/ |