• Docker
  • Traefik plusieurs services sur le même port

Bonjour,

J'utilise Traefik comme reverse proxy (au lieu de l'image de jrcs) pour la prise en charge du wildcard let's encrypt. Je voudrais que traefik redirige le trafic vers plusieurs docker qui tournent sur le port 80. Naturellement, j'ai exposé le port 80 de chaque docker vers un autre port pour l'utiliser dans traefik mais cela ne fonctionne pas. Comment faire ?

Voici mon docker-compose :

    version: '3.6'

services:
  traefik:
    hostname: traefik
    image: traefik:latest
    container_name: traefik
    restart: always
    domainname: ${DOMAINNAME}
    networks:
      - default
      - traefik_proxy
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    environment:
      - OVH_ENDPOINT=${OVH_ENDPOINT}
      - OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
      - OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
      - OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
    labels:
      - "traefik.enable=true"
      - "traefik.backend=traefik" # Utile pour le load balancing
      # L'adresse sur laquelle l'utilisateur accède à l'application
      - "traefik.frontend.rule=Host:toto.${DOMAINNAME}, www.toto.${DOMAINNAME}"  
      - "traefik.port=8080" # Le port de l'application dans le conteneur
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.STSSeconds=315360000"
      - "traefik.frontend.headers.browserXSSFilter=true"
      - "traefik.frontend.headers.contentTypeNosniff=true"
      - "traefik.frontend.headers.forceSTSHeader=true"
      - "traefik.frontend.headers.SSLHost=richardantoine.fr"
      - "traefik.frontend.headers.STSIncludeSubdomains=true"
      - "traefik.frontend.headers.STSPreload=true"
      - "traefik.frontend.headers.frameDeny=true"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik:/etc/traefik
      - shared:/shared
    deploy:
      replicas: 6
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  portainer:
    image: portainer/portainer
    container_name: portainer
    restart: always
    command: -H unix:///var/run/docker.sock
#    ports:
#      - "XXXX:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer-data:/data
      - shared:/shared
    environment:
      - TZ=${TZ}
    networks:
      - traefik_proxy
    labels:
      - "traefik.enable=true"
      - "traefik.backend=portainer"
      - "traefik.frontend.rule=Host:toto1.${DOMAINNAME},www.toto2.${DOMAINNAME}"
      - "traefik.port=9000"
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.STSSeconds=315360000"
      - "traefik.frontend.headers.browserXSSFilter=true"
      - "traefik.frontend.headers.contentTypeNosniff=true"
      - "traefik.frontend.headers.forceSTSHeader=true"
      - "traefik.frontend.headers.SSLHost=richardantoine.fr"
      - "traefik.frontend.headers.STSIncludeSubdomains=true"
      - "traefik.frontend.headers.STSPreload=true"
      - "traefik.frontend.headers.frameDeny=true"

  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    depends_on:
      - wordpress_db
    networks:
      - traefik_proxy
      - internal
    ports:
      - "7006:80"  
    environment:
      - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
    volumes:
      - wp_conf_upload_php:/usr/local/etc/php/conf.d/uploads.ini
      - wp_app:/var/www/html # Full wordpress project
    labels:
      - "traefik.enable=true"
      - "traefik.backend=wordpress"
      - "traefik.frontend.rule=Host:toto3.${DOMAINNAME}"
      - "traefik.port=7006"
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.STSSeconds=315360000"
      - "traefik.frontend.headers.browserXSSFilter=true"
      - "traefik.frontend.headers.contentTypeNosniff=true"
      - "traefik.frontend.headers.forceSTSHeader=true"
      - "traefik.frontend.headers.SSLHost=richardantoine.fr"
      - "traefik.frontend.headers.STSIncludeSubdomains=true"
      - "traefik.frontend.headers.STSPreload=true"
      - "traefik.frontend.headers.frameDeny=true"

  wordpress_db:
    image: mariadb:latest
    container_name: wordpress_db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
    networks:
      - internal
    volumes:
      - wp_data:/docker-entrypoint-initdb.d
    labels:
      - traefik.enable=true

  nextcloud:
    container_name: nextcloud
    restart: always
    image: linuxserver/nextcloud
    volumes:
      - nextcloud:/config
      - shared_data:/data
      - shared:/shared
#    ports:
#      - "XXXX:443"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    networks:
      - traefik_proxy
    labels:
      - "traefik.enable=true"
      - "traefik.backend=nextcloud"
      - "traefik.frontend.rule=Host:toto4.${DOMAINNAME}"
      - "traefik.port=443"
      - "traefik.protocol=https"
      - "traefik.docker.network=traefik_proxy"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.STSSeconds=315360000"
      - "traefik.frontend.headers.browserXSSFilter=true"
      - "traefik.frontend.headers.contentTypeNosniff=true"
      - "traefik.frontend.headers.forceSTSHeader=true"
      - "traefik.frontend.headers.SSLHost=example.com"
      - "traefik.frontend.headers.STSIncludeSubdomains=true"
      - "traefik.frontend.headers.STSPreload=true"
      - "traefik.frontend.headers.frameDeny=true"





volumes:
  traefik:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/traefik
  shared:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/shared
  organizr:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/organizr
  shared_data:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/shared_data
  nextcloud:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/nextcloud
  podcast_conf:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/podcast
  ### WORDPRESS ###
  wp_app:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/wordpress/app
  wp_data:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/wordpress/data
  wp_conf_upload_php:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/wordpress/conf   
  portainer-data:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ${USERDIR}/docker/portainer/data
  
networks:
  traefik_proxy:
    external:
      name: traefik_proxy
  internal:
    external: false
  default:
    driver: bridge

    Plusieurs choses qui ne vont pas ici :
    - Tu ne défini pas de conf pour traefik !
    - Tu n'as pas besoin de mapper les ports des container avec ceux de l'hôte.
    - Tes containers doivent être dans le réseau traefik_proxy.
    - Le port défini dans tes labels doivent dorrespondre au port interne du container.
    - Tu devrais définir tes headers dans le fichier de conf de traefik, ça allègerai ton docker-compose !
    `
    Après relecture, c'est surprenant.. tu as des services bien configurés (portainer) et d'autres pas du tout !
    Exemple de service OK :

      wordpress:
        image: wordpress:latest
        container_name: wordpress
        restart: always
        depends_on:
          - wordpress_db
        networks:
          - traefik_proxy
          - internal
        environment:
          - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
        volumes:
          - wp_conf_upload_php:/usr/local/etc/php/conf.d/uploads.ini
          - wp_app:/var/www/html # Full wordpress project
        networks:
          - traefik_proxy
        labels:
          - "traefik.enable=true"
          - "traefik.frontend.rule=Host:toto3.${DOMAINNAME}"
          - "traefik.port=80"
          - "traefik.docker.network=traefik_proxy"
          - "traefik.frontend.headers.SSLRedirect=true"
          - "traefik.frontend.headers.STSSeconds=315360000"
          - "traefik.frontend.headers.browserXSSFilter=true"
          - "traefik.frontend.headers.contentTypeNosniff=true"
          - "traefik.frontend.headers.forceSTSHeader=true"
          - "traefik.frontend.headers.SSLHost=richardantoine.fr"
          - "traefik.frontend.headers.STSIncludeSubdomains=true"
          - "traefik.frontend.headers.STSPreload=true"
          - "traefik.frontend.headers.frameDeny=true"

    Exemple de fichier de conf de traefik:

    defaultEntryPoints = ["https","http"]
    
    [api]
    entryPoint = "traefik"
    dashboard = true
    
    [entryPoints]
      [entryPoints.http]
      address = ":80"
        [entryPoints.http.redirect]
        entryPoint = "https"
      [entryPoints.https]
      address = ":443"
        [entryPoints.https.tls]
      [entryPoints.traefik]
      address = ":8080"
      [entryPoints.traefik.auth.basic]
      users = ["zer:$apr1$Gj3CFGpe$2j.Yr0fF8lcd2SJOl97Pu1"]
    
    [acme]
    email = "me@mydomain.tld"
    storage = "/etc/traefik/acme/acme.json"
    entryPoint = "https"
    onHostRule = true
    onDemand = false
      [acme.httpChallenge]
      entryPoint = "http"
    
    [docker]
    endpoint = "unix:///var/run/docker.sock"
    domain = "mydomain.tld"
    watch = true
    exposedbydefault = false

    Il convient d'enregistrer ça dans un fichier traefik.toml et de le mapper avec le container traefik.

      zer Effectivement le fichier de conf n'est pas nécessaire, mais demande de tout foutre dans le compose (perso je pref le fichier de conf)
      Glodi avec traefik (ou n'importe quel reverse en general) il n'est pas nécéssaire d'expose les ports (sinon tu perds l'interet du reverse 🙂 ) Ensuite 6 replicas pour 2 parralelism c'est un peu beaucoup ? :p. Sinon le reste du compose j'ai pas poussé

        Merrick

        arckosfr

        Oui et non. Ou en tout cas, je n'ai pas réussi à faire passer certains paramètres en command:. Et ce n'est pas faute d'avoir cherché et testé beaucoup de confs !

        Dès qu'on sort d'une conf basique, il vaut mieux passer par le fichier. Et perso, je préfère: plus lisible et mieux catégorisé (je n'utilise pas traefik uniquement avec docker. Dès qu'on multiplie les front/back-ends, c'est vite le bordel si on ne segmente pas tout ! )

        Je confirme, dès qu'on sort du full docker, il faut un fichier de conf.

        hydrog3n a renommé le titre en Traefik plusieurs services sur le même port.

        zer Merci de ton aide 😄

        Dans le volume traefik, j'ai bien un traefik.toml qui est presque identique au tiens, à l'exception du domaine et du md5.
        Je n'avais pas de ports définis au départ, je les ai ajouté "pour voir si ça fonctionnait mieux"... J'ai donc remis le port 80 pour wordpress.
        Comment mettre les headers dans le fichier de conf de traefik ? Je n'ai pas trouvé d’exemple sur la doc officielle

        arckosfr 6 replicas pour 2 parralelism

        Ouais effectivement 😜

        Quand je lance mon docker-compose, le conteneur wordpress est en bad gateway. Les logs du conteneur wordpress indiquent : php_network_getaddresses: getaddrinfo failed: Name or service not known

        Les logs de traefik indiquent : level=error msg="undefined backend 'backend-wordpress-docker'. J'ai pourtant supprimé le backend wordpress... Voici mon docker-compose :

        version: '3.6'
        services:
        traefik:
            hostname: traefik
            image: traefik:latest
            container_name: traefik
            restart: always
            domainname: ${DOMAINNAME}
            networks:
            - default
            - traefik_proxy
            ports:
            - "80:80"
            - "443:443"
            - "8080:8080"
            environment:
            - OVH_ENDPOINT=${OVH_ENDPOINT}
            - OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
            - OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
            - OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
            labels:
            - "traefik.enable=true"
            - "traefik.backend=traefik" # Utile pour le load balancing
            # L'adresse sur laquelle l'utilisateur accède à l'application
            - "traefik.frontend.rule=Host:toto.${DOMAINNAME}, www.toto.${DOMAINNAME}"  
            - "traefik.port=8080" # Le port de l'application dans le conteneur
            - "traefik.docker.network=traefik_proxy"
            - "traefik.frontend.headers.SSLRedirect=true"
            - "traefik.frontend.headers.STSSeconds=315360000"
            - "traefik.frontend.headers.browserXSSFilter=true"
            - "traefik.frontend.headers.contentTypeNosniff=true"
            - "traefik.frontend.headers.forceSTSHeader=true"
            - "traefik.frontend.headers.SSLHost=richardantoine.fr"
            - "traefik.frontend.headers.STSIncludeSubdomains=true"
            - "traefik.frontend.headers.STSPreload=true"
            - "traefik.frontend.headers.frameDeny=true"
            volumes:
            - /var/run/docker.sock:/var/run/docker.sock:ro
            - traefik:/etc/traefik
            - shared:/shared
            deploy:
            replicas: 2
            update_config:
                parallelism: 2
                delay: 10s
            restart_policy:
                condition: on-failure
        
        portainer:
            image: portainer/portainer
            container_name: portainer
            restart: always
            command: -H unix:///var/run/docker.sock
            volumes:
            - /var/run/docker.sock:/var/run/docker.sock
            - portainer-data:/data
            - shared:/shared
            environment:
            - TZ=${TZ}
            networks:
            - traefik_proxy
            labels:
            - "traefik.enable=true"
            - "traefik.backend=portainer"
            - "traefik.frontend.rule=Host:toto1.${DOMAINNAME},www.toto2.${DOMAINNAME}"
            - "traefik.port=9000"
            - "traefik.docker.network=traefik_proxy"
            - "traefik.frontend.headers.SSLRedirect=true"
            - "traefik.frontend.headers.STSSeconds=315360000"
            - "traefik.frontend.headers.browserXSSFilter=true"
            - "traefik.frontend.headers.contentTypeNosniff=true"
            - "traefik.frontend.headers.forceSTSHeader=true"
            - "traefik.frontend.headers.SSLHost=richardantoine.fr"
            - "traefik.frontend.headers.STSIncludeSubdomains=true"
            - "traefik.frontend.headers.STSPreload=true"
            - "traefik.frontend.headers.frameDeny=true"
        
        wordpress:
            image: wordpress:latest
            container_name: wordpress
            restart: always
            depends_on:
            - wordpress_db
            networks:
            - traefik_proxy
            - internal
            environment:
            - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
            volumes:
            - wp_conf_upload_php:/usr/local/etc/php/conf.d/uploads.ini
            - wp_app:/var/www/html # Full wordpress project
            labels:
            - "traefik.enable=true"
            - "traefik.frontend.rule=Host:toto3.${DOMAINNAME}"
            - "traefik.port=80"
            - "traefik.docker.network=traefik_proxy"
            - "traefik.frontend.headers.SSLRedirect=true"
            - "traefik.frontend.headers.STSSeconds=315360000"
            - "traefik.frontend.headers.browserXSSFilter=true"
            - "traefik.frontend.headers.contentTypeNosniff=true"
            - "traefik.frontend.headers.forceSTSHeader=true"
            - "traefik.frontend.headers.SSLHost=richardantoine.fr"
            - "traefik.frontend.headers.STSIncludeSubdomains=true"
            - "traefik.frontend.headers.STSPreload=true"
            - "traefik.frontend.headers.frameDeny=true"
        
        wordpress_db:
            image: mariadb:latest
            container_name: wordpress_db
            restart: always
            environment:
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
            networks:
            - internal
            volumes:
            - wp_data:/docker-entrypoint-initdb.d
            labels:
            - traefik.enable=true
        
        nextcloud:
            container_name: nextcloud
            restart: always
            image: linuxserver/nextcloud
            volumes:
            - nextcloud:/config
            - shared_data:/data
            - shared:/shared
            environment:
            - PUID=${PUID}
            - PGID=${PGID}
            networks:
            - traefik_proxy
            labels:
            - "traefik.enable=true"
            - "traefik.backend=nextcloud"
            - "traefik.frontend.rule=Host:toto4.${DOMAINNAME}"
            - "traefik.port=443"
            - "traefik.protocol=https"
            - "traefik.docker.network=traefik_proxy"
            - "traefik.frontend.headers.SSLRedirect=true"
            - "traefik.frontend.headers.STSSeconds=315360000"
            - "traefik.frontend.headers.browserXSSFilter=true"
            - "traefik.frontend.headers.contentTypeNosniff=true"
            - "traefik.frontend.headers.forceSTSHeader=true"
            - "traefik.frontend.headers.SSLHost=example.com"
            - "traefik.frontend.headers.STSIncludeSubdomains=true"
            - "traefik.frontend.headers.STSPreload=true"
            - "traefik.frontend.headers.frameDeny=true"
        
        
        
        
        
        volumes:
        traefik:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/traefik
        shared:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/shared
        organizr:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/organizr
        shared_data:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/shared_data
        nextcloud:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/nextcloud
        podcast_conf:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/podcast
        ### WORDPRESS ###
        wp_app:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/wordpress/app
        wp_data:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/wordpress/data
        wp_conf_upload_php:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/wordpress/conf   
        portainer-data:
            driver: local
            driver_opts:
            o: bind
            type: none
            device: ${USERDIR}/docker/portainer/data
        
        networks:
        traefik_proxy:
            external:
            name: traefik_proxy
        internal:
            external: false
        default:
            driver: bridge
        

        Salut, essayez d'utiliser les balises svp, surtout qu'il y a un menu à cliquer maintenant 😉 C'est plus simple pour la lecture et la compréhension.

          Aerya Ce n'est pas faute d'avoir essayé mais je n'arrive pas à placer les balises à cause de l'indentation...

            Glodi Hello j'ai fait la modification mais pour information la balise BBcode existe pour mettre le mode code avec [code][/code]

              4 jours plus tard

              Suite à des recherches sur Internet pour résoudre le problème de backend avec traefik, il s'agirait d'un problème au niveau du nom du frontend.

              En effet, le sous-domaine (toto3 dans l’exemple) wordpress comporte un tiret. Quelqu'un a déjà été confronté au problème ?

              Répondre…