Caddy Web Server Setup
Caddy is a modern web server written in Go with automatic HTTPS via Let's Encrypt. Obtains and renews SSL certificates without certbot configuration. Configuration is orders of magnitude simpler than Nginx.
Installation
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-main main" | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install caddy
Caddyfile
# /etc/caddy/Caddyfile
# Automatic HTTPS - just specify the domain
example.com {
root * /var/www/myapp/public
# PHP-FPM
php_fastcgi unix//var/run/php/php8.3-fpm.sock
# SPA: all requests to index.html
try_files {path} /index.php?{query}
# Compression
encode gzip
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Frame-Options "DENY"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server # remove Server header
}
# Static assets
@static {
path *.css *.js *.jpg *.png *.gif *.ico *.svg *.woff2
}
header @static Cache-Control "public, max-age=31536000, immutable"
# Deny .env
@dotfiles {
path /.*
}
respond @dotfiles 403
log {
output file /var/log/caddy/access.log
format json
}
}
# Reverse proxy for Node.js
api.example.com {
reverse_proxy localhost:3000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
# Redirect www to non-www
www.example.com {
redir https://example.com{uri} permanent
}
Multiple sites
# All in one file
site1.com {
root * /var/www/site1/public
php_fastcgi unix//var/run/php/php8.3-fpm.sock
encode gzip
}
site2.com {
reverse_proxy localhost:4000
}
# Wildcard (requires DNS provider with ACME DNS challenge support)
*.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
reverse_proxy localhost:8080
}
Caddy API (JSON config)
# Reload config via API
curl -X POST "http://localhost:2019/load" \
-H "Content-Type: application/json" \
-d @caddy.json
# Check current configuration
curl http://localhost:2019/config/
Docker
# docker-compose.yml
services:
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data # stores certificates
- caddy_config:/config
restart: unless-stopped
volumes:
caddy_data:
caddy_config:
Timeline
Caddy is the fastest web server to set up: basic configuration with SSL takes 1–2 hours.







