Schema architettura Traefik come reverse proxy integrato con Docker

Traefik come Reverse Proxy per Docker: Guida Completa con SSL Automatico

Se gestisci più servizi web su un singolo server, prima o poi ti trovi a dover risolvere il problema del reverse proxy. Dopo aver provato diverse soluzioni, sono passato a Traefik come reverse proxy integrato con Docker e devo dire che è stata una delle migliori decisioni infrastrutturali degli ultimi anni. In questo articolo ti racconto la mia esperienza concreta, partendo dalla configurazione che uso in produzione su questo server.

Cos’è Traefik e perché sceglierlo come reverse proxy per Docker

Traefik è un reverse proxy e load balancer moderno, pensato nativamente per ambienti containerizzati. A differenza di Nginx o Apache configurati manualmente, Traefik si integra direttamente con Docker e aggiorna la sua configurazione automaticamente ogni volta che un container viene avviato o fermato.

I vantaggi principali che mi hanno convinto:

  • Configurazione zero-touch: basta aggiungere label al container Docker, nessun file di configurazione separato da modificare
  • SSL automatico con Let’s Encrypt: i certificati vengono generati e rinnovati senza intervento manuale
  • Dashboard web integrata per monitorare router, servizi e middleware
  • Supporto nativo per Docker, Kubernetes, Consul e altri provider
  • Middleware potenti: redirect, autenticazione basic/OAuth, rate limiting, compressione e molto altro

La mia architettura con Traefik e Docker

Sul mio server gira un’infrastruttura composta da diversi servizi, tutti orchestrati tramite Docker Compose e collegati sulla stessa rete bridge interna dedicata. Traefik è l’unico container che espone porte verso l’esterno e fa da punto di ingresso per tutto il traffico.

I servizi attivi sono:

  • Traefik — il reverse proxy, esposto su porte 80 e 443
  • WordPress (questo blog) — raggiungibile su rogue1.it e www.rogue1.it
  • Vari servizi interni — ciascuno su un proprio sottodominio, non esposto direttamente
  • Database — non esposti all’esterno, accessibili solo dalla rete interna

Nessuno dei container tranne Traefik ha porte mappate sull’host: tutto il traffico passa obbligatoriamente attraverso il reverse proxy. Questo semplifica enormemente la gestione della sicurezza.

Configurazione di Traefik con Docker Compose

Ecco la struttura del docker-compose.yml relativa a Traefik, con i punti più importanti commentati. I domini nei code block sono sostituiti con example.com a titolo esemplificativo.

Entrypoint: le porte di ingresso

Gli entrypoint definiscono su quali porte Traefik resta in ascolto. Una configurazione tipica prevede almeno HTTP e HTTPS:

command:
  - "--entrypoints.web.address=:80"
  - "--entrypoints.websecure.address=:443"

Traefik supporta anche entrypoint TCP generici, utili per gestire altri protocolli (posta, federation, ecc.) mantenendo un unico punto di ingresso per tutto il traffico del server.

Provider Docker: la magia dell’auto-discovery

Il parametro --providers.docker=true abilita il provider Docker: Traefik si connette al socket Docker in sola lettura e monitora in tempo reale i container attivi. Quando un container viene avviato con label traefik.enable=true, Traefik lo registra automaticamente come servizio.

volumes:
  - /var/run/docker.sock:/var/run/docker.sock:ro

Il mount del socket in modalità read-only (:ro) è una buona pratica di sicurezza: Traefik legge lo stato dei container ma non può modificarli.

SSL automatico con Let’s Encrypt

Questa è probabilmente la feature più apprezzata di Traefik: il rinnovo automatico dei certificati SSL tramite Let’s Encrypt. La configurazione è minima:

- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=tua@email.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"

Uso la HTTP challenge (http-01): Let’s Encrypt verifica la proprietà del dominio facendo una richiesta HTTP sulla porta 80. I certificati vengono salvati nel file acme.json su un volume persistente e rinnovati automaticamente prima della scadenza.

Routing con le Label Docker

Il cuore della configurazione di ogni servizio sta nelle label Docker. Invece di un file di configurazione centralizzato, ogni container dichiara le proprie regole di routing. Ecco un esempio completo:

labels:
  - "traefik.enable=true"
  # Router HTTP: redirect a HTTPS
  - "traefik.http.routers.myapp-http.rule=Host(`example.com`) || Host(`www.example.com`)"
  - "traefik.http.routers.myapp-http.entrypoints=web"
  - "traefik.http.routers.myapp-http.middlewares=myapp-https-redirect"
  - "traefik.http.middlewares.myapp-https-redirect.redirectscheme.scheme=https"
  - "traefik.http.middlewares.myapp-https-redirect.redirectscheme.permanent=true"
  # Router HTTPS: traffico reale
  - "traefik.http.routers.myapp.rule=Host(`example.com`) || Host(`www.example.com`)"
  - "traefik.http.routers.myapp.entrypoints=websecure"
  - "traefik.http.routers.myapp.tls=true"
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  - "traefik.http.services.myapp.loadbalancer.server.port=80"

Il pattern HTTP → HTTPS redirect

Un pattern che ripeto per tutti i servizi è il doppio router: uno per HTTP (porta 80) che redirige permanentemente a HTTPS, e uno per HTTPS (porta 443) che gestisce il traffico reale con TLS. Il middleware redirectscheme gestisce il redirect 301, che è corretto anche per la SEO.

La Dashboard di Traefik

Traefik include una dashboard web molto utile per il monitoraggio. La best practice è esporla su un sottodominio dedicato accessibile solo via HTTPS, con autenticazione basic obbligatoria:

- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=YOURUSER:BCRYPT_HASH"

Il servizio speciale api@internal è quello della dashboard stessa. Il middleware basicauth protegge l’accesso con password hashata con bcrypt — mai in chiaro. L’hash bcrypt si genera con il comando htpasswd -nB nomeutente. Importante: nel docker-compose i simboli $ vanno raddoppiati in $$ come escape.

Dalla dashboard puoi vedere in tempo reale tutti i router attivi, i servizi, i middleware applicati e lo stato dei certificati TLS. È uno strumento indispensabile per il debug, ma tienila sempre protetta: espone l’intera mappa dell’infrastruttura.

Aggiungere un nuovo servizio: esempio pratico

Per dimostrare quanto sia semplice aggiungere un nuovo servizio, ecco la configurazione generica per un’applicazione su sottodominio dedicato:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.myservice-http.rule=Host(`myservice.example.com`)"
  - "traefik.http.routers.myservice-http.entrypoints=web"
  - "traefik.http.routers.myservice-http.middlewares=myservice-https-redirect"
  - "traefik.http.middlewares.myservice-https-redirect.redirectscheme.scheme=https"
  - "traefik.http.middlewares.myservice-https-redirect.redirectscheme.permanent=true"
  - "traefik.http.routers.myservice.rule=Host(`myservice.example.com`)"
  - "traefik.http.routers.myservice.entrypoints=websecure"
  - "traefik.http.routers.myservice.tls=true"
  - "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
  - "traefik.http.services.myservice.loadbalancer.server.port=8080"

Basta sostituire myservice con il nome del tuo servizio, aggiornare il sottodominio e indicare la porta interna su cui il container è in ascolto. Nessuna porta esposta sull’host, nessuna modifica a file di configurazione centralizzati: Traefik legge le label e configura il routing da solo in pochi secondi.

Considerazioni sulla sicurezza

Alcune pratiche di sicurezza che applico nella mia configurazione:

  • Socket Docker in read-only: /var/run/docker.sock:/var/run/docker.sock:ro — Traefik legge ma non scrive
  • Dashboard protetta da basic auth con password hashata bcrypt, mai in chiaro
  • API dashboard non insecure: --api.insecure=false, esposta solo tramite router autenticato su HTTPS
  • Nessuna porta dei servizi esposta sull’host: solo Traefik ha porte mappate, gli altri container comunicano solo sulla rete interna
  • HTTPS forzato su tutti i servizi con redirect permanente 301
  • Sottodominio dashboard su URL non ovvio: evita nomi prevedibili come admin. o traefik. per ridurre la superficie di attacco da bot

Pro e contro dopo mesi di utilizzo in produzione

Dopo diversi mesi di utilizzo quotidiano, ecco il mio bilancio onesto:

Pro

  • Aggiungere un nuovo servizio richiede solo label nel docker-compose, nessuna altra configurazione
  • I certificati SSL non sono mai scaduti, il rinnovo è completamente automatico
  • La dashboard rende immediatamente visibile lo stato di tutta l’infrastruttura
  • Il log di Traefik è molto dettagliato e facilita il debug
  • Community attiva e documentazione eccellente

Contro

  • La sintassi delle label può diventare verbosa per configurazioni complesse
  • Il debug dei middleware richiede un po’ di pratica iniziale
  • L’escape dei $ nelle label docker-compose (che diventano $$) è una fonte comune di errori
  • Per configurazioni molto personalizzate è necessario usare file di configurazione statici aggiuntivi

Conclusioni

Usare Traefik come reverse proxy integrato con Docker ha semplificato enormemente la gestione della mia infrastruttura. L’approccio configuration-as-code tramite label Docker, la gestione automatica di SSL e la dashboard di monitoraggio lo rendono la scelta ideale per chi gestisce più servizi containerizzati su un singolo server.

Se stai ancora usando Nginx o Apache con configurazioni manuali in un ambiente Docker, ti consiglio di valutare la migrazione a Traefik: il tempo investito nell’apprendimento iniziale viene ripagato in fretta dalla semplicità di gestione a regime.

Hai domande sulla configurazione o vuoi condividere la tua esperienza con Traefik? Scrivimi nei commenti!