Caddy Reverse Proxy Guide 2026: Automatic HTTPS Made Easy
Set up Caddy as a reverse proxy with automatic HTTPS, zero-config SSL, and simple Caddyfile syntax. Complete VPS deployment guide.
Caddy Reverse Proxy Guide: Automatic HTTPS Made Easy
Caddy is the web server that does HTTPS by default. No certbot, no cron jobs, no renewal scripts. Point a domain at Caddy and it gets a certificate automatically.
What is Caddy?
What is Caddy?
Caddy sits between the internet and your services:
Internet → Caddy → Service A (app.domain.com)
→ Service B (api.domain.com)
→ Service C (admin.domain.com)
Why developers love Caddy:
- Automatic HTTPS — SSL certificates with zero configuration
- Simple config — The Caddyfile is human-readable
- HTTP/2 and HTTP/3 — Enabled by default
- Single binary — No dependencies
- API-driven — Change config without restarts
Caddy vs Nginx vs Traefik
| Feature | Caddy | Nginx | Traefik |
|---|---|---|---|
| Auto HTTPS | Default | Certbot needed | Built-in |
| Config syntax | Simple | Moderate | Complex |
| Docker integration | Good | Manual | Native |
| Performance | Excellent | Excellent | Excellent |
| Plugins | Go modules | C modules | Middleware |
| Config reload | Zero-downtime | Requires signal | Hot reload |
| Learning curve | Low | Moderate | Higher |
Caddy wins on simplicity. If you want the easiest reverse proxy setup, this is it. See our Traefik Docker guide for container-native routing.
VPS Requirements
Caddy is extremely lightweight:
- 1 vCPU
- 256MB RAM (for Caddy itself)
- Ports 80, 443
- A domain name pointing to your VPS
Your VPS sizing depends on your backend services, not Caddy. Check our best VPS for Docker guide for sizing recommendations.
Install Caddy
Option 1: Package Manager (Debian/Ubuntu)
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
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
Option 2: Docker
# docker-compose.yml
services:
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- 80:80
- 443:443
- 443:443/udp # HTTP/3
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
Option 3: Single Binary
curl -sS https://webi.sh/caddy | sh
Basic Reverse Proxy
The Simplest Caddyfile
app.domain.com {
reverse_proxy localhost:3000
}
That’s it. Caddy will:
- Listen on ports 80 and 443
- Get an SSL certificate from Let’s Encrypt
- Redirect HTTP to HTTPS
- Proxy traffic to your app on port 3000
Multiple Services
app.domain.com {
reverse_proxy localhost:3000
}
api.domain.com {
reverse_proxy localhost:8080
}
admin.domain.com {
reverse_proxy localhost:9000
}
Each domain gets its own certificate automatically.
Docker Reverse Proxy Setup
Step 1: Create Project Directory
mkdir -p /opt/caddy
cd /opt/caddy
Step 2: Docker Compose
# docker-compose.yml
services:
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- 80:80
- 443:443
- 443:443/udp
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- caddy
whoami:
image: traefik/whoami
container_name: whoami
networks:
- caddy
networks:
caddy:
name: caddy
volumes:
caddy_data:
caddy_config:
Step 3: Caddyfile
test.domain.com {
reverse_proxy whoami:80
}
Step 4: Launch
docker compose up -d
Visit https://test.domain.com — it works with full HTTPS.
Adding More Docker Services
Any service on the caddy network can be proxied:
# separate docker-compose.yml
services:
myapp:
image: myapp:latest
container_name: myapp
networks:
- caddy
networks:
caddy:
external: true
Then add to your Caddyfile:
myapp.domain.com {
reverse_proxy myapp:8080
}
Reload Caddy:
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
Path-Based Routing
Route by Path
domain.com {
handle /api/* {
reverse_proxy localhost:8080
}
handle /admin/* {
reverse_proxy localhost:9000
}
handle {
reverse_proxy localhost:3000
}
}
Strip Path Prefix
domain.com {
handle_path /api/* {
reverse_proxy localhost:8080
}
}
handle_path strips the matched prefix. /api/users becomes /users for the backend.
Load Balancing
Round Robin (Default)
app.domain.com {
reverse_proxy app1:3000 app2:3000 app3:3000
}
With Health Checks
app.domain.com {
reverse_proxy app1:3000 app2:3000 {
health_uri /health
health_interval 10s
health_timeout 5s
}
}
Sticky Sessions
app.domain.com {
reverse_proxy app1:3000 app2:3000 {
lb_policy cookie
}
}
Least Connections
app.domain.com {
reverse_proxy app1:3000 app2:3000 {
lb_policy least_conn
}
}
Security
Basic Authentication
# Generate password hash
caddy hash-password --plaintext 'your-secure-password'
admin.domain.com {
basicauth {
admin $2a$14$Zkx19...hashed...password
}
reverse_proxy localhost:9000
}
IP Allowlist
admin.domain.com {
@blocked not remote_ip 192.168.1.0/24 10.0.0.0/8
respond @blocked 403
reverse_proxy localhost:9000
}
Rate Limiting
api.domain.com {
rate_limit {
zone dynamic {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:8080
}
Security Headers
domain.com {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
reverse_proxy localhost:3000
}
The -Server directive removes the Server header from responses.
Wildcard Certificates
For *.domain.com, use DNS challenge:
*.domain.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
@app host app.domain.com
handle @app {
reverse_proxy localhost:3000
}
@api host api.domain.com
handle @api {
reverse_proxy localhost:8080
}
}
Build Caddy with the Cloudflare DNS module:
xcaddy build --with github.com/caddy-dns/cloudflare
Or use the Docker image with modules:
services:
caddy:
image: caddy:2-builder AS builder
# Use multi-stage or pre-built custom image
Static Files + API
SPA with API Backend
domain.com {
handle /api/* {
reverse_proxy localhost:8080
}
handle {
root * /srv/frontend
try_files {path} /index.html
file_server
}
}
Serve Static + Proxy
domain.com {
root * /var/www/html
file_server
handle /app/* {
reverse_proxy localhost:3000
}
}
WebSocket Support
Caddy proxies WebSocket connections automatically:
ws.domain.com {
reverse_proxy localhost:8080
}
No extra configuration needed. Caddy detects the Upgrade header and handles it.
Logging
Access Logs
domain.com {
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 5
}
format json
}
reverse_proxy localhost:3000
}
Per-Site Logging
app.domain.com {
log {
output file /var/log/caddy/app.log
}
reverse_proxy localhost:3000
}
api.domain.com {
log {
output file /var/log/caddy/api.log
}
reverse_proxy localhost:8080
}
Compression
domain.com {
encode gzip zstd
reverse_proxy localhost:3000
}
Caddy supports both gzip and Zstandard compression out of the box.
CORS Headers
api.domain.com {
header Access-Control-Allow-Origin "https://app.domain.com"
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
header Access-Control-Allow-Headers "Content-Type, Authorization"
@options method OPTIONS
respond @options 204
reverse_proxy localhost:8080
}
Redirects
WWW to Apex
www.domain.com {
redir https://domain.com{uri} permanent
}
domain.com {
reverse_proxy localhost:3000
}
HTTP to HTTPS
Caddy does this automatically. No configuration needed.
Custom Redirects
domain.com {
redir /old-page /new-page permanent
redir /blog/* /articles/{re.1} permanent
reverse_proxy localhost:3000
}
Caching
domain.com {
header /static/* Cache-Control "public, max-age=31536000, immutable"
header /api/* Cache-Control "no-cache"
reverse_proxy localhost:3000
}
Configuration via API
Caddy has a full REST API for config changes:
# Get current config
curl localhost:2019/config/
# Update a route
curl localhost:2019/config/apps/http/servers/srv0/routes/0 \
-X PUT \
-H "Content-Type: application/json" \
-d '{"handle": [{"handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3001"}]}]}'
# Reload from Caddyfile
caddy reload --config /etc/caddy/Caddyfile
Troubleshooting
Certificate Not Issued
- Check DNS points to your VPS:
dig +short domain.com
- Ensure ports 80 and 443 are open:
sudo ufw allow 80,443/tcp
- Check Caddy logs:
journalctl -u caddy --no-pager -n 50
# Or for Docker:
docker logs caddy
502 Bad Gateway
- Verify backend is running:
curl localhost:3000
-
Check the upstream address in Caddyfile
-
For Docker: ensure both containers are on the same network
Config Syntax Error
caddy validate --config /etc/caddy/Caddyfile
Slow Performance
- Enable compression:
encode gzip zstd
-
Check backend response times
-
Add connection timeouts:
reverse_proxy localhost:3000 {
transport http {
dial_timeout 5s
response_header_timeout 10s
}
}
Production Checklist
- DNS records pointing to VPS
- Firewall allows ports 80, 443
- Caddyfile validated (
caddy validate) - Access logs enabled
- Security headers configured
- Backend health checks set up
- Compression enabled
- Backup
/datadirectory (certificates)
Best VPS for Caddy
Caddy runs anywhere. Pick your VPS based on your backend needs:
| Provider | Plan | Price | Best For |
|---|---|---|---|
| Hostinger | KVM1 | $4.99 | Best value starter |
| Hetzner | CX22 | €5.49 | Europe-based projects |
| DigitalOcean | Basic | $6 | Developer-friendly |
| Vultr | VC2 | $6 | Global edge locations |
Hostinger offers the best bang for your buck if you’re starting out. Their KVM1 plan handles Caddy plus several backend services comfortably.
FAQ
Is Caddy production-ready?
Absolutely. Caddy v2 powers thousands of production sites. It’s used by companies of all sizes.
Caddy vs Nginx for reverse proxy?
Caddy for simplicity and automatic HTTPS. Nginx for maximum control and legacy configurations. For most new deployments, Caddy saves hours of setup time.
How does automatic HTTPS work?
Caddy uses the ACME protocol to get certificates from Let’s Encrypt (or ZeroSSL). It handles issuance, renewal, and OCSP stapling automatically.
Can Caddy replace Apache?
Yes. Caddy handles everything Apache does for modern web deployments, with a fraction of the config.
Does Caddy support HTTP/3?
Yes, HTTP/3 (QUIC) is enabled by default on the HTTPS port.
How do I update Caddy?
Package manager: apt upgrade caddy. Docker: pull the new image. Binary: download and replace.
Summary
Caddy makes reverse proxying simple:
| Task | Nginx | Caddy |
|---|---|---|
| Get SSL | Install certbot, configure | Automatic |
| Add service | Edit config, test, reload | Add 3 lines, reload |
| Redirect HTTP→HTTPS | Add server block | Automatic |
| Enable HTTP/2 | Configure | Automatic |
| Config syntax | Complex | Human-readable |
Three lines in a Caddyfile replace dozens in Nginx config. For new projects, Caddy is the fastest path to a secure, production-ready reverse proxy. Pair it with Docker Compose for a complete deployment workflow, or check out our VPS hardening guide to lock down the rest of your server.
Ready to get started?
Get the best VPS hosting deal today. Hostinger offers 4GB RAM VPS starting at just $4.99/mo.
Get Hostinger VPS — $4.99/mo// up to 75% off + free domain included
// related topics
// related guides
$1 VPS Hosting 2026: Cheapest VPS Servers Starting at $1/Month
Looking for $1 VPS hosting? Compare the cheapest VPS providers starting from $1-3/month. Real specs, no hidden fees, honest reviews of budget VPS options.
tutorialCloudflare Tunnel VPS Guide 2026: Expose Services Without Opening Ports
Set up Cloudflare Tunnel on your VPS to expose web apps securely without opening ports or revealing your server IP. Complete guide with Docker and DNS config.
tutorialCoolify VPS Setup Guide 2026: Self-Hosted Vercel Alternative
Deploy Coolify on your VPS for a self-hosted Vercel/Netlify experience. Complete setup guide with Docker, SSL, and app deployments.
tutorialVPS with Crypto & No KYC — 7 Providers That Accept Bitcoin
Pay for VPS hosting with Bitcoin, Monero, or ETH — no ID required. We list 7 privacy-first providers with anonymous signup. Updated March 2026.
Andrius Putna
I am Andrius Putna. Geek. Since early 2000 in love tinkering with web technologies. Now AI. Bridging business and technology to drive meaningful impact. Combining expertise in customer experience, technology, and business strategy to deliver valuable insights. Father, open-source contributor, investor, 2xIronman, MBA graduate.
// last updated: March 11, 2026. Disclosure: This article may contain affiliate links.