NoctisNode
← GuideSelf-hosting2026-10-239 min

Caddy come reverse proxy Docker: setup con Compose e HTTPS automatico

Usa Caddy come reverse proxy Docker: un solo stack compose, una rete condivisa, reverse_proxy verso i nomi dei servizi e HTTPS automatico, più quando conviene usare le label di caddy-docker-proxy.

In breve: esegui Caddy in un container dedicato che pubblica le porte 80 e 443, collega lui e i container delle tue app a un'unica rete Docker condivisa e punta `reverse_proxy` al nome di ogni servizio e alla sua porta interna (per esempio `reverse_proxy app:3000`). Caddy risolve il nome tramite il DNS integrato di Docker e ottiene automaticamente un certificato TLS per ogni indirizzo di sito.

Questa guida mostra prima l'approccio con un semplice Caddyfile, poi la variante basata su label caddy-docker-proxy, e spiega quando conviene ciascuna su un singolo VPS. Se esegui Caddy direttamente sull'host invece che in Docker, vedi la guida base al reverse proxy con Caddy.

Come si incastrano i pezzi

Solo il container di Caddy pubblica porte verso l'esterno. Ogni container backend si unisce a una rete bridge definita dall'utente (qui chiamata `web`) ed espone la propria porta solo su quella rete. Il server DNS integrato di Docker, disponibile sulle reti definite dall'utente, permette a Caddy di raggiungere `app:3000` tramite il nome del servizio o del container, così non devi mai scrivere a mano IP dei container che cambiano a ogni ricreazione.

Non pubblicare i backend è più importante di quanto sembri: Docker scrive le proprie regole iptables, quindi una porta pubblicata con `ports:` può essere raggiungibile da internet anche quando ufw dice che è bloccata. Usa `expose:` o nessuna mappatura di porte per tutto ciò che deve stare dietro il proxy.

ComponenteRuoloPubblicato sull'host?
container caddyTerminazione TLS, routing per hostname, redirect da HTTP a HTTPSSì: 80/tcp, 443/tcp, 443/udp
rete webRete bridge condivisa con DNS integrato per i nomi dei serviziNo
container delle appI tuoi servizi (web app, API, dashboard)No, raggiungibili solo tramite Caddy
volume caddy_dataCertificati, chiavi private, account ACMENo, ma deve essere persistente

Passo per passo: Caddyfile semplice con docker compose

  1. 01.Punta al VPS un record A (e un record AAAA se usi IPv6) per ogni hostname prima di avviare Caddy, altrimenti l'emissione dei certificati fallirà.
  2. 02.Crea la rete condivisa una sola volta: `docker network create web`.
  3. 03.Crea `/opt/proxy/compose.yaml` e `/opt/proxy/Caddyfile` come mostrato sotto, poi esegui `docker compose up -d` in `/opt/proxy`.
  4. 04.Collega ogni stack applicativo alla rete esterna `web` e avvialo con `docker compose up -d`.
  5. 05.Segui l'emissione del primo certificato con `docker compose logs -f caddy` in `/opt/proxy`.
  6. 06.Dopo aver modificato il Caddyfile, ricarica senza downtime: `docker compose exec -w /etc/caddy caddy caddy reload`.
# /opt/proxy/compose.yaml
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"   # HTTP/3
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data      # certificates and ACME account keys
      - caddy_config:/config
    networks:
      - web

volumes:
  caddy_data:
  caddy_config:

networks:
  web:
    external: true

Collega un'app e scrivi il Caddyfile

Ogni stack applicativo dichiara la stessa rete esterna. Il nome del servizio diventa l'hostname che Caddy contatta. Il volume `caddy_data` è quello che non devi mai perdere: eliminarlo costringe Caddy a richiedere di nuovo tutti i certificati, il che può farti incappare nei rate limit ACME.

# /opt/app/compose.yaml
services:
  app:
    image: ghcr.io/example/app:latest
    restart: unless-stopped
    expose:
      - "3000"        # reachable on the network, NOT published on the host
    networks:
      - web

networks:
  web:
    external: true

# /opt/proxy/Caddyfile
{
	email [email protected]
}

app.example.com {
	reverse_proxy app:3000
}

grafana.example.com {
	reverse_proxy grafana:3000
}

api.example.com {
	reverse_proxy api-1:8080 api-2:8080 {
		lb_policy round_robin
		health_uri /healthz
		health_interval 10s
	}
}

Backend in Caddy: upstream, load balancing e health check

Nella terminologia di Caddy un backend è un upstream di `reverse_proxy`. Puoi elencare più upstream in una sola direttiva, scegliere una `lb_policy` come `round_robin`, `least_conn` o `ip_hash` e aggiungere health check attivi con `health_uri` così i container guasti escono dalla rotazione. Anche i check passivi (`fail_duration`, `max_fails`) sono utili quando l'app non ha un endpoint di health.

Per impostazione predefinita Caddy imposta `X-Forwarded-For`, `X-Forwarded-Proto` e `X-Forwarded-Host` sulle richieste inoltrate. Configura la tua app perché si fidi del range di rete del proxy, così vede il vero IP del client e genera link `https://`. WebSocket e gRPC funzionano attraverso `reverse_proxy` senza impostazioni aggiuntive; per gRPC in chiaro usa `reverse_proxy h2c://service:50051`.

Label al posto del Caddyfile: caddy-docker-proxy

Chi cerca un «Caddy proxy manager» di solito vuole quello che offre Nginx Proxy Manager: aggiungi un container e ottieni hostname e certificato senza modificare un file centrale. Caddy non ha una GUI ufficiale, ma il progetto della community caddy-docker-proxy (github.com/lucaslorentz/caddy-docker-proxy) genera il Caddyfile dalle label dei container e ricarica Caddy quando i container si avviano o si fermano.

Richiede accesso in lettura al socket Docker, che di fatto equivale a root sull'host. Montalo in sola lettura, tieni aggiornata l'immagine del proxy e preferisci il Caddyfile semplice se gestisci solo pochi servizi.

services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CADDY_INGRESS_NETWORKS=web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - caddy_data:/data
    networks:
      - web

  whoami:
    image: traefik/whoami
    networks:
      - web
    labels:
      caddy: whoami.example.com
      caddy.reverse_proxy: "{{upstreams 80}}"

volumes:
  caddy_data:

networks:
  web:
    external: true

Caddyfile semplice vs caddy-docker-proxy

Caddyfile sempliceLabel caddy-docker-proxy
La configurazione sta inUn solo file versionato in gitLabel sparse tra i file compose
Accesso al socket DockerNon necessarioObbligatorio (delicato per la sicurezza)
Nuovo servizioModifica il Caddyfile, esegui `caddy reload`Aggiungi le label, avvia il container
ImmagineUfficiale `caddy:2`Immagine della community basata su Caddy
DebugLeggi direttamente il fileIspeziona la configurazione generata nei log
Ideale perSetup VPS piccoli e stabiliMolti servizi di breve durata o modificati spesso

Eseguirlo su un VPS

Su un VPS KVM NoctisNode hai root completo e un IPv4 dedicato, quindi pubblicare 80 e 443 da un unico container Caddy e nascondere tutto il resto è semplice. Un Wisp (1 vCPU, 1 GB di RAM) basta per Caddy più un paio di container leggeri; gli stack più pesanti stanno bene su Pulse o Umbra. I dettagli sull'emissione dei certificati e i possibili errori sono trattati in come funziona l'HTTPS automatico di Caddy, mentre l'inoltro TCP grezzo o SSH è in proxy TCP e SSH con Caddy. Proteggi l'SSH dell'host con la guida all'hardening SSH.

FAQ

QCome faccio a usare Caddy come reverse proxy verso un container Docker?

AMetti Caddy e il container sulla stessa rete Docker definita dall'utente e usa `reverse_proxy service-name:port` nel Caddyfile. Non usare `localhost`, perché dentro il container di Caddy si riferisce a Caddy stesso.

QPerché Caddy restituisce 502 Bad Gateway per il mio container?

ADi solito i container non sono su una rete condivisa, la porta è sbagliata (usa la porta interna del container, non una porta pubblicata sull'host) oppure l'app ascolta solo su 127.0.0.1 dentro il suo container. Fai in modo che l'app si metta in ascolto su 0.0.0.0 e controlla `docker network inspect web`.

Qcaddy-docker-proxy è sicuro da usare?

AFunziona bene, ma richiede il socket Docker, che concede un controllo equivalente a root sull'host. Montalo in sola lettura, tieni aggiornata l'immagine ed evita di esporre l'endpoint admin di Caddy.

QDove salva i certificati Caddy in Docker?

AIn `/data` dentro l'immagine ufficiale, quindi monta lì un volume con nome. Perderlo significa riemettere tutti i certificati e potenzialmente raggiungere i rate limit ACME.

QEsiste un Caddy proxy manager con interfaccia web?

ACaddy di per sé non ha un'interfaccia web ufficiale; si configura con un Caddyfile, JSON o la sua API admin. Strumenti basati su label come caddy-docker-proxy offrono un flusso simile: aggiungi un container e sei pronto.

Caddy come reverse proxy Docker: setup con Compose e HTTPS automatico · NoctisNode