Reverse proxy - Traefik

undraw_server_status_-5-pbv

Je me suis lancé dans l'idée de monter un serveur avec un ensemble d'application sous docker. L'idée principal est la simplicité d'installation d'une tel application. En effet, pas besoin de réfléchir aux diverses dépendances, les images sont fonctionnelles et installable en quelques minutes sans prise de tête. Bref, en réfléchissant à ma future solution, il fallait que j'imagine un système pour que l'ensemble de c'est applications soient disponible en http et en https le tout sur des ports normaux (80/443). J'ai ainsi hésité avec un simple reverse proxy sous nginx, HAProxy et Traefik. Je vais vous décrire la solution sous traefik qui s'oriente plutôt dans le bon sens avec des containers docker.


Déploiement de traefik sous docker

Dans un premier temps, j'ai regardé un peu comment configurer Traefik. Il est normalement necessaire de monté une configuration dans un fichier traefik.toml. Cependant, à l'aide de docker-compose on peu monter cette configuration aisément dans la partie "commands".

Docker-compose de traefik

version: '3.9'
services:
  traefik:
    image: traefik:v2.5
    container_name: traefik
    restart: unless-stopped
    command:
      # Globals
      - "--global.checkNewVersion=true"
      - "--global.sendAnonymousUsage=true"
      # Http & Https      
      - "--entryPoints.web.address=:80"
      - "--entryPoints.websecure.address=:443"
      # Permits the update by user's services
      - "--api=true"
      # Docker Configuration      
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=false"
      - "--providers.docker.network=proxy"
      - "--providers.docker.swarmMode=false"
      # Certificate Resolver
      - "--certificatesResolvers.lets-encrypt.acme.email=allouche.arnaud@gmail.com"
      - "--certificatesresolvers.lets-encrypt.acme.storage=/etc/traefik/acme.json"
      - "--certificatesresolvers.lets-encrypt.acme.httpchallenge.entrypoint=web"
      - "--serverstransport.insecureskipverify=true"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik:/etc/traefik
    ports:
      - "80:80"
      - "443:443"

networks: 
  default: 
    external: 
      name: proxy

Quelques explications sur les commandes

Command Explication
--global.checkNewVersion=true Autorise la notification d'une nouvelle version
--entryPoints.web.address=:80 Ajoute l'entrypoint nommé web qui aura pour port 80
--entryPoints.websecure.address=:443 Ajoute l'entrypoint nommé websecure qui aura pour port 443
--api=true Permet de déployé container avec des labels qui agiront sur traefik
--providers.docker=true Récupérer les providers de docker
--providers.docker.endpoint Chemin du socket docker
--providers.docker.network Permettra d'ouvrir le reverse proxy vers le réseau docker
--certificatesResolvers.lets-encrypt.acme.email Nécessaire pour la création des certificats
--certificatesresolvers.lets-encrypt.acme.storage Emplacement des certificats
--certificatesresolvers.lets-encrypt.acme.httpchallenge.entrypoint=web La méthode pour générer le certificat dit "challenge"


Déploiement d'une application docker derrière un proxy traefik

Pour expliquer simplement, je vais dans mon exemple utiliser une image qui ne fait qu'une redirection 301. Du coup afin de configurer traefik depuis un docker-compose, il faudra définir un ensemble de paramètre dans la partie "labels".

Docker-compose de mon application

version: '3'

services:
  redirect:
    image: morbz/docker-web-redirect
    restart: always
    environment:
      - VIRTUAL_HOST=graphedron.net
      - REDIRECT_TARGET=domobox.fr
    labels:
      # The labels are usefull for Traefik only
      - "traefik.enable=true"
      # http
      - "traefik.http.routers.httpgraphedron.rule=Host(`www.graphedron.net`) || Host(`graphedron.net`)"
      - "traefik.http.routers.httpgraphedron.entrypoints=web"
      - "traefik.http.routers.httpgraphedron.service=httpgraphedron-service"
      - "traefik.http.services.httpgraphedron-service.loadbalancer.server.port=80"
      # Middlewares
      # Redirect these routes to https
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.routers.httpgraphedron.middlewares=redirect-to-https"
      # https
      - "traefik.http.routers.httpsgraphedron.entrypoints=websecure"
      - "traefik.http.routers.httpsgraphedron.rule=Host(`www.graphedron.net`) || Host(`graphedron.net`)"
      - "traefik.http.routers.httpsgraphedron.service=httpsgraphedron-service"
      - "traefik.http.routers.httpsgraphedron.tls=true"
      - "traefik.http.routers.httpsgraphedron.tls.certresolver=lets-encrypt"
      - "traefik.http.services.httpsgraphedron-service.loadbalancer.server.port=80"

networks: 
  default: 
    external: 
      name: proxy

Quelques explications sur les labels

Label Explication
traefik.enable=true Activation de trafik pour ce docker-compose
traefik.http.routers.httpgraphedron.rule=Host(`www.graphedron.net`) || Host(`graphedron.net`) Définition d'un routers nommé "httpgraphedron" dont la règle (rule) s'applique au host www.graphedron.net et graphedron.net
traefik.http.routers.httpgraphedron.entrypoints=web Définition du routers nommé "httpgraphedron", il aura pour écoute l'entrypoint "web", ce qui correspond d'après mon docker compose traefik au port 80
traefik.http.routers.httpgraphedron.service=httpgraphedron-service Création du service ayant pour nom "httpgraphedron-service"
traefik.http.services.httpgraphedron-service.loadbalancer.server.port=80 Le service "httpgraphedron-service" transfèrera les requêtes au container sur le port 80 (le port d'écoute à l'intérieur de notre container applicatif)
traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https Chargement d'un middlewares (il s'agit plus ou moins d'un plugin) permettant de rediriger automatiquement les requêtes http en https
traefik.http.routers.httpgraphedron.middlewares=redirect-to-https On applique le middleware sur le routers "httpgraphedron" afin que les requêtes soient renvoyées sur l'https
traefik.http.routers.httpsgraphedron.entrypoints=websecure On défini un router "httpsgraphedron" qui aura pour entrypoints websecure (d'après mon docker compose traefik celui-ci écoute sur le port 443)
traefik.http.routers.httpsgraphedron.rule=Host(`www.graphedron.net`) || Host(`graphedron.net`) Comme pour l'http, je souhaite que le domaine en écoute soit www.graphedron.net et graphedron.net en https
traefik.http.routers.httpsgraphedron.service=httpsgraphedron-service On créer le service "httpsgraphedron-service"
traefik.http.routers.httpsgraphedron.tls=true On active la génération de certificat
traefik.http.routers.httpsgraphedron.tls.certresolver=lets-encrypt On choisi une génération délégué à lets-encrypt
traefik.http.services.httpsgraphedron-service.loadbalancer.server.port=80 Les requêtes seront soumise au container sur le port interne 80