Traefik container not reaching Wordpress as a service

I'm new to Traefik and Docker and trying to set up an environment to learn, so I'd appreciate some patience with any silly questions I might have.

I'm trying to set up a Traefik container that routes to two web servers on two different hosts. I'm having trouble adding the WordPress site as a service in Traefik, so that it can then route and establish the connection between WordPress and Traefik, as well as the connection between Traefik and the WordPress containers.

Is there anything obvious that I'm missing or any clear mistake that you see? It feels like I've tried everything but just can't get it to work. Let me know if you need any more information about my environment! Would appreciate any help! :grin:

Here are my config files:

docker_compose.yml:

networks:
  wordpress-network:
    external: true
  traefik-network:
    external: true

volumes:
  mysql-data:
  wordpress-data:

services:
  mysql:
    image: ${WORDPRESS_MYSQL_IMAGE_TAG}
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: ${WORDPRESS_DB_NAME}
      MYSQL_USER: ${WORDPRESS_DB_USER}
      MYSQL_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${WORDPRESS_DB_ADMIN_PASSWORD}
    networks:
      - wordpress-network
    restart: unless-stopped

  wordpress:
    image: ${WORDPRESS_IMAGE_TAG}
    volumes:
      - wordpress-data:${DATA_PATH}
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_PORT_NUMBER: 3306
      WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      WORDPRESS_TABLE_PREFIX: ${WORDPRESS_TABLE_PREFIX}
      WORDPRESS_BLOG_NAME: ${WORDPRESS_BLOG_NAME}
      WORDPRESS_FIRST_NAME: ${WORDPRESS_ADMIN_NAME}
      WORDPRESS_LAST_NAME: ${WORDPRESS_ADMIN_LASTNAME}
      WORDPRESS_USERNAME: ${WORDPRESS_ADMIN_USERNAME}
      WORDPRESS_PASSWORD: ${WORDPRESS_ADMIN_PASSWORD}
    networks:
      - wordpress-network
      - traefik-network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wordpress.rule=Host(`${WORDPRESS_HOSTNAME}`)"
      - "traefik.http.routers.wordpress.service=wordpress"
      - "traefik.http.routers.wordpress.entrypoints=web"
      - "traefik.http.services.wordpress.loadbalancer.server.port=80"
      - "traefik.docker.network=traefik-network"
    restart: unless-stopped

  traefik:
    image: ${TRAEFIK_IMAGE_TAG}
    command:
      - "--log.level=${TRAEFIK_LOG_LEVEL}"
      - "--accesslog=true"
      - "--api.dashboard=true"
      - "--api.insecure=true"
      - "--entryPoints.web.address=:80"
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik-network
    ports:
      - "80:80"
      - "8080:8080"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME}`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.entrypoints=web"
    restart: unless-stopped

docker-compose-traefik.yml:

  traefik:
    image: ${TRAEFIK_IMAGE_TAG}
    command:
      - "--log.level=${TRAEFIK_LOG_LEVEL}"
      - "--accesslog=true"
      - "--api.dashboard=true"
      - "--api.insecure=true"
      - "--entryPoints.web.address=:80"
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik-network
    ports:
      - "80:80"
      - "8080:8080"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME}`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.entrypoints=web"
    restart: unless-stopped

docker-compose-wordpress.yml:

version: '3'

networks:
  traefik:
    external: true
  wordpress:
    external: true

volumes:
  db_data:

services:
  wordpress:
    image: wordpress
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wordpress.rule=Host(`www.proxmoxpojkarna.se`)"
      - "traefik.http.routers.wordpress.entrypoints=web"
      - "traefik.http.services.wordpress.loadbalancer.server.port=80"
    environment:
      - WORDPRESS_DB_HOST=mysql
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=password
    depends_on:
      - mysql
    networks:
      - traefik
      - wordpress
  
  mysql:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=wordpress
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wordpress

You could use Docker Swarm and a single Traefik instance, with providers.docker and swarmmode enabled. Traefik can auto-discovery your target services, when you attach according labels.

Check simple Traefik Swarm example.

3 things to note:

  • labels in swarm go under deploy
  • you need to set the target service port
  • set docker.network in labels when having multiple networks

When you want to use multiple hosts without swarm, then you probably need to manually create a router and service with loadbalancer.server.url, which can only be used in a dynamic config file.

Hi!

Thank you for the reply. Your traefik-best-practice repo really helped a lot! I managed to deploy wordpress and mysql on my host. Im now facing a new problem. I want to be able to host multiple websites on my hosts. How do I configure this without the ports conflicting. I have tried to set it up but traefik redirects to the same site.

Here are my current compose-files:

traefik-compose-file:

version: '3'

services:
  traefik:
    image: traefik:v2.10
    hostname: '{{.Node.Hostname}}'
    ports:
    # listen on host ports without ingress network
    - target: 80
      published: 80
      protocol: tcp
      mode: host
    networks:
      - traefik_frontend
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    command:
      - --api.dashboard=true
      - --log.level=INFO
      #- --log.filepath=/var/log/traefik.log
      - --accesslog=true
      #- --accesslog.filepath=/var/log/traefik-access.log
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=traefik_frontend
      - --providers.docker.swarmMode=true
      - --entrypoints.web.address=:80
    deploy:
      mode: global  
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - traefik.http.routers.mydashboard.rule=Host(`traefik.example.com`)
        - traefik.http.routers.mydashboard.service=api@internal
        - traefik.http.services.mydashboard.loadbalancer.server.port=8080

networks:
  traefik_frontend:
    name: traefik_frontend
    driver: overlay
    attachable: true

mysql-compose-file:

version: '3'

volumes:
  mysql: #UNIQUE
  mysql_replica: #UNIQUE

services:
  mysql: #UNIQUE
    image: mysql
    ports:
    # listen on host ports without ingress network
    - target: 3306
      published: 3306
      protocol: tcp
      mode: host
    networks:
      - traefik_backend
    environment:
      - MYSQL_ROOT_PASSWORD=password #UNIQUE
      - MYSQL_DATABASE=wordpress #UNIQUE
      - MYSQL_USER=dbuser #UNIQUE
      - MYSQL_PASSWORD=wordpress #UNIQUE
    volumes:
      - mysql:/var/lib/mysql #UNIQUE not /var/lib/mysql
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.mysql == webserver1
      labels:
      - "traefik.enable=true"
      - "traefik.http.services.mysql_backup_replica.loadbalancer.server.port=3306"

  
  mysql_backup_replica:
    image: mysql
    ports:
    # listen on host ports without ingress network
    - target: 3306
      published: 3306
      protocol: tcp
      mode: host
    networks:
      - traefik_backend
    environment:
      - MYSQL_ROOT_PASSWORD=password #UNIQUE
      - MYSQL_DATABASE=wordpress_replica #UNIQUE
      - MYSQL_USER=dbuser_replica #UNIQUE
      - MYSQL_PASSWORD=wordpress_replica #UNIQUE
    volumes:
      - mysql_replica:/var/lib/mysql #UNIQUE not /var/lib/mysql
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.mysql == webserver2
      labels:
      - "traefik.enable=true"
      - "traefik.http.services.mysql_backup_replica.loadbalancer.server.port=3306"

networks:
  traefik_backend:
    name: traefik_backend
    driver: overlay
    attachable: true

wordpress-compose-file:

version: '3'

services:
  wordpress: #UNIQUE
    image: wordpress
    networks:
      - traefik_frontend
      - traefik_backend
    ports:
    # listen on host ports without ingress network
    - target: 80
      published: 80
      protocol: tcp
      mode: host
    environment:
      - WORDPRESS_DB_HOST=mysql #UNIQUE
      - WORDPRESS_DB_NAME=wordpress
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=password
    deploy:
      mode: global
      labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wordpress.rule=Host(`www.testsite1.se`)" #UNIQUE
      - "traefik.http.services.wordpress.loadbalancer.server.port=80" #UNIQUE
      - "traefik.docker.network=traefik_frontend, traefik_backend"

networks:
  traefik_frontend:
    name: traefik_frontend
    driver: overlay
    attachable: true
    external: true
  traefik_backend:
    name: traefik_backend
    driver: overlay
    attachable: true
    external: true

You should not use ports: with your internal containers, you are exposing them to the whole Internet. Just attach them to a Docker network, then no ports is required, the ports are reachable automatically within the Docker network. Connect to WordPress and the DB via the compose service name.

I only see a single site, so I don't know what is not working. Note that you can't just place WordPress on a different domain/path, as it has saved the initial one and will always redirect back to it. It needs to be changed within the database.