Caddy è un web server e reverse proxy open-source scritto in Go, noto per la sua semplicità di configurazione e per la gestione automatica dei certificati HTTPS tramite Let’s Encrypt. A differenza di altri web server come Nginx Reverse Proxy , Caddy abilita HTTPS di default senza richiedere configurazioni manuali, rendendo la messa in sicurezza dei propri servizi (anche all’interno della propria rete) un processo praticamente trasparente.
Tutta la configurazione avviene in modo dichiarativo tramite un unico file chiamato Caddyfile, con una sintassi semplice e intuitiva che lo rende accessibile anche a chi non ha grande esperienza con i web server. Oltre al reverse proxy, Caddy offre un supporto nativo al load balancing e alla compressione automatica.
Processo di Installazione
Dopo aver installato Docker Engine e Docker Compose, è possibile procedere con l’installazione di Caddy utilizzando un container Docker. La configurazione richiede il file docker-compose.yml per definire il servizio e un Caddyfile per configurare i siti e i reverse proxy.
Installazione Standard
Per una configurazione base, il file docker-compose.yml qui sotto è sufficiente per avviare Caddy. Le porte esposte sono la 80 (HTTP) e la 443 (HTTPS), necessarie per servire il traffico web e gestire i certificati TLS automatici.
services:
caddy:
container_name: Caddy
image: caddy:latest
restart: always
ports:
- '80:80'
- '443:443'
- '443:443/udp'
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:In questa configurazione sono stati creati due volumi: caddy_data per memorizzare i certificati TLS e le informazioni persistenti, e caddy_config per la configurazione runtime di Caddy. La porta 443/udp è necessaria per il supporto al protocollo HTTP/3 (QUIC). Il Caddyfile viene montato direttamente dalla directory corrente.
Installazione con DNS Challenge
Nel caso i servizi fossero dietro un firewall o un NAT, oppure si avesse bisogno di certificati wildcard, è possibile ottenere i certificati Let’s Encrypt tramite una DNS Challenge. Questo metodo verifica (attraverso una chiamata API al provider DNS, come Cloudflare) la proprietà del dominio creando un record TXT nel DNS anziché rispondere a una richiesta HTTP, ed una volta eseguita la verifica il sistema scaricherà ed installerà il certificato.
Questo approccio richiede un plugin DNS per il provider scelto che (al momento della scrittura della guida) non è incluso nell’immagine ufficiale di Caddy. Sarà quindi necessario aggiungerlo andando a creare un Dockerfile dedicato, così da poter compilare Caddy con il modulo caddy-dns/cloudflare tramite xcaddy.
Questo Dockerfile utilizza un multi-stage build, ovvero una costruzione in due fasi separate: nella prima compila Caddy aggiungendo il plugin di Cloudflare, nella seconda copia il binario ottenuto nell’immagine finale leggera.
FROM caddy:builder AS builder
RUN xcaddy build --with github.com/caddy-dns/cloudflare
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddyUna volta creato il Dockerfile, sarà necessario andare a creare il docker-compose.yaml che è simile a quello precedente, ma utilizza build: . per costruire l’immagine dal Dockerfile appena creato. In più necessita del token API di Cloudflare, passato tramite variabile d’ambiente che può essere definita in un file .env nella stessa directory.
services:
caddy:
build: .
restart: unless-stopped
container_name: Caddy
ports:
- "80:80"
- "443:443"
- "443:443/udp"
environment:
CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_TOKEN}
volumes:
- ./conf:/etc/caddy
- ./site:/srv
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:Perché Cloudflare?
Cloudflare non è uno sponsor di questa guida. È semplicemente il provider DNS che utilizzo e con cui questa configurazione è stata testata. Lo stesso approccio è applicabile ad altri provider supportati dal progetto caddy-dns .Configurazione del Caddyfile
Il Caddyfile è il file di configurazione di Caddy, all’interno del quale vengono definiti tutti i domini, i sottodomini e i relativi comportamenti del reverse proxy. La sintassi è totalmente dichiarativa e qui sotto riporto alcuni esempi comuni, ma la configurazione completa è disponibile nella documentazione ufficiale .
Configurazione DNS Challenge (opzionale)
Questo blocco è necessario solo se si utilizza la DNS Challenge per ottenere i certificati Let’s Encrypt (come descritto nella sezione di installazione). Va inserito in testa al Caddyfile e contiene le opzioni globali, tra cui l’email per le notifiche di Let’s Encrypt e le credenziali del provider DNS (inserite nel docker-compose).
{
# Email per notifiche Let's Encrypt
email mario.rossi@dominio.xx
# DNS Challenge globale via Cloudflare
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}Configurazione Reverse Proxy
Questo è l’esempio più comune: instradare il traffico da un dominio (o sottodominio) verso un altro servizio, che può trovarsi sulla stessa macchina o in un altro container. Con questa configurazione Caddy otterrà automaticamente un certificato SSL per il dominio specificato e instraderà tutto il traffico verso il servizio in ascolto sulla porta 8080.
servizio.dominio.xx {
reverse_proxy localhost:8080
}Configurazione Reverse Proxy con Cache
Oltre al reverse proxy, è possibile definire le regole di cache specificando quali file il browser deve tenere in memoria (e per quanto tempo) e quali invece devono essere ricaricati ad ogni visita. Nell’esempio qui sotto, i file statici come immagini, CSS e JavaScript vengono mantenuti in cache per una settimana, mentre le pagine HTML vengono sempre richieste al server.
servizio.dominio.xx {
reverse_proxy 80.81.82.83:1234
@static path *.js *.css *.png *.jpg *.jpeg *.gif *.svg *.ico *.woff *.woff2 *.ttf *.eot
header @static Cache-Control "public, max-age=604800, immutable"
@html path *.html /
header @html Cache-Control "no-cache"
}Configurazione di un Redirect
In alcuni casi può essere necessario reindirizzare un dominio verso un altro, ad esempio per ridirigere la versione con www verso quella senza, oppure per spostare il traffico da un vecchio dominio a uno nuovo. In questo esempio, tutte le richieste verso www.dominio.xx vengono reindirizzate con un redirect permanente (HTTP 301) verso dominio.xx, mantenendo il percorso originale grazie a {uri}.
www.dominio.xx {
redir https://dominio.xx{uri} permanent
}Configurazione di Load Balancing
Caddy supporta nativamente il load balancing semplicemente specificando più destinazioni nella direttiva reverse_proxy. Il traffico verrà distribuito automaticamente tra i vari backend in modalità round-robin.
servizio.dominio.xx {
reverse_proxy 10.0.0.1:8080 10.0.0.2:8080 10.0.0.3:8080
}Volendo è possibile specificare una politica di distribuzione diversa, come ad esempio least_conn che seleziona il backend con il minor numero di connessioni attive, oppure random.
servizio.dominio.xx {
reverse_proxy 10.0.0.1:8080 10.0.0.2:8080 10.0.0.3:8080 {
lb_policy least_conn
}
}Primo Accesso ed Aggiornamento
Una volta completata l’installazione e avviato il container, Caddy inizierà immediatamente a servire i siti seguendo quanto dichiarato nel Caddyfile. Se i domini puntano correttamente al server, Caddy provvederà automaticamente ad ottenere e gestire i certificati HTTPS tramite Let’s Encrypt. Per verificare che tutto funzioni correttamente è possibile controllare i log con docker logs Caddy, dove si dovrebbe vedere il messaggio di ottenimento del certificato SSL.
Quando si modifica il Caddyfile, le modifiche non vengono applicate automaticamente al salvataggio del file. Per attivarle è necessario eseguire un reload esplicito all’interno del container:
docker exec Caddy caddy reload --config /etc/caddy/CaddyfileQuesto approccio è un punto di forza di Caddy: il reload avviene in modo “graceful”, ovvero la nuova configurazione viene caricata senza interrompere le connessioni attive, garantendo virtualmente zero downtime. In questo modo è possibile aggiornare le regole di reverse proxy, aggiungere nuovi domini o modificare i comportamenti della cache con la certezza che il servizio non subirà interruzioni.
Troubleshooting & Consigli
Di seguito alcuni consigli utili per risolvere i problemi di configurazione più comuni:
- Se Caddy non riesce ad ottenere i certificati SSL, verificare che le porte 80 e 443 siano raggiungibili dall’esterno e che il dominio punti correttamente all’indirizzo IP del server. Controllare i log con
docker logs Caddyper dettagli. - Se il reverse proxy non funziona, assicurarsi che il servizio di destinazione sia raggiungibile dal container Caddy. Se il servizio è in un altro container Docker, utilizzare il nome del container o una rete Docker condivisa al posto di
localhost. - Per utilizzare Caddy come reverse proxy verso altri container Docker, è consigliato creare una rete Docker dedicata e collegarvi sia Caddy che i servizi da esporre, in modo che possano comunicare tramite il nome del container.