Nouvelle config Traefik
Déjà 10 mois que mon infra Docker / Traefik ronronne tranquillement…il est temps de tout casser !
Photo by Denys Nevozhai on Unsplash
J’ai commencé mon infra auto-hébergée en août dernier pour me faire un peu la main sur Docker et Traefik. Depuis beaucoup d’eau a coulé sous les ponts (oui je suis normand…) et il est temps de revoir un peu la configuration.
Pourquoi changer un truc qui marche ?
- simplifier la configuration: avec une configuration globale incluse dans le docker-compose.yml au lieu du traditionnel “traefik.toml”
- ajouter un peu de sécurité: avec des passwords gérés par des Docker secrets
- gérer les redirections HTTPS au niveau global au lieu de par service
- passer la config du dashboard Traefik dans le docker-compose.yml
Configuration
Je pars du principe que vous avez un serveur clean avec Docker, docker-compose installés (sinon voir la doc officielle) et une petite idée de comment ça marche…
Arborescence
Comme dans la précédente config, l’ensemble de la configuration des conteneurs est stocké dans /opt
1/opt
2├── traefik
3│ ├── config
4│ │ ├── acme.json
5│ │ ├── dynamic-conf
6│ │ │ ├── tls.toml
7│ └── docker-compose.yml
J’ai conservé le fonctionnement dynamique de Traefik avec le dossier dynamic-conf
pour prendre en charge des modifications sans avoir à relancer le conteneur.
Voici les commandes pour créer l’arborescence, le fichier docker-compose.yml
et le fichier acme.json
qui va contenir les certificats TLS et les clés privées obtenus grâce à Let’s Encrypt:
1sudo mkdir -p /opt/traefik/config/dynamic-conf
2sudo touch /opt/traefik/config/acme.json /opt/traefik/docker-compose.yml
3sudo chmod 600 /opt/traefik/config/acme.json
Docker-Compose
J’utilise un bridge Docker dédié pour l’interconnexion entre les conteneurs et Traefik.
1 sudo docker network create --driver=bridge --subnet=172.19.0.0/24 traefik_lan
Sans cette astuce et si vous laissez docker-compose créer le reseau pour vous, vous ne pourrez pas stopper le conteneur traefik sans couper tous les autres conteneurs qui utiliseraient ce même réseau.
Il ne reste plus qu’à éditer le fichier docker-compose.yml
et modifier les lignes:
email@exemple.tld
: mettre votre adresse emailtraefik.exemple.tld
: indiquer l’url choisie pour l’accès au dashboard Traefikadmin:$$xxxxxxxxx$$xxxxxxx/
: basic auth pour protéger l’accès au dashboard
Pour générer le hash du password, vous pouvez utiliser la commande suivante pour doubler tous les caractères $
:
1echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
Le contenu du fichier /opt/traefik/docker-compose.yml
:
1version: '3'
2services:
3 traefik:
4 image: traefik:v2.4.8
5 container_name: traefik
6 restart: unless-stopped
7 command:
8 - "--providers.docker=true"
9 - "--providers.docker.exposedbydefault=false"
10 - "--providers.file.directory=/etc/traefik/dynamic-conf"
11 - "--providers.file.watch=true"
12 - "--api.dashboard=true"
13 - "--entrypoints.web.address=:80"
14 - "--entrypoints.websecure.address=:443"
15 - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
16 - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
17 - "--certificatesResolvers.letsencrypt.acme.email=email@exemple.tld"
18 - "--certificatesResolvers.letsencrypt.acme.storage=acme.json"
19 - "--certificatesResolvers.letsencrypt.acme.tlsChallenge=true"
20 labels:
21 - "traefik.enable=true"
22 - "traefik.http.routers.dashboard.rule=Host(`traefik.exemple.tld`)"
23 - "traefik.http.routers.dashboard.service=api@internal"
24 - "traefik.http.routers.dashboard.entrypoints=websecure"
25 - "traefik.http.routers.dashboard.middlewares=auth-dashboard"
26 - "traefik.http.middlewares.auth-dashboard.basicauth.users=admin:$$xxxxxxxxx$$xxxxxxx/"
27 - "traefik.http.routers.dashboard.tls=true"
28 - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
29 networks:
30 - traefik_lan
31 ports:
32 - 80:80
33 - 443:443
34 volumes:
35 - /var/run/docker.sock:/var/run/docker.sock:ro
36 - $PWD/config/acme.json:/acme.json
37 - $PWD/config:/etc/traefik:ro
38networks:
39 traefik_lan:
40 external: true
On peut maintenant lancer le conteneur Traefik:
1docker-compose -f /opt/traefik/docker-compose.yml up -d
et vérifier que tout fonctionne correctement: https://traefik.exemple.tld
Utiliser Traefik
Pour exposer un service frontalisé en HTTPS par Traefik, il suffit de déclarer quelques labels. Voici un exemple avec un simple serveur NGINX:
1version: '3'
2services:
3 app:
4 container_name: mysite
5 image: nginx:latest
6 restart: unless-stopped
7 networks:
8 - traefik_lan
9 volumes:
10 - app:/usr/share/nginx/html:ro
11 expose:
12 - "80"
13 environment:
14 - NGINX_HOST=mysite.exemple.tld
15 - NGINX_PORT=80
16 labels:
17 - "traefik.enable=true"
18 - "traefik.http.routers.blog.rule=Host(`mysite.exemple.tld`)"
19 - "traefik.http.routers.blog.entrypoints=websecure"
20 - "traefik.http.routers.blog.tls=true"
21 - "traefik.http.routers.blog.tls.certresolver=letsencrypt"
22networks:
23 traefik_lan:
24 external: true
25volumes:
26 app:
Améliorer la configuration TLS:
Pour finir cet article sur Traefik, nous allons profiter la fonctionnalité de configuration dynamique pour sécurisé la partie TLS. Pour cela, il suffit d’ajouter un fichier /opt/traefik/config/dynamic-conf/tls.toml
.
Le dossier /opt/traefik/config/dynamic-conf
est en bind mount dans le conteneur Traefik et la directivement providers.file.watch=true"
permet de prendre compte tous les événements dans ce dossier.
1[tls]
2 [tls.options]
3 [tls.options.default]
4 minVersion = "VersionTLS12"
5 sniStrict = true
6 cipherSuites = [
7 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
8 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
9 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
10 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
11 "TLS_AES_256_GCM_SHA384",
12 "TLS_CHACHA20_POLY1305_SHA256"
13 ]
14 curvePreferences = ["CurveP521","CurveP384"]