Parce qu'il y a toujours une solution...

Traefik est reverse-proxy et load-balancer HTTP et TCP open-source. La gestion des certificats SSL est aussi de la partie et est "auto-gérée".

An open-source reverse proxy and load balancer for HTTP and TCP-based  applications that is easy, dynamic, automatic, fast, full-featured,  production proven, provides metrics, and integrates with every major  cluster technology...

Quelques éléments de compréhension

Traefik utilise un fichier de configuration au format ".toml". De nombreuses options sont disponibles et bien documentées sur le site officiel à cette adresse.
De base, Traefik n'est pas capable de rediriger/proxifier le flux automatiquement, tout se passe dans le fichier docker-compose en y ajoutant des "labels".

Traefik fonctionne soit en mode "configuration statique" ou "configuration dynamique". Le premier mode est le plus simple à mettre en place : quelques lignes de conf' dans le fichier .toml et ensuite copier/coller les labels sur tous vos services du fichier docker-compose. L'inconvénient, c'est la lourdeur d'affichage dans le docker-compose.
Le mode de configuration dynamique est plus propre mais plus compliqué à mettre en œuvre. Plutôt que d'utiliser des dizaines de lignes de labels dans chaque service, vous utiliserez quelques labels avec des redirections vers le(s) fichier(s) de configuration de Traefik.


Docker-compose pour Traefik 2

L'idée ici est d'avoir un conteneur Traefik ingurgitant les requêtes et les rediriger en fonction de la demande. La configuration reste simple - pour le moment, je ne suis pas allé dans les retranchements de l'application. Une partie "configuration avancée" sera saisie une fois Traefik bien pris en main. Cet documentation est considérée comme "configuration statique".

Étapes préliminaires

  • Créer les dossiers où seront stocker le conteneur traefik et ses fichiers. Pour l'exemple, j'utiliserai /srv/docker/traefik pour le fichier docker-compose et /srv/docker/traefik/conf pour les autres fichiers.
  • Créer les fichiers et y attribuer les droits nécessaires.
sudo mkdir -p /srv/docker/traefik/conf
sudo touch /srv/docker/traefik/conf/acme.json
sudo touch /srv/docker/traefik/conf/traefik.toml
sudo chmod 0600 /srv/docker/traefik/conf/acme.json

Ci-dessous une configuration pour Traefik 2, avec son fichier de configuration "traefik.toml" et son fichier "acme.json" pour les certificats Let's Encrypt - J'ai préalablement créé un nouveau réseau docker intitulé "oueb", que vous pouvez créer via la commande "docker network create oueb".

version: '3.7'
services:
  traefik:
    image: traefik:latest
    restart: always
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./conf/traefik/traefik.toml:/traefik.toml
      - ./conf/traefik/acme.json:/acme.json
    networks:
      - oueb
      
networks:
  oueb:
    driver: bridge
(traefik) docker-compose.yml

Le fichier traefik.toml évite une redondance dans la saisie des labels pour vos services. Le fichier permet aussi d'affiner la configuration.

Actuellement, je vous propose un fichier relativement simple, permettant 2 points d'entrées (80 & 443), des logs, accéder au réseau où se trouve vos autres conteneurs et l'accès au tableau de bord Traefik :

[global]
  sendAnonymousUsage = false

[log]
  level = "INFO"
  format = "common"

[providers]
  [providers.docker]
    endpoint = "unix:///var/run/docker.sock"
    watch = true
    exposedByDefault = true
    swarmMode = false

[api]
  dashboard = true
  debug = false
  insecure = true

[entryPoints]
  [entryPoints.insecure]
    address = ":80"
  [entryPoints.secure]
    address = ":443"
Contenu du fichier traefik.toml

A partir de cet instant, traefik est exploitable et peut être lancé via un "docker-compose up -d".


Utiliser Let's Encrypt pour vos conteneurs

Traefik est capable de gérer automatiquement les certificats SSL nécessaires pour le HTTPS sur/vers vos conteneurs. Une documentation est disponible sur le site officiel de Traefik ici.

Pour la documentation, je vais configurer Let's Encrypt pour qu'il puisse me fournir des certificats SSL "propres".

[certificatesResolvers.letsencrypt.acme]
  email = "contact@computerz.solutions"
  storage = "acme.json"
  caServer = "https://acme-v02.api.letsencrypt.org/directory"
  keyType = "EC256"
  [certificatesResolvers.letsencrypt.acme.httpChallenge]
    entryPoint = "http"
  [certificatesResolvers.letsencrypt.acme.tlsChallenge]

[tls]
  [tls.options]
    [tls.options.default]
      minVersion = "VersionTLS12"
      sniStrict = true
      cipherSuites = [
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
        "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
        "TLS_AES_128_GCM_SHA256",
        "TLS_AES_256_GCM_SHA384",
        "TLS_CHACHA20_POLY1305_SHA256",
        "TLS_FALLBACK_SCSV"
    ]
contenu du fichier traefik.toml

Cette configuration est relativement simple mais fonctionnelle ; vous devez ajouter ces blocs de code dans votre fichier traefik.toml, à la suite de vos autres configurations. N'oubliez pas de redémarrer votre conteneur Traefik pour prendre en comptes les dernières modifications.

Maintenant que Traefik est en place, faites un "docker-compose up -d" pour lancer le conteneur. Dans le fichier de configuration .toml, une rubrique "[api]" a été saisie : vous pourrez accéder au tableau de bord via l’URL "http://ip-or-dns:8080". Cette configuration n'est pas optimale ni sécurisée (pas de mot de passe pour accéder à l'interface, mais il n'y a pas de possibilité de configurer quoi que ce soit via l'interface web).

Bienvenue sur votre Traefik ! Ne reste plus maintenant qu'à configurer vos services pour être accessibles, avoir une configuration fine du HTTPS, puis explorer les possibilités TCP... !


Passer un service derrière Traefik sans HTTPS

C'est mignon d'avoir votre Traefik mais maintenant il faut configurer les services qui seront "derrières". Pour chaque service que vous souhaitez "reversé", saisissez ces labels :

    labels:
      - traefik.enable=true
      - traefik.http.routers.NOM-SERVICE.rule=Host(`NOM-SERVICE.NDD`)
      - traefik.http.routers.NOM-SERVICE.entryPoints=http
      - traefik.http.services.NOM-SERVICE.loadbalancer.server.port=80
     

Il s'agit là du strict minimum pour faire fonctionner un service derrière Traefik. Remplacez donc "NOM-SERVICE" par ce que vous souhaitez et "NOM-SERVICE.NDD" aussi. D'autres labels sont disponibles mais pas nécessaires pour l'instant.


Passer un service derrière Traefik avec HTTPS

Là c'est plus lourd. Plusieurs méthodes sont disponibles - ce que je vous partage en dessous fonctionne avec toute la doc' entièrement saisie ici.

    labels:
      - traefik.http.routers.NOM-SERVICE-http.entrypoints=http
      - traefik.http.routers.NOM-SERVICE-http.rule=Host(`NOM-SERVICE.NDD`)
      - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
      - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
      - traefik.http.routers.NOM-SERVICE-http.middlewares=https-redirect@docker
      - traefik.http.routers.NOM-SERVICE-https.entrypoints=https
      - traefik.http.routers.NOM-SERVICE-https.rule=Host(`NOM-SERVICE.NDD`)
      - traefik.http.routers.NOM-SERVICE-https.tls=true
      - traefik.http.routers.NOM-SERVICE-https.tls.certresolver=letsencrypt
      - traefik.http.middlewares.SslHeader.headers.FrameDeny=true
      - traefik.http.middlewares.SslHeader.headers.SslRedirect=true
      - traefik.http.middlewares.SslHeader.headers.AccessControlAllowMethods=GET,OPTIONS,PUT
      - traefik.http.middlewares.SslHeader.headers.AccessControlAllowOrigin=origin-list-or-null
      - traefik.http.middlewares.SslHeader.headers.AccessControlMaxAge=100
      - traefik.http.middlewares.SslHeader.headers.AddVaryHeader=true
      - traefik.http.middlewares.SslHeader.headers.BrowserXssFilter=true
      - traefik.http.middlewares.SslHeader.headers.ContentTypeNosniff=true
      - traefik.http.middlewares.SslHeader.headers.ForceSTSHeader=true
      - traefik.http.middlewares.SslHeader.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.SslHeader.headers.STSPreload=true
      - traefik.http.middlewares.SslHeader.headers.ContentSecurityPolicy=default-src 'self' 'unsafe-inline'
      - traefik.http.middlewares.SslHeader.headers.CustomFrameOptionsValue=SAMEORIGIN
      - traefik.http.middlewares.SslHeader.headers.ReferrerPolicy=same-origin
      - traefik.http.middlewares.SslHeader.headers.FeaturePolicy="vibrate 'self'"
      - traefik.http.middlewares.SslHeader.headers.STSSeconds=315360000
      - traefik.http.services.NOM-SERVICE.loadbalancer.server.port=80
      - traefik.http.services.NOM-SERVICE.loadbalancer.server.scheme=http

Dans l'ordre :

  1. Les premiers labels "routers" correspondent à la mise en place de Traefik pour du HTTP, basique.
  2. On crée le middleware (l'opération) pour transformer/rediriger le HTTP automatiquement vers le HTTPS.
  3. Mise en place des labels "routers" pour le HTTPS (sensiblement la même chose que du HTTP)
  4. Ajout des middleware pour avoir une configuration HTTPS aux petits oignons
  5. Enfin, on ajoute le port / sur lequel Traefik doit fournir le service

Enjoy !