Caddy come reverse proxy: più semplice di Nginx, HTTPS automatico
Come sostituire Nginx con Caddy per esporre servizi self-hosted con HTTPS automatico e configurazione in 10 righe. Guida pratica con Docker Compose.
Pubblicato: 3 giugno 2025
Nginx è ottimo, ma ogni volta che aggiungi un servizio devi scrivere un blocco di configurazione, ricordarti di ricaricare certbot, rinnovare il certificato manualmente se qualcosa va storto. Caddy risolve tutto questo per default: HTTPS con Let’s Encrypt è automatico, il Caddyfile è leggibile, e bastano davvero 10 righe per esporre tre servizi su domini diversi.
Perché Caddy invece di Nginx
Nginx ha una configurazione verbosa e il TLS richiede certbot come processo separato con cron job di rinnovo. Caddy gestisce tutto internamente: ottiene il certificato al primo avvio, lo rinnova da solo, e se il dominio non è ancora propagato riprova in background senza crashare.
Per un server self-hosted con 5-10 servizi, Caddy riduce la configurazione da 150 righe a 30. Non è una questione di prestazioni — Nginx e Caddy sono equivalenti su traffico normale — è una questione di manutenzione.
Caddyfile base
Un Caddyfile che espone tre servizi locali su HTTPS:
app.example.com {
reverse_proxy localhost:3000
}
api.example.com {
reverse_proxy localhost:8000
}
monitor.example.com {
reverse_proxy localhost:9000
}
Questo è tutto. Caddy contatta Let’s Encrypt, ottiene tre certificati, li rinnova automaticamente. Non tocchi più niente.
Docker Compose con Caddy come gateway
Nella pratica, i tuoi servizi girano già in container. Ecco un docker-compose.yml completo con Caddy davanti a due servizi:
services:
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- proxy
open-webui:
image: ghcr.io/open-webui/open-webui:main
networks:
- proxy
portainer:
image: portainer/portainer-ce:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- proxy
networks:
proxy:
volumes:
caddy_data:
caddy_config:
Il Caddyfile corrispondente usa i nomi dei servizi Docker come hostname (Caddy e i container sono sulla stessa network):
chat.example.com {
reverse_proxy open-webui:8080
}
portainer.example.com {
reverse_proxy portainer:9000
}
Wildcard certificate con Cloudflare
Se vuoi un singolo certificato wildcard per *.example.com invece di uno per dominio, devi fare il DNS challenge. Funziona solo se il tuo DNS è su Cloudflare (o altro provider supportato).
Usa l’immagine caddy:2-builder per compilare Caddy con il plugin DNS:
FROM caddy:2-builder AS builder
RUN xcaddy build --with github.com/caddy-dns/cloudflare
FROM caddy:2-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
Nel Caddyfile:
*.example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
@webui host chat.example.com
handle @webui {
reverse_proxy open-webui:8080
}
}
Passa il token Cloudflare come variabile d’ambiente nel docker-compose.yml. Non serve aprire la porta 80 per il DNS challenge.
Cosa fare
- Installa Caddy con
docker compose up -d, punta un sottodominio al tuo IP e guarda i log condocker compose logs caddyper vedere il certificato emesso in tempo reale - Migra da Nginx un servizio alla volta: metti Caddy in ascolto su una porta alternativa (ad es. 8443) per testare prima di spostare il traffico principale
- Se usi Cloudflare, attiva il DNS challenge e consolida tutto sotto un wildcard
*.tuodominio.comper evitare di gestire certificati singoli per ogni nuovo servizio