Works great with docker as a provider but not with docker-swarm

Hello,

I'm trying to setup a personnal server where I can host all the web apps I am working on and use traefik as a reverse proxy for now.
I successfully managed to setup traefik with let's encrypt and a wildcard.
Now I want to do the same with docker-swarm so I can have multi-container application isolated from each other.
I naively thought that all I would need is to move the labels in the deploy section of my docker-compose.yaml and add the loadbalancer.server.port key for swarm.

All i get is a 404 when I access my subdomain on port 80 and a Gateway Timeout on https.

Here are my config files :

traefik.yaml :

log:
  level: DEBUG

api:
  dashboard: true

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

providers:
  docker:
    exposedByDefault: false
    swarmMode: true
    endpoint: "unix:///var/run/docker.sock"

certificatesResolvers:
  ovhcert:
    acme:
      email: bar@foo.com
      storage: acme.json
      dnsChallenge:
        provider: ovh
        delayBeforeCheck: 10

traefik docker-compose

version: '3'

services:
  traefik:
    image: traefik:2.1
    ports:
      - 80:80
      - 8080:8080
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - $PWD/traefik.yml:/etc/traefik/traefik.yml
      - $PWD/acme.json:/acme.json
    environment:
      - OVH_ENDPOINT=ovh-eu
      - OVH_APPLICATION_KEY=xxxx
      - OVH_APPLICATION_SECRET=xxxxx
      - OVH_CONSUMER_KEY=xxxxx
    deploy:
      labels:
        - "traefik.http.routers.api.rule=Host(`traefik.mydomain.com`)"
        - "traefik.http.routers.api.service=api@internal"
        - "traefik.http.routers.api.middlewares=auth"
        - "traefik.http.routers.api.entrypoints=websecure"
        - "traefik.http.routers.api.tls.certresolver=ovhcert"
        - "traefik.http.services.api@internal.loadbalancer.server.port=80"
        - "traefik.enable=true"

test app docker-compose.yaml

version: '3'
services:
    hello:
        image: tutum/hello-world
        deploy:
          labels:
            - "traefik.enable=true"
            - "traefik.http.routers.hello.rule=Host(`hello.mydomain.com`)"
            - "traefik.http.routers.hello.entrypoints=websecure"
            - "traefik.http.routers.hello.tls.certresolver=ovhcert"
            - "traefik.http.routers.hello.service=hello"
            - "traefik.http.services.hello.loadbalancer.server.port=80"

I think I am missing something obvious but I definitely can't tell what. Hoping you can help.

Thanks !

I think you haven't defined any networks, thus there is no route. In my docker-compose files, for both Traefik and my app, I have defined them as traefik-public. And of course you need to create the network in Docker first as an overlay network.

compose:

    networks:
      - traefik-public

Also, I'm not sure why you put "traefik.http.routers.hello.service=hello" in there. You're referencing the service in the service.

Thank you for your answer.

I thought I understood from the documentation (provider/docker) that Traefik is creating a default network and so there is no need to explicitly declare it in the compose file unless you want to override it.
I didn't declare the network either when I wasn't in swarm mode and it worked perfectly. Does swarm have a subtlety that I am overlooking ?

The hello.service=hello line is a remnant of a previous test, I will remove it. :slight_smile:

Thanks !

Indeed, with an overlay network, it works as intended. Thanks @braham2019.

If it can help someone, this is what I have in the end :

docker network create -d overlay --attachable proxy

traefik docker-compose.yaml

services:
  traefik:
    image: traefik:2.1
    ...
    deploy:
      labels:
        ...
        - "traefik.docker.network=proxy"
    networks:
        - proxy

networks:
  proxy:
    external: true

test app docker-compose.yaml

services:
    hello:
         ...
          labels:
            ...
            - "traefik.docker.network=proxy"
        networks:
          - proxy

networks:
    proxy:
        external: true