How do I setup multiple Traefiks, with one domain, and one external IP

Hello everyone, I'm trying to have a setup where I can have an ingress Traefik instance that redirects to a specific Traefik instance on another server in the LAN, using one domain and with a docker setup on multiple hosts, so no Kubernetes.

The problem is that the Ingress Traefik does not have a way to know to which Traefik instance redirect a request since all the instances use the same domain, the only way is to manually have each subdomain in a file provider, but my objective is to have a docker provider on each instance and then have the Ingress Traefik figure out somehow how to deal with incoming requests so I don't have to maintain a manual list of subdomains, is this possible?

Bonus question: How can I share the certificate between all the instances since it is a wildcard certificate?

You could just use Docker Swarm to connect the nodes to a common Docker network, then you only need one Traefik instance. See undocumented simple Traefik Swarm example.

If you want multi-level Traefik, you need to make up your mind first how you want to use TLS. Ingress needs to have a cert to be able to use Host() or HostSNI() to match the URL and forward it accordingly. I would use Ingress Traefik to terminate TLS, so have LetsEncrypt there, then only forward decrypted http requests to the other instances.

I am pretty sure I created an example docker-compose.yml of chained Traefik here (or on Docker forum), but I can't find it, too many posts created :smile:

Found the config :slight_smile:, to be used with docker stack deploy:

version: '3.9'

networks:
  proxy-ext:
    name: proxy-ext
    driver: overlay
    attachable: true
  proxy-int:
    name: proxy-int
    driver: overlay
    attachable: true


volumes:
  traefik-certificates:


services:
  traefik-ext:
    image: traefik:v2.10
    hostname: '{{.Node.Hostname}}'
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
    networks:
      - proxy-ext
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-certificates:/certificates
    command:
      - --providers.docker=true
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy-ext
      - --providers.docker.constraints=Label(`traefik.ext`,`true`)
      - --entryPoints.web.address=:80
      - --entryPoints.web.http.redirections.entryPoint.to=websecure
      - --entryPoints.web.http.redirections.entryPoint.scheme=https
      - --entryPoints.websecure.address=:443
      - --entryPoints.websecure.http.tls=true
      - --entryPoints.websecure.http.tls.certResolver=myresolver
      - --api.debug=true
      - --api.dashboard=true
      - --log.level=DEBUG
      - --accesslog=true
      - --certificatesResolvers.myresolver.acme.email=me@example.com
      - --certificatesResolvers.myresolver.acme.storage=/certificates/acme.json
      - --certificatesresolvers.myresolver.acme.tlschallenge=true
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
      labels:
        - traefik.ext=true
        - traefik.enable=true
        - traefik.http.routers.traefik-ext.entrypoints=websecure
        - traefik.http.routers.traefik-ext.rule=Host(`traefik-ext.example.com`)
        - traefik.http.routers.traefik-ext.service=api@internal
        - traefik.http.routers.traefik-ext.middlewares=auth-ext
        - 'traefik.http.middlewares.auth-ext.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/'
        - traefik.http.services.dummy-svc.loadbalancer.server.port=9999


  traefik-int:
    image: traefik:v2.10
    hostname: '{{.Node.Hostname}}'
    networks:
      - proxy-ext
      - proxy-int
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    command:
      - --providers.docker=true
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy-int
      - --providers.docker.constraints=Label(`traefik.int`,`true`)
      - --entryPoints.web.address=:80
      - --entryPoints.web.forwardedHeaders.insecure=true
      - --api.debug=true
      - --api.dashboard=true
      - --log.level=DEBUG
      - --accesslog=true
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
      labels:
        - traefik.ext=true
        - traefik.enable=true
        - traefik.http.routers.traefik-int.entrypoints=websecure
        - traefik.http.routers.traefik-int.rule=Host(`traefik-int.example.com`)
        - traefik.http.routers.traefik-int.service=api@internal
        - traefik.http.routers.traefik-int.middlewares=auth-int
        - 'traefik.http.middlewares.auth-int.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/'
        - traefik.http.services.dummy-svc.loadbalancer.server.port=9999
        - traefik.http.routers.traefik-fwd.entrypoints=websecure
        - traefik.http.routers.traefik-fwd.rule=PathPrefix(`/`)
        - traefik.http.routers.traefik-fwd.service=fwd
        - traefik.http.services.fwd.loadbalancer.server.port=80



  whoami-ext:
    hostname: '{{.Node.Hostname}}'
    image: traefik/whoami:v1.10
    networks:
      - proxy-ext
    deploy:
      mode: global
      labels:
        - traefik.ext=true
        - traefik.enable=true
        - traefik.http.routers.whoami-ext.entrypoints=websecure
        - traefik.http.routers.whoami-ext.rule=Host(`whoami-ext.example.com`)
        - traefik.http.services.whoami-ext.loadbalancer.server.port=80


  whoami-int:
    hostname: '{{.Node.Hostname}}'
    image: traefik/whoami:v1.10
    networks:
      - proxy-int
    deploy:
      mode: global
      labels:
        - traefik.int=true
        - traefik.enable=true
        - traefik.http.routers.whoami-int.entrypoints=web
        - traefik.http.routers.whoami-int.rule=Host(`whoami-int.example.com`)
        - traefik.http.services.whoami-int.loadbalancer.server.port=80

@bluepuma77 Can you explain what "hostname: '{{.Node.Hostname}}'" does or link me to documentation on that? I don't even know what to call that to search for myself.

It will set the hostname within the container to the hostname of the parent node (doc). So the container "knows" which host it is on.

1 Like

Hi folks,

I think I have a similar use case.

I'm running Traefik on my main server to route traffic to various Docker-based apps. My landing page is a dashboard app like Homarr, which makes navigation easy.

IP addresses are assigned dynamically, and my router handles local DNS resolution based on hostnames, so I don't need to keep track of IPs and ports manually. It’s a pretty foolproof setup so far.

Now, I’m extending the network with edge devices. These will host Docker-based apps as well, and I plan to run Traefik on each of them. Some edge apps will provide local interaction or specific connectivity services.

My goal is to make all these distributed apps accessible through a single dashboard on the main server. So the Traefik instance running on the main server must be able to discover the Container running on the edge devices.

Is the solution discussed here (with multiple Traefik instances sharing one domain and external IP) the right approach for this scenario?

Thanks!

With Docker Swarm you can create an overlay network and attach all services/container to it, have a single Traefik instance discover them and proxy/forward to them.

1 Like

Thx for the quick response :blush:.

So only a single instance which runs on the main server, isn't it?

Yes, one instance where requests are coming in. Should be a Swarm manager or you need a Docker Socket Proxy on the manager to be accessible by Traefik. Check simple Traefik Swarm example.

Note that Docker Swarm usually wants 3 manager nodes to be HA. But you can run workloads on managers like in regular workers.

thx for the remark.
I'll have two edge devices and the main device, so no workaround necessary :slight_smile: