Merci, je commence par la version simple moins secure pour déjà comprendre la base et après je rajouterai les couches sécu 😉
Donc je suis parti sur le fichier traefik.yml fourni par Banip quelques posts au dessus.
J'ai quelques questions comme toujours :

log:
level: INFO
filePath: /etc/traefik/traefik.log

  • Il ne faudrait pas ajouter un bind mount pour le répertoire ci-dessus dans le docker-compose (/etc/traefik/traefik.log) ?

  • Quelle est la différence entre web et http dans les entrypoints ?

  • Quelqu'un utilise un nom de domaine OVH ? J'ai bien suivi les procédures, apparemment c'est un DNS challenge qui est utilisé. J'ai bien configuré mon API OVH mais concernant les variables à passer, est-ce qu'il faut le faire par un fichier ? Si oui sous quelle forme ? Ou directement en variables d'environnement ? Directement dans mon fichier docker-compose ou dans le traefik.yml ?

Merci !

Edit : A moins que je puisse utiliser le challenge HTTP avec OVH, je viens de lire que le DNS challenge n'est pas trop sécurisé car il faut donner des droits particuliers...

    NicCo Il ne faudrait pas ajouter un bind mount pour le répertoire ci-dessus dans le docker-compose (/etc/traefik/traefik.log) ?

    Si tu veux, tu peux bien sûr.

    Quelle est la différence entre web et http dans les entrypoints ?

    Tu peux le nommer web ou http, webscure ou https, c'est la même chose, c'est un nom pour le point d'entrée vers respectivement 80 et 443 (HTTP et HTTPS).

    A moins que je puisse utiliser le challenge HTTP avec OVH, je viens de lire que le DNS challenge n'est pas trop sécurisé car il faut donner des droits particuliers...

    Oui, tu dois laisser un token d'accès à l'API du registar, c'est pas ouf. Je conseille d'utiliser TLS-ALPN-01 que Traefik a l'avantage de supporter (contrairement à nginx/certbot pour l'instant), il suffit simplement de préciser tlsChallenge: {}.

    Merci encore @Wonderfall
    J'ai réussi à faire tourner et à accéder à Traefik, le certificat marche en HTTP challenge mais pour passer en TLN-ALPN-01 il faut que je bascule comme ça ?

    certificatesResolvers:
      letsencrypt-ecdsa:
        acme:
          email: xxxx@xxxx.com
          caserver: https://acme-v02.api.letsencrypt.org/directory
          storage: /etc/traefik/acme.json
          keytype: EC384
          httpChallenge:
            entryPoint: web
          tlschallenge: {} # au lieu de true
      letsencrypt-rsa2048:
        acme:
          email: xxxx@xxxx.com
          caserver: https://acme-v02.api.letsencrypt.org/directory
          storage: /etc/traefik/acme.json
          keytype: RSA2048
          httpChallenge:
            entryPoint: web
          tlschallenge: {} # au lieu de true

    J'ai rencontré aussi un autre problème, j'avais un Bad Gateway en essayant d'accéder à l'interface de Traefik. J'avais repris le fichier de @Banip

    api:
      insecure: true
      dashboard: true

    Le problème venait du "insecure: true" que j'ai passé en false.

    Est-ce qu'il vaut mieux rester dans cette config ou modifier la config des routers ?

    traefik:
      rule: "Host(`revprox.minga.fr`)"
      entryPoints:
        - "web"
      middlewares:
        - "redirect-to-https@file"
      service: "noop@internal"
    traefik-secure:
      rule: "Host(`revprox.minga.fr`)"
      entryPoints:
        - "websecure"
      middlewares:
        - "hsts@file"
        - "security@file"
        - "compression@file"
        - "admin-user@file"
      service: "traefik@file"
      tls:
        certResolver: letsencrypt-ecdsa
        options: mintls13

    Est-ce qu'il y a une config à modifier dans cette partie pour passer en "insecure: false" ?

    Merci !

    Pour le challenge TLS, utilise simplement ces quelques lignes :

    certificatesResolvers:
      le-ec384:
        acme:
          email: mail@domaine.tld
          storage: acme.json
          keyType: EC384
          tlsChallenge: {}

    Effectivement il ne faut pas activer l'option insecure, à la place utilise le service api@internal qui est créé automatiquement dès que l'API est activée, et tu peux l'utiliser directement dans un routeur. Chez ta config, remplace ainsi traefik@file par api@internal tout simplement.

    Ok merci je vais regarder ça, je vais en profiter pour simplifier le resolver. Pas besoin d'indiquer le caserver ni httpchallenge du coup ?

    Et pour l'api le fait d'indiquer api: insecure: et dashboard: ça active l'api ? Pas besoin de faire un enable: true par exemple ?

    Merci.

    Non non, pas besoin. Et pour l'api, juste dashboard: true, car insecure expose le port, mais pas besoin comme tu auras api@internal.

    Tout est dans la doc : https://doc.traefik.io/traefik/
    (Mais je conviens, Traefik v2 est plus compliqué à dompter que la v1.)

    Parfait ça a l'air de fonctionner 🙂 merci !
    Le docker-compose se limite à ça pour le moment (en attendant de mettre en place le socket proxy, le runtime gvisor, le no-new-privileges, etc..), s'il y a des choses importantes à rajouter je suis preneur 😉 Même chose pour les autres fichiers

    version: "2.4"
      networks:
        frontend:
          external: true
          
    services:
      traefik:
        container_name: traefik
        image: traefik:latest
        volumes:
          - ./traefik.yml:/etc/traefik/traefik.yml
          - ./acme/acme.json:/etc/traefik/acme.json
          - ./certs:/etc/traefik/certs
          - ./conf.d:/etc/traefik/conf.d
          - ./traefik2.log:/etc/traefik/traefik2.log
          - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 80:80
      - 443:443
    networks:
      - frontend
    restart: unless-stopped

    Le traefik.yml :

    global:
      checkNewVersion: false
      sendAnonymousUsage: false
    
    providers:
      file:
        directory: /etc/traefik/conf.d/
        watch: true
    
    api:
    #  insecure: true
      dashboard: true
    
    log:
      level: INFO
      filePath: /etc/traefik/traefik2.log
    
    accessLog: true
    
    entryPoints:
      web:
        address: ":80"
      websecure:
        address: ":443"
    
    certificatesResolvers:
      letsencrypt-ecdsa:
        acme:
          email: mail@domain.tld
          caserver: https://acme-v02.api.letsencrypt.org/directory
          storage: /etc/traefik/acme.json
          keytype: EC384
          httpChallenge:
            entryPoint: web
          tlschallenge: true
      letsencrypt-rsa2048:
        acme:
        email: mail@domain.tld
        caserver: https://acme-v02.api.letsencrypt.org/directory
        storage: /etc/traefik/acme.json
        keytype: RSA2048
        httpChallenge:
          entryPoint: web
        tlschallenge: true
    letsencrypt-ec384:
      acme:
        email: mail@domain.tld
        storage: /etc/traefik/acme.json
        keyType: EC384
        tlsChallenge: {}

    Le traefik.yml dans conf.d :

    http:
      services:
        traefik:
          loadBalancer:
            servers:
              - url: "http://localhost:8080"
    
    routers:
      traefik:
        rule: "Host(`traefik.domain.tld`)"
        entryPoints:
          - "web"
        middlewares:
          - "redirect-to-https@file"
        service: "noop@internal"
      traefik-secure:
        rule: "Host(`traefik.domain.tld`)"
        entryPoints:
          - "websecure"
        middlewares:
          - "hsts@file"
          - "security@file"
          - "compression@file"
          - "admin-user@file"
        service: "api@internal"
        tls:
          certResolver: letsencrypt-ec384
          options: mintls13

    Le reste des fichiers est identique au tuto. Pour les resolvers je peux garder juste le 3ème et supprimer les 2 autres du coup ?

    Merci !

    Tu as besoin de tous ces certificatesResolvers pour la compatibilité de clients ? Sinon reste en full EC384, c'est le mieux.

    Aussi tu peux dès maintenant faire une redirection totale de HTTP vers HTTPS, comme ça :

    entryPoints:
      web:
        address: :80
        http:
          redirections:
            entryPoint:
              to: :443
              scheme: https
              permanent: true

    Tu n'auras jamais besoin de créer un service http avec les middlewares redirect-to-https, ça réduit drastiquement la configuration... A condition que tu veuilles bien du full HTTPS (donc si c'est en prod, en 2021, la question se pose pas).

    Pour ton traefik.yml, comme tu utilises le service intégré api@internal, tu peux virer le bloc services qui est redondant du coup.

    Merci @Wonderfall pour les infos (encore et encore 😃)

    Pour les certs resolvers, je n'ai pas encore testé les clients. Le risque c'est qu'ils ne puissent pas se connecter ? Ou c'est plus subtil que ça et ça ne se voit pas du premier coup ?

    Pour la redirection totale de HTTP vers HTTPS, je pense effectivement que c'est obligatoire et que tous les clients supportent le HTTPS maintenant (sauf peut-être des cas particuliers isolés qui n'ont pas eu de mises à jour depuis des années...). Du coup il faut que je modifie la configuration des routers aussi ? Plus besoin d'avoir un router traefik, je garde uniquement le traefik-secure ? Et j'adapte le nom de l'entrypoints en fonction de ce que j'ai renseigné dans mon traefik.yml ?

    Oui c'est un risque pour des vieux clients, mais après on n'est plus en 2015 (et encore en 2016 en utilisant "précocement" les certificats EC384 j'ai eu peu de soucis), aujourd'hui le support des certificats ECC et plus précisément EC384 est vraiment "mainstream", ça ne devrait pas poser de soucis. Donc franchement t'es bon avec juste ça.

    Du coup il faut que je modifie la configuration des routers aussi ? Plus besoin d'avoir un router traefik, je garde uniquement le traefik-secure ? Et j'adapte le nom de l'entrypoints en fonction de ce que j'ai renseigné dans mon traefik.yml ?

    Oui c'est ça, tu vires les routeurs qui sont pas "secure", ça ne sert plus à rien vu que la redirection sera globale sur l'entrypoint "non-secure". J'ai testé les redirections, ça marche parfaitement et c'est une solution propre (maintenant suggérée dans leur doc).

    Merci @Wonderfall
    Je vais tester de rester uniquement en EC384, si je vois que certains clients ne peuvent pas se connecter je regarderai pour remettre d'autres certificatesresolvers 😉
    Pour la redirection effectivement je viens de regarder la doc et j'ai vu ce dont tu parles, je suis parti comme dans leur exemple du coup :

    entryPoints:
      web:
        address: ":80"
        http:
          redirections:
            entryPoint:
              to: websecure
              scheme: https
              permanent: true
      websecure:
        address: ":443"

    La seule différence avec ton exemple c'est le to: qui pointe vers websecure au lieu de :443 mais ça doit revenir au même vu que websecure pointe vers :443 (et donc si jamais on venait à modifier, pour x raison, le 443 en 4443 on aurait juste à faire une modif sur websecure au lieu de 2 ?)

    Je pense que traefik est OK après ces modifs, me reste à essayer d'intégrer une app comme nextcloud ou autre, et une fois que tout sera fonctionnel je passe à la sécurisation 🙂

      Et donc si j'ai bien compris, si par exemple mon app traefik est dans /home/user/docker/traefik et que je veux créer une autre app dans /home/user/docker/app, je n'aurais plus à déclarer de labels concernant traefik dans le docker-compose.yml de la nouvelle app ?
      J'aurais juste à créer un app.yml dans le dossier conf.d de traefik avec les infos concernant ma nouvelle app et c'est tout ? Pas besoin de bind mount le dossier conf.d dans le docker-compose.yml de ma nouvelle app ?
      Si je prends par exemple portainer (je n'ai pas encore organisé mes stacks donc disons qu'elle sera à part et on ferme les yeux sur le docker.sock pour le moment 😃), j'aurais juste ce fichier docker-compose.yml dans le répertoire que je veux ?

      version: "2.4"
      
      networks:
        frontend:
          external: true
      
      services:
        portainer:
          container_name: portainer
          image: portainer/portainer-ce
          volumes:
            - ./data/:/data/
            - /var/run/docker.sock:/var/run/docker.sock
          networks:
            - frontend
          restart: unless-stopped

      NicCo La seule différence avec ton exemple c'est le to: qui pointe vers websecure au lieu de :443 mais ça doit revenir au même vu que websecure pointe vers :443 (et donc si jamais on venait à modifier, pour x raison, le 443 en 4443 on aurait juste à faire une modif sur websecure au lieu de 2 ?)

      Oui c'est la même chose, moi j'ai précisé :443 car mon conteneur Traefik est rootless et écoute sur le port 4430 (et avec la magie de Docker et du NAT ça devient le port 443 exposé sur mon IP publique). Mais longue histoire

      J'aurais juste à créer un app.yml dans le dossier conf.d de traefik avec les infos concernant ma nouvelle app et c'est tout ? Pas besoin de bind mount le dossier conf.d dans le docker-compose.yml de ma nouvelle app ?

      Pas besoin non, l'app n'y ferait rien. Traefik communiquera avec ton app via le réseau docker, frontend dans ton cas. Après moi j'utilise encore la configuration dynamique, il faudra voir les exemples de xataz pour la configuration statique, mais c'est l'idée

      Merci @Wonderfall
      Petit à petit ça avance, c'est cool 🙂
      Encore une question : si par exemple je souhaite monter un serveur de medias type Emby ou Jellyfin auquel je veux accéder soit directement en local, soit derrière Traefik, il suffit juste de rajouter les ports dans le docker-compose du serveur de medias ? En l'occure :

      ports :
        - 8096:8096
        - 7359:7359/udp
        - 1900:1900/udp

      Merci !

      Edit: Je viens de tomber sur macvlan, c'est la solution qu'il faudrait que j'utilise ?

        NicCo Ne fais pas ça, tu risques d'exposer publiquement Jellyfin en HTTP, c'est pas ce que tu veux. Ce qu'il faut faire, c'est lier les 2 conteneurs (Jellyfin et Traefik) avec un réseau, et créer un service qui écoute sur jellyfin:8096.

        Si ton serveur est local, tu peux par contre modifier et préciser par sécurité 127.0.0.1:8096:8096 pour qu'en gros le port ne soit exposé que localement si tu veux y accéder sans Traefik. Pareil pour les autres, si c'est une utilisation spécifique (je doute que tu aies besoin les exposer sur Internet !).

        Moi je ferais juste tout simplement passer par Traefik, et dans ce cas tu n'as pas besoin de publier les ports de Jellyfin.

          Wonderfall Merci, donc je crée un réseau différent de frontend, je l'ajoute sur Jellyfin et Traefik et je crée un autre service différent de celui-ci ?

          http:
            services:
              jellyfin:
                loadBalancer:
                  servers:
                    - url: "http://jellyfin:8096"

          Pour le serveur oui il est en local, si je précise 127.0.0.1:8096:8096, tous les équipements de mon réseau local pourront y accéder ? Par contre Jellyfin utilise 2 autres ports UDP pour le discovery et le DLNA. J'avais tenté d'exposer les 3 ports pour tester dans mon docker-compose mais par exemple le DLNA n'était pas détecté sur mon réseau local, alors qu'avec macvlan oui.

          Et tout passer par Traefik, je vais être dépendant de ma connexion Internet non ? Si je passe comme ça, je perds également le discovery et le DLNA, pratique pour la famille. Si j'utilise macvlan, l'accès ne sera pas limité uniquement qu'aux IP du subnet défini dans le réseau macvlan ?

            NicCo J'avoue que ça dépasse un peu mon utilisation donc je ne peux pas trop t'aider sur ce terrain. 🙁

            Mais macvlan me semble être utilisé pour des besoins bien précis, ce réseau associe une adresse MAC à ton conteneur, j'ai du mal à voir pourquoi faire ça.

            Sinon au pire tu publies le port 8096 et le reste normalement, mais tu filtres l'accès par iptables comme ça :
            -A FILTERS -p tcp --dport PORT -s LOCAL_SUBNET -j ACCEPT
            Avec la chaîne FILTERS à ajouter dans INPUT et DOCKER-USER. C'est une solution aussi je pense

            @Wonderfall De ce que j'ai compris macvlan te permet d'attaquer directement le réseau en bypassant un peu l'hôte en gros. Par contre il n'y a aucune communication entre l'hôte Docker et les containers d'après ce que j'ai lu.
            La surface d'attaque est donc limitée je pense. J'ai trouvé un cas d'utilisation pour Jellyfin / Emby et un AdGuard apparemment.
            Je vais refaire quelques tests hors Traefik pour voir déjà ce que ça donne, sinon je testerai ta méthode aussi 😉 merci

            @Wonderfall Je viens de relire la doc de Jellyfin et eux indiquent d'utiliser le host mode à la base. Sauf qu'à priori le host mode n'est pas compatible avec l'utilisation de networks donc pas possible d'utiliser le container en local (avec le DLNA qui fonctionne) et en distant derrière Traefik.
            Donc en gros :

            • soit je passe tout derrière Traefik (mais est-ce que le fonctionnement est le même qu'à l'extérieur, à savoir que le débit max sera celui de l'upload de ma connexion donc 40Mbps ? Malgré que soit pour une utilisation LAN le flux va sortir et rentrer par ma connexion Internet ?)
            • soit j'utilise macvlan pour avoir un Jellyfin complètement opérationnel, avec les éventuels risques de sécurité que ça peut comporter
            • soit je me passe du DLNA et du discover (je vais re réfléchir à mon utilisation) et à ce moment-là je peux exposer sur mon réseau local, en activant en plus la règle iptables que tu m'as indiqué

              NicCo Moi je pense toujours que tu peux utiliser bridge même pour les ports en local.
              Précise l'IP du subnet local comme j'ai montré avant pour voir si ça marche. Et si ça marche pas, tu le fais écouter sur localhost et puis t'utilises nginx pour reverse proxy ça.

              Dans tous les cas, je vois difficilement l'intérêt du mode network host, tu peux juste publier les ports de la bonne façon. Et en dernier recours faire des règles iptables manuelles.