- Traefik funge da proxy inverso dinamico e risolve i certificati TLS, mentre Portainer offre un'interfaccia grafica per la gestione di Docker e Swarm.
- La combinazione di traefik.yml, dynamic.yml e docker-compose.yml consente di definire punti di ingresso, middleware di sicurezza e routing HTTP/HTTPS basato su etichette.
- Negli scenari Docker standalone o Swarm, è sufficiente unire i servizi alla rete proxy e contrassegnarli in modo che Traefik possa scoprirli ed esporli in modo sicuro.
- L'uso di Let's Encrypt, reti dedicate e autenticazione di base sulla dashboard consolida un ambiente robusto per la distribuzione di più applicazioni su un singolo server.
Configurare uno stack moderno con Docker, Traefik e Portainer è attualmente uno dei modi più semplici per gestire i container su un singolo server ed esporre più servizi tramite HTTPS senza impantanarsi nella configurazione. Il vantaggio principale è che Traefik funge da proxy inverso dinamico, mentre Portainer offre un'interfaccia web molto semplice per la gestione di Docker e, volendo, anche di Swarm.
In questo articolo vedrai come adattando Traefik come proxy inverso di fronte a Portainer Sia in uno scenario Docker "classico" (autonomo) che in un cluster Docker Swarm, come integrare TLS (autofirmato o Let's Encrypt) e quali file di configurazione entrano in gioco (traefik.yml, dynamic.yml y docker-compose.yml) e alcuni trucchi comuni con middleware, reti e tipici problemi di tagging in Traefik.
Quali ruoli hanno Docker, Traefik e Portainer nell'architettura?
In questo tipo di configurazione, Docker rappresenta il livello base su cui vengono eseguiti i container, Traefik funge da proxy inverso e bilanciatore di carico che riceve tutte le richieste HTTP/HTTPS sulle porte 80 e 443 e le inoltra al container appropriato, e Portainer fornisce un'interfaccia grafica per la gestione di immagini, container, volumi, reti e stack Docker o Swarm.
L'idea è di avere un singolo host con Docker dove Traefik si trova alla “porta”: ascoltare ai punti di ingresso web (80) y websecure (443), risolve i certificati TLS (solitamente con Let's Encrypt) e, grazie all'integrazione con il provider Docker, rileva automaticamente i servizi esposti aggiungendo etichette ai contenitori.
D'altra parte, Portainer funziona come un altro contenitore, ma esposto attraverso un sottodominio specifico, ad esempio portainer.tudominio.com, protetto da TLS e, se desiderato, dietro un middleware di autenticazione aggiuntivo oltre al login di Portainer. Tutto questo è orchestrato con un finestra mobile-composizione che definisce Traefik, Portainer e la rete comune di tipo proxy.
Un chiaro vantaggio di questo approccio è la possibilità di implementare nuovi servizi semplicemente aggiungendo etichette ai container: Traefik rileva la modifica in Docker, crea router, servizi e middleware al volo e in pochi secondi si ottiene un nuovo sottodominio o una nuova rotta operativa senza dover modificare manualmente i file di configurazione statici.
Configurazione statica di Traefik: traefik.yml
La configurazione statica di Traefik è solitamente memorizzata in un file come traefik.ymlche è montato all'interno del contenitore. Qui è definito dashboard, punti di ingresso, provider e risolutore di certificati Tra le altre cose, Let's Encrypt.
Una tipica configurazione YAML inizia attivando l'API e il pannello di controllo con qualcosa come api: dashboard: trueCiò consente l'accesso all'interfaccia web in cui è possibile visualizzare router, servizi e middleware. Questo pannello non è autenticato di default, quindi vedremo più avanti come proteggerlo con l'autenticazione di base dalla configurazione dinamica.
Successivamente, vengono definiti i punti di ingresso. Normalmente, ci sono un punto di ingresso web al porto 80 e altri websecure in 443. Nel web Un reindirizzamento automatico è solitamente configurato per websecurein modo che qualsiasi accesso HTTP venga reindirizzato a HTTPS:
Uno schema tipico includerebbe una sezione http.redirections.entryPoint.to: websecure per forzare tale reindirizzamento e centralizzare tutto il traffico crittografato nel punto di ingresso sicuro.
a websecure Viene indicato che si deve utilizzare TLS e viene fornito un collegamento. Risolutore di certificati (per esempio letsencrypt) che si occuperà della gestione automatica dei certificati. Tutto ciò è supportato da ACME, che è il protocollo utilizzato da Let's Encrypt per emettere e rinnovare i certificati.
Nel blocco fornitori Il provider Docker è configurato, puntando al socket unix:///var/run/docker.sockcon un'opzione chiave: exposedByDefault: falseCon questo, Traefik non pubblica tutti i contenitori per impostazione predefinita, ma solo quelli che riportano l'etichetta traefik.enable=trueÈ anche possibile configurare un provider di file (file) per caricare una configurazione dinamica aggiuntiva, ad esempio, da /configurations/dynamic.yml.
Infine, il file statico di solito include la sezione certificatesResolversdove è definito il risolutore ACME: email di registrazione, file di archiviazione (solitamente acme.json), tipo di chiave (ad esempio EC384) e il metodo di convalida (ad esempio httpChallenge sul punto di ingresso webÈ importante che impostare una vera e-mail in questa sezione perché Let's Encrypt lo usa per notifiche e rinnovi; se si lascia un valore fittizio o non valido, potrebbero verificarsi errori all'avvio del contenitore Traefik.
Oltre a questa configurazione YAML, ci sono distribuzioni che utilizzano Formato TOML (traefik.toml)Ma la logica è la stessa: sezionano i certificati del resolver (ad esempio [certificatesResolvers.main.acme]), definire le sfide (come dnsChallenge con provider = "route53") e aggiungere opzioni TLS predefinite, come vigore minVersion = "VersionTLS13" o configurare un elenco di cipherSuites permesso.
Configurazione dinamica: middleware, TLS e sicurezza
La parte dinamica di Traefik di solito va in un file come dynamic.yml, caricato dal fornitore del file. Qui si definisce middleware e opzioni TLS che può essere modificato senza riavviare il contenitore Traefik, il che è molto utile per regolare la sicurezza al volo.
Un caso tipico è la creazione di un middleware di intestazione, ad esempio secureHeadersche aggiunge policy relative a HSTS e all'uso obbligatorio di HTTPS. In YAML potresti trovare parametri come sslRedirect: true, forceSTSHeader: true, stsIncludeSubdomains: true, stsPreload: true e stsSeconds elevato (ad esempio, un anno in secondi). Ciò rafforza la sicurezza del traffico dal lato browser.
Un altro middleware comune è quello per l'autenticazione di base, ad esempio user-auth tipo basicAuth, dove un elenco di utenti è dichiarato nel formato usuario:hashL'hash viene solitamente generato con htpasswd ed è incorporato nel file. Questo middleware è solitamente associato al router della dashboard Traefik, quindi, oltre all'accesso HTTPS, richiede un nome utente e una password.
All'interno della stessa configurazione dinamica, è comune vedere un blocco tls.options con un profilo predefinito (default) dove vengono impostati i cifrari supportati e la versione minima TLS, ad esempio VersionTLS12In alcune distribuzioni vengono definite diverse opzioni (ad esempio, un profilo denominato tls12 e altri default) per adattare il livello di sicurezza ai diversi servizi, se necessario.
In ambienti in cui si desidera utilizzare TLS anche internamente Tra Traefik e i servizi backend (come Portainer), può sorgere un problema quando questi servizi non dispongono di un certificato riconosciuto da una CA pubblica. È qui che entra in gioco l'opzione. insecureSkipVerify, che, configurato sotto providers.http.tls oppure, nelle opzioni TLS appropriate, consente a Traefik di bypassare la convalida dei certificati back-end. Questa funzionalità è utile per gli ambienti di laboratorio o per i certificati autofirmati interni, ma deve essere utilizzata con cautela perché attenua la verifica.
Un dettaglio pratico: il file dynamic.yml Può essere modificato al volo.Traefik ricarica la configurazione dinamica senza richiedere un riavvio, così puoi aggiungere o rimuovere middleware, modificare le intestazioni di sicurezza o modificare l'autenticazione di base senza compromettere la disponibilità del proxy.
docker-compose con Traefik e Portainer in Docker standalone
In uno scenario Docker nudo, senza Swarm, la cosa più comune da fare è lanciare Traefik e Portainer con un singolo docker-compose.yml che definisce sia i servizi che una rete condivisa di tipo bridge chiamata, ad esempio, proxy.
Il servizio Traefik Di solito utilizza l'immagine ufficiale, ad esempio traefik:latest o una versione specifica come traefik:v3.4Le porte sono mappate. 80 e 443 per il traffico web e, in alcuni esempi, la porta 8080 per esporre internamente il pannello di controllo. Inoltre, l'opzione è aggiunta restart: unless-stopped e la sicurezza è rafforzata con security_opt: - no-new-privileges:true per ridurre il rischio di escalation dei privilegi all'interno del contenitore.
Per quanto riguarda i volumi, Traefik deve montare il socket Docker di sola lettura (/var/run/docker.sock:/var/run/docker.sock:ro) per scoprire i contenitori, il file statico traefik.yml e la directory in cui verrà salvata la configurazione dinamica (./traefik-data/configurations:/configurationsAnche il file è montato. acme.jsonQui Traefik archivia i certificati emessi da Let's Encrypt. Questo file viene creato sull'host e gli vengono assegnate le autorizzazioni. 600 in modo che solo l'utente appropriato possa leggerlo e scriverlo; se lo si lascia con 644, Traefik di solito si lamenta.
La chiave per far sì che Traefik faccia la sua magia è la etichette di servizioTra le altre cose, troverete: traefik.enable=true (in modo che il provider Docker esponga questo servizio), traefik.docker.network=proxy (indica quale rete Traefik dovrebbe usare per comunicare con il contenitore) e un router come traefik.http.routers.traefik-secure, con etichette che definiscono il suo punto di ingresso (websecure), la regola host (ad esempio Host(`traefik.tudominio.com`)), il servizio associato (api@internal) e il middleware di autenticazione (user-auth@file).
Servizio vettore nello stesso docker-compose.yml generalmente usa portainer/portainer-ce:latest (o l'edizione Enterprise se si dispone di una licenza). Vengono montati volumi simili: il socket Docker, la cartella dati (./portainer-data:/data) e spesso anche il /etc/localtime in modo che erediti il fuso orario dell'host.
Le etichette di Portainer lo registrano presso Traefik: traefik.enable=true, traefik.docker.network=proxyun router del tipo traefik.http.routers.portainer-secure con punto di ingresso websecure e una regola host come Host(`portainer.tudominio.com`)Inoltre, viene definito il servizio che Traefik dovrebbe utilizzare, puntando alla porta interna di Portainer, ad esempio con traefik.http.services.portainer.loadbalancer.server.port=9000.
Con tutto questo in corso, dopo il lancio docker compose up -d Nella directory stack, Traefik scarica le immagini e crea la rete. proxy Se viene dichiarato come esterno ed espone entrambi i pannelli nei sottodomini configurati, con HTTPS automatico grazie a Let's EncryptDa quel momento in poi, per aggiungere nuovi servizi sarà sufficiente clonare il progetto, aggiungere alcune etichette Traefik e collegarlo alla rete. proxy.
Scenario Docker Swarm: Portainer e Traefik in un cluster
Quando si attiva Docker Swarm, le cose cambiano un po', perché i servizi vengono distribuiti come stack e le reti sono in genere basate su overlay. Tuttavia, la logica sottostante con Traefik e Portainer è molto simile: Traefik continua a fungere da reverse proxy e da rilevatore dinamico di servizi, e Portainer può operare sia in modalità standalone che in modalità Portainer + agent per gestire i nodi remoti all'interno del cluster.
In una tipica distribuzione Swarm, lo stack viene creato prima di essere applicato. due reti sovrapposte che Traefik utilizzerà per instradare il traffico tra i nodi. Inoltre, viene creato un volume per rendere persistenti i dati Portainer (ad esempio) portainer_data) e, se ne hai bisogno, uno per acme.json oppure la directory in cui Traefik memorizza i certificati e la configurazione.
El docker-compose.yml (che poi si dispiega con docker stack deploy utilizzando, ad esempio, -c portainer.yml) definisce solitamente due servizi: Agente portainer, che funziona in modalità global su tutti i nodi Linux e sul servizio Portainer principale (CE o EE), che normalmente rimane in modalità replicata con il vincolo di essere eseguito solo sui gestori.
L'agente Portainer monta il socket Docker e la directory del volume (/var/lib/docker/volumes) per poter ispezionare le risorse. Si connette alla rete overlay che condividerà con Traefik, ad esempio traefik_publicIl servizio Portainer principale può essere configurato per comunicare con l'agente tramite TCP (tcp://tasks.agent:9001) e, infatti, in alcuni esempi quel comando è mostrato con --tlsskipverify commentato, per saltare la verifica TLS se necessario.
Sullo stesso stack o su un altro, Traefik si avvia con il provider Docker in modalità Swarm (swarmMode = true in TOML o l'opzione equivalente in flag), osservando i servizi taggati. La sua configurazione include un certificatesResolvers.main.acme per Let's Encrypt, un dnsChallenge con un fornitore come Route53 Se si desidera convalidare i certificati tramite DNS e un blocco di tls.options dove, ad esempio, è costretto minVersion = "VersionTLS13" per il profilo predefinito e viene definito un elenco esplicito di cipherSuites per un profilo TLS 1.2.
Le etichette Portainer su Swarm seguono la stessa filosofia: traefik.enable=trueun router come traefik.http.routers.portainer con Host(`portainer.midominio.com`), traefik.http.routers.portainer.entrypoints=https (o websecure (secondo la denominazione), e traefik.http.routers.portainer.tls=true per abilitare TLS su quel router. Inoltre, puoi specificare risolutore di certificati con traefik.http.routers.portainer.tls.certresolver=main e lo schema backend se il servizio parla HTTPS internamente con traefik.http.services.portainer.loadbalancer.server.scheme=https.
Nei log di debug di Traefik in Swarm vedrai la configurazione generata: router come api y portainer, servizi scoperti (ad esempio portainer en http://10.0.1.12:9000 e un servizio traefik (che punta alla porta 8080 della dashboard) e, se c'è un problema con etichette mal definite, messaggi come "Impossibile definire il nome del servizio per il router: troppi servizi"che di solito indicano che c'è un conflitto o una duplicazione di servizi associati a un router.
Esempio minimo: whoami, percorsi e TLS con Traefik
Prima di introdurre Portainer, è molto pratico provare Traefik con un backend molto semplice, come quello nell'immagine. traefik/whoamiche restituisce informazioni sulla richiesta. Questo aiuta a verificare che Traefik sia configurato correttamente e che le regole di routing funzionino.
Un docker-compose.yml base può includere il servizio traefik con immagini traefik:v3.4, montando il socket Docker e definendo i flag di avvio come --providers.docker=true, --providers.docker.exposedbydefault=false, --providers.docker.network=proxy e il punto di ingresso --entryPoints.web.address=:80Le porte 80 e 8080 vengono pubblicizzate sull'host e viene creata una rete. proxy che utilizzerà anche il contenitore whoami.
Il servizio whoami Inizia sulla stessa rete ed è contrassegnato con traefik.enable=trueQuindi un router viene definito con l'etichetta traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`) e viene indicato che il tuo punto di ingresso è webSe fai una richiesta con curl -H "Host: whoami.docker.localhost" http://localhost/Vedrai una risposta con nome host, IP, intestazioni e così via, che conferma che Traefik sta eseguendo il routing correttamente.
Da lì in poi è tutto semplice. aggiungere il routing tramite percorsiAd esempio, puoi creare un altro servizio. whoami-api con la stessa immagine, sulla stessa rete, e taggarla con una regola del tipo Host(`whoami.docker.localhost`) && PathPrefix(`/api`)Quindi, la radice / vai a whoami originale e le richieste di /api li servirà whoami-apiPuoi verificarlo effettuando richieste a / già /api con lo stesso host.
Attivare TLS In questo ambiente locale, un'opzione è quella di generare un certificato autofirmato per il dominio *.docker.localhost con opensslCrei una directory certs, tu generi local.key y local.crt, e poi aggiungi un file dinamico (ad esempio dynamic/tls.yml) con la sezione tls: e i percorsi certFile y keyFile che punta a quei file.
Successivamente, aggiorni la definizione del servizio Traefik in docker-compose.yml per montare la cartella ./certs e la cartella ./dynamic all'interno del contenitore, si attiva l'API sicura con --api.dashboard=true, crei il punto di ingresso websecure (--entryPoints.websecure.address=:443) e abilitare TLS lì con --entryPoints.websecure.http.tls=trueSi etichetta anche il router del dashboard e i router di whoami per loro da usare websecure e avere tls=true.
Una volta attivato, potrai accedere https://whoami.docker.localhost/ e al pannello Traefik con un certificato autofirmato, accettando l'avviso di sicurezza del browser. Questa esperienza è molto simile a quella che si otterrà in seguito in produzione con Let's Encrypt, ma senza dover fare affidamento su server DNS pubblici.
Best practice, distribuzione delle app e risoluzione dei problemi tipici
Uno schema che si ripete in tutti questi esempi è che Traefik semplifica notevolmente l'implementazione di nuove applicazioniUna volta che hai il tuo stack di base (Traefik + Portainer + rete) proxy (+ certificati), l'aggiunta di un nuovo servizio si riduce solitamente a:
Clona il progetto o copia il tuo docker-compose.yml al server, punta un sottodominio all'indirizzo IP dell'host utilizzando un registrare A nel tuo DNS (ad esempio app.tudominio.com), quindi aggiungere le etichette chiave al servizio: traefik.enable=true, traefik.docker.network=proxy e un router con una regola host per quel sottodominio, che specifica il punto di ingresso sicuro websecure e il servizio con la porta interna corretta.
Molti tutorial mostrerebbero, ad esempio, la distribuzione di una piccola app API veloce Separato: vengono aggiunte quattro etichette, assicurando che si unisca alla rete proxy nella sezione networks del docker-compose.ymle dopo aver fatto docker compose up -d L'app appare automaticamente sulla dashboard di Traefik con TLS abilitato. Grazie al rilevamento automatico di Traefik, non è nemmeno necessario modificarne le impostazioni statiche.
Per garantire che tutto funzioni senza intoppi, è importante prestare attenzione ad alcuni dettagli: Non riutilizzare lo stesso identificativo del router In varie app, verifica che ci sia un solo servizio associato a ciascun router (evitando l'errore "troppi servizi"), usa nomi di rete coerenti (ad esempio, proxy su tutti gli stack che vuoi esporre) e, se stai usando Let's Encrypt, assicurati che acme.json Ha i permessi 600 e l'email configurata è valida.
Negli ambienti Swarm, verificare anche che la configurazione di Traefik includa il provider Docker. swarmMode=true y watch=truee che i vincoli dei servizi (ad esempio node.role == manager (per Portainer) non siano in conflitto con la posizione in cui è distribuito Traefik. I log di debug sono molto dettagliati, ma sono fondamentali per individuare problemi di routing o TLS.
Combinando Docker, Traefik e Portainer, è possibile configurare un ambiente di orchestrazione completo e leggero su un singolo server, con dashboard grafiche, certificati automatici e un flusso di implementazione estremamente rapido, in cui l'aggiunta, l'aggiornamento o la rimozione dei servizi si riduce alla modifica di poche righe di file YAML, lasciando che Traefik si occupi del reverse proxy e del TLS.
