# Routing between two traefiks (splited by constraints)

**URL:** <https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737>\
**Category:** Traefik v2\
**Tags:** docker-swarm\
**Created:** [September 4, 2023, 11:56pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737 "2023-09-04T23:56:32Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![maycon](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/maycon/32/7536_2.png) [@maycon](https://community.traefik.io/u/maycon)\
**Post date:** [September 4, 2023, 11:56pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/1 "2023-09-04T23:56:32Z")

</div>

I have two Traefiks (T1 & T2), each one with their constraints. So, basically two environments, but on the same Docker Swarm infrastructure.

I want to create a entry on the first one (T1) to route to a service on the second one. I think it could be done by using file provider, such the following example:

```yaml
  services:
    route-to-service-on-t1:
      loadbalancer:
        servers:
          - url: http://my-service-name-here/
        passhostheader: true

```

I didn't test it, by when connect on the T1 I was able to execute `curl http://my-service-name-here/`. But I'd like to do it by using the labels.

I know that `services.[service-name].loadbalancer.servers[x].url` is not available on Docker Swarm (even when not using the IP address, but the service name). Is there a way to configure on T1 a router to a service linked to T2? I cant configure directly on the service, because it does not have the T1 constraint, so the service cannot "see" T1.

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [September 5, 2023, 4:54am UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/2 "2023-09-05T04:54:50Z")

</div>

Sure, `loadbalancer.servers.url` is available in Docker Swarm. It is just not available in Docker dynamic config via labels, you need to use `providers.file` with a dynamic config file.

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [September 5, 2023, 8:21am UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/3 "2023-09-05T08:21:24Z")

</div>

Shouldn’t it work with Configuration Discovery and a constraint for both services? ([Doc](https://doc.traefik.io/traefik/providers/docker/#constraints))

Here is a simple example, that doesn't fully utilize TLS, you would need to setup a wildcard cert (with LetsEncrypt). And the rule in `traefik-dynamic.yml` could be improved, using something like `*.lab.example.com`.

`traefik-ext` listens externally on 80 and 443, creates TLS certs. It recognizes services with `traefik.ext=true` label. Every request not matching the discovered "ext" services will be forwarded to `traefik-int` via the `traefik-dynamic.yml` configuration file.

`traefik-int` only listens in Docker network internally on port 80, no TLS, discovers services using `traefik.int=true` label.

docker-compose.yml:

```auto
version: '3.9'

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

volumes:
  traefik-certificates:

configs:
  traefik-dynamic.yml:
    file: traefik-dynamic.yml

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
    configs:
      - traefik-dynamic.yml
    command:
      - --providers.docker=true
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy-ext
      - --providers.docker.constraints=Label(`traefik.ext`,`true`)
      - --providers.file.filename=/traefik-dynamic.yml
      - --providers.file.watch=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=INFO
      - --accesslog=true
      - --certificatesResolvers.myresolver.acme.email=mail@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=INFO
      - --accesslog=true
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
      labels:
        - traefik.int=true
        - traefik.enable=true
        - traefik.http.routers.traefik-int.entrypoints=web
        - 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

  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

```

traefik-dynamic.yml:

```auto
http:
  routers:
    forward-all:
      rule: PathPrefix(`/`)
      service: forward-all
  services:
    forward-all:
      loadbalancer:
        servers:
          - url: http://traefik-int/

```

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [September 5, 2023, 10:13am UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/4 "2023-09-05T10:13:56Z")

</div>

Here is another template using only a docker-compose file.

`traefik-int` is labeled with `traefik.ext=true`, so it is automatically picked up by `traefik-ext`, and using entrypoint `websecure`, it is (incl. `/dashboard/`) practically available externally.

Again, it's missing a TLS wildcard certresolver for `traefik-ext` and all requests unknown to `traefik-ext` are passed to `traefik-int` using `rule=PathPrefix(`/`)`.

Other "internal" services must use label `traefik.int=true` and entrypoint `web`.

```auto
version: '3.9'

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

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=INFO
      - --accesslog=true
      - --certificatesResolvers.myresolver.acme.email=mail.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=INFO
      - --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

```

---

<div class="post-metadata">

**Author:** ![maycon](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/maycon/32/7536_2.png) [@maycon](https://community.traefik.io/u/maycon)\
**Post date:** [September 5, 2023, 3:32pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/5 "2023-09-05T15:32:42Z")

</div>

Hi @bluepuma77.

Thank you for your help. It worked perfectly to my propose. 🙂

I just had to make a small change on your approach, because since both traefik are referencing `api@internal`, they were showing the same result (from the external one).

My workaround was to enable the `--api.insecure=true` and use the `port=8080` on the internal Traefik. Of course I will have to create the middlewares (`auth` and `ipwhitelist`) to do not expose it to the other services inside the swarm.

My question is: was my approach the best solution? Is there another way to reference the `api@internal` on the internal traefik without conflicting with the external one?

---

<div class="post-metadata">

**Author:** ![maycon](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/maycon/32/7536_2.png) [@maycon](https://community.traefik.io/u/maycon)\
**Post date:** [September 5, 2023, 3:55pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/6 "2023-09-05T15:55:38Z")

</div>

I've just figure out that my approach to protect the API makes no sense. It will be applied to the proxy layer (accessing from outside). Another service could still access the traefik API (traefik-int:8080), even with whitelist and auth. ☹

Back to the doc/google/whatever. 🙂

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [September 5, 2023, 5:55pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/7 "2023-09-05T17:55:12Z")

</div>

The first one with `traefik-dynamic.yml` has a completely separate `traefik-int`, there dashboard should work with auth.

Note: add `attachable: true` to the network definition if you want other services in different compose files to work with Traefik.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex020/uploads/containo/original/2X/b/bd81ebdb578656e76e56ff3cc3eed021d3ba132d.png) [@system](https://community.traefik.io/u/system)\
**Post date:** [September 8, 2023, 5:55pm UTC](https://community.traefik.io/t/routing-between-two-traefiks-splited-by-constraints/19737/8 "2023-09-08T17:55:21Z")

</div>

Closed on September 8, 2023, 5:55pm UTC

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.
