Whoami under subdomain

Hi,
Here is the simplest compose I could come up with that accesses a sample service(whoami) through traefik with http to https redirect. This is being deployed as a stack to a swarm.

version: "3.3"
networks:
  routing:
    driver: overlay
volumes:
  traefik-data:
    driver: local
  ssl-certs:
    driver: local
  influxdb-data:
    driver: local
services:
  traefik:
    image: "traefik:v2.10.1"
    command:
      # TRAEFIK PROXY STATIC CONFIGURATION:
      - "--global.checkNewVersion=true"
      - "--global.sendAnonymousUsage=true"
      - "--log.level=ERROR"
      - "--providers.docker=true"
      - "--api=true"
      - "--api.debug=true" # DEBUG ONLY
      - "--api.insecure=true"
      - "--api.dashboard=true"
      - "--providers.docker.exposedbydefault=true"

      # entrypoints
      - "--entrypoints.websecure"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls.certresolver=staging"
      - "--entrypoints.web"
      - "--entrypoints.web.address=:80"

      # # redirect http to https
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"

      # certificate resolvers
      - "--certificatesResolvers.staging"
      - "--certificatesResolvers.staging.acme.email=hraccesky@gmail.com"
      - "--certificatesResolvers.staging.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesResolvers.staging.acme.httpChallenge.entryPoint=websecure"

      # - "--certificatesResolvers.production"
      # - "--certificatesResolvers.production.acme.email=hraccesky@gmail.com"
      # - "--certificatesResolvers.production.acme.storage=/etc/traefik/certs/acme.json"
      # - "--certificatesResolvers.production.acme.caServer=https://acme-v02.api.letsencrypt.org/directory"
      # - "--certificatesResolvers.production.acme.httpChallenge.entryPoint=websecure"

      # InfluxDB metrics collection
      - "--metrics.influxDB2"
      - "--metrics.influxDB2.address=http://influx:8086"
      # SECURITY: FIXME:
      - "--metrics.influxDB2.token=8SKVmszA-V8bI5eLohzG8gQX33xWBZIYcZ-bPij2IDF1_yfrhn1cc61KqkUhK18Y949R0ba-b-gnGTfJBNTeSQ=="
      - "--metrics.influxDB2.org=traefik"
      - "--metrics.influxDB2.bucket=traefik-metrics-1"
      - "--metrics.influxDB2.addEntryPointsLabels=true"
      - "--metrics.influxDB2.addRoutersLabels=true"
      - "--metrics.influxDB2.addServicesLabels=true"
      - "--metrics.influxDB2.pushInterval=3s"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "ssl-certs:/ssl-certs"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - routing
      - default
    depends_on:
      - influx
  influx: # for traefik metrics
    image: influxdb:2.7.1-alpine
    # env_file:
    #   - .env
    environment:
      # SECURITY: FIXME:
      - DOCKER_INFLUXDB_INIT_USERNAME=<username>
      - DOCKER_INFLUXDB_INIT_PASSWORD=<password>
      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=<token>

      - DOCKER_INFLUXDB_INIT_ORG=traefik
      - DOCKER_INFLUXDB_INIT_BUCKET=traefik-metrics-1
      - DOCKER_INFLUXDB_INIT_MODE=setup
    volumes:
      - influxdb-data:/var/lib/influxdb2:rw
    # DEBUG ONLY:
    ports:
      - 8086:8086 # web UI default port
  whoami:
    image: "traefik/whoami"
    labels:
      ## works:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami"
      - "traefik.http.routers.whoami.rule=Host(`swarm.local`) && PathPrefix(`/whoami`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls=true"
      - "traefik.http.routers.whoami.tls.certresolver=staging"
      ## Doesn't work:
      - "traefik.http.routers.whoami-subdomain"
      - "traefik.http.routers.whoami-subdomain.rule=Host(`whoami.swarm.local`)"
      - "traefik.http.routers.whoami-subdomain.entrypoints=websecure"
      - "traefik.http.routers.whoami-subdomain.tls=true"
      - "traefik.http.routers.whoami-subdomain.tls.certresolver=staging"
    networks:
      - routing
      - default

The first router(whoami) works fine, and I can access whoami at swarm.local/whoami, the second one does not work.
Here are the logs:

time="2023-06-25T09:50:14Z" level=info msg="Configuration loaded from flags."
time="2023-06-25T09:50:14Z" level=error msg="service \"swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka\" error: port is missing" providerName=docker container=swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka-70ddd823844959945e414925d49a202fcb8c3131d5514739430939de286851dc
time="2023-06-25T09:50:16Z" level=error msg="service \"swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka\" error: port is missing" providerName=docker container=swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka-70ddd823844959945e414925d49a202fcb8c3131d5514739430939de286851dc
time="2023-06-25T09:50:16Z" level=error msg="service \"swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka\" error: port is missing" providerName=docker container=swirl-manager-agent-kurq8rtcrt20kjn6jqytdkrcp-rgaz1zez7nvhgjlqzaaguq1ka-70ddd823844959945e414925d49a202fcb8c3131d5514739430939de286851dc
time="2023-06-25T09:50:18Z" level=error msg="the service \"whoami@docker\" does not exist" entryPointName=websecure routerName=whoami-subdomain@docker
time="2023-06-25T09:50:21Z" level=error msg="Unable to obtain ACME certificate for domains \"swirl-prometheus-1-mabadbpij4rbxw2dxno5g6zz9\": unable to generate a certificate for the domains [swirl-prometheus-1-mabadbpij4rbxw2dxno5g6zz9]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"swirl-prometheus-1-mabadbpij4rbxw2dxno5g6zz9\": Domain name needs at least one dot" rule="Host(`swirl-prometheus-1-mabadbpij4rbxw2dxno5g6zz9`)" providerName=staging.acme ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" routerName=websecure-swirl-prometheus-1-mabadbpij4rbxw2dxno5g6zz9@docker
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"traefik-traefik-1-wn5df636xbycpeeiq4k47tmii\": unable to generate a certificate for the domains [traefik-traefik-1-wn5df636xbycpeeiq4k47tmii]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"traefik-traefik-1-wn5df636xbycpeeiq4k47tmii\": Domain name needs at least one dot" routerName=websecure-traefik-traefik-1-wn5df636xbycpeeiq4k47tmii@docker rule="Host(`traefik-traefik-1-wn5df636xbycpeeiq4k47tmii`)" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" providerName=staging.acme
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"gitea-maria-1-0b0dvwfzujwy886oq5g1txofw\": unable to generate a certificate for the domains [gitea-maria-1-0b0dvwfzujwy886oq5g1txofw]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"gitea-maria-1-0b0dvwfzujwy886oq5g1txofw\": Domain name needs at least one dot" rule="Host(`gitea-maria-1-0b0dvwfzujwy886oq5g1txofw`)" providerName=staging.acme ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" routerName=websecure-gitea-maria-1-0b0dvwfzujwy886oq5g1txofw@docker
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"swirl-cadvisor-kurq8rtcrt20kjn6jqytdkrcp-h6mi30yhnrcir96jglxf7frd5\": unable to generate a certificate for the domains [swirl-cadvisor-kurq8rtcrt20kjn6jqytdkrcp-h6mi30yhnrcir96jglxf7frd5]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: NewOrder request did not include a SAN short enough to fit in CN" rule="Host(`swirl-cadvisor-kurq8rtcrt20kjn6jqytdkrcp-h6mi30yhnrcir96jglxf7frd5`)" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" providerName=staging.acme routerName=websecure-swirl-cadvisor-kurq8rtcrt20kjn6jqytdkrcp-h6mi30yhnrcir96jglxf7frd5@docker
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"traefik-influx-1-zl3tgjw4oajd39ufubcpl2fkq\": unable to generate a certificate for the domains [traefik-influx-1-zl3tgjw4oajd39ufubcpl2fkq]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"traefik-influx-1-zl3tgjw4oajd39ufubcpl2fkq\": Domain name needs at least one dot" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" providerName=staging.acme rule="Host(`traefik-influx-1-zl3tgjw4oajd39ufubcpl2fkq`)" routerName=websecure-traefik-influx-1-zl3tgjw4oajd39ufubcpl2fkq@docker
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"swirl-swirl-1-0z8rra0nqavqqih8ertyyjxld\": unable to generate a certificate for the domains [swirl-swirl-1-0z8rra0nqavqqih8ertyyjxld]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"swirl-swirl-1-0z8rra0nqavqqih8ertyyjxld\": Domain name needs at least one dot" providerName=staging.acme ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" routerName=websecure-swirl-swirl-1-0z8rra0nqavqqih8ertyyjxld@docker rule="Host(`swirl-swirl-1-0z8rra0nqavqqih8ertyyjxld`)"
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"swarm.local\": unable to generate a certificate for the domains [swarm.local]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"swarm.local\": Domain name does not end with a valid public suffix (TLD)" providerName=staging.acme ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" routerName=whoami@docker rule="Host(`swarm.local`) && PathPrefix(`/whoami`)"
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"whoami.swarm.local\": unable to generate a certificate for the domains [whoami.swarm.local]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"whoami.swarm.local\": Domain name does not end with a valid public suffix (TLD)" routerName=whoami-subdomain@docker rule="Host(`whoami.swarm.local`)" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" providerName=staging.acme
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"minecraft-minecraft-server-1-wgega656tsvdwwrbvx47tn7fs\": unable to generate a certificate for the domains [minecraft-minecraft-server-1-wgega656tsvdwwrbvx47tn7fs]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"minecraft-minecraft-server-1-wgega656tsvdwwrbvx47tn7fs\": Domain name needs at least one dot" rule="Host(`minecraft-minecraft-server-1-wgega656tsvdwwrbvx47tn7fs`)" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory" providerName=staging.acme routerName=websecure-minecraft-minecraft-server-1-wgega656tsvdwwrbvx47tn7fs@docker
time="2023-06-25T09:50:22Z" level=error msg="Unable to obtain ACME certificate for domains \"gitea.swarm.local\": unable to generate a certificate for the domains [gitea.swarm.local]: acme: error: 400 :: POST :: https://acme-staging-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier :: Error creating new order :: Cannot issue for \"gitea.swarm.local\": Domain name does not end with a valid public suffix (TLD)" providerName=staging.acme routerName=gitea-router@docker rule="Host(`gitea.swarm.local`)" ACME CA="https://acme-staging-v02.api.letsencrypt.org/directory"

When using Docker Swarm, you need to enable swarmMode and place labels under deploy, see doc.

- "--providers.docker.swarmMode=true" made whoami disappear in the traefik dashboard.
Once again, here is the compose file so you can repro:

version: "3.3"
networks:
  routing:
    driver: overlay
volumes:
  influxdb2_data:
    driver: local
  influxdb_config:
    driver: local
  ssl_certs:
    driver: local
services:
  traefik:
    image: "traefik:v2.10.1"
    command:
      # TRAEFIK PROXY STATIC CONFIGURATION:
      - "--global.checkNewVersion=true"
      - "--global.sendAnonymousUsage=false"
      # - "--log.level=DEBUG"
      # - "--log.level=INFO"
      # - "--log.level=WARNING"
      - "--log.level=ERROR"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.network=routing"
      - "--providers.docker.swarmMode=true"
      - "--providers.docker.exposedByDefault=true"
      - "--providers.docker.swarmModeRefreshSeconds=5"
      - "--api=true"
      - "--api.debug=true" # DEBUG ONLY
      - "--api.insecure=true"
      - "--api.dashboard=true"

      # entrypoints
      - "--entrypoints.websecure"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls.certresolver=staging"
      - "--entrypoints.web"
      - "--entrypoints.web.address=:80"
      # - "--entrypoints.internal"
      # - "--entrypoints.internal.address=:8080"

      # # redirect http to https
      # - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      # - "--entrypoints.web.http.redirections.entryPoint.scheme=https"

      # certificate resolvers
      - "--certificatesResolvers.staging"
      - "--certificatesResolvers.staging.acme.email=hraccesky@gmail.com"
      - "--certificatesResolvers.staging.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesResolvers.staging.acme.httpChallenge.entryPoint=websecure"

      - "--certificatesResolvers.production"
      - "--certificatesResolvers.production.acme.email=hraccesky@gmail.com"
      - "--certificatesResolvers.production.acme.storage=/etc/traefik/certs/acme.json"
      - "--certificatesResolvers.production.acme.caServer=https://acme-v02.api.letsencrypt.org/directory"
      - "--certificatesResolvers.production.acme.httpChallenge.entryPoint=websecure"

      # InfluxDB metrics collection
      - "--metrics.influxDB2"
      - "--metrics.influxDB2.address=http://influx:8086"
      # SECURITY: FIXME:
      - "--metrics.influxDB2.token=8SKVmszA-V8bI5eLohzG8gQX33xWBZIYcZ-bPij2IDF1_yfrhn1cc61KqkUhK18Y949R0ba-b-gnGTfJBNTeSQ=="
      - "--metrics.influxDB2.org=traefik"
      - "--metrics.influxDB2.bucket=traefik-metrics-1"
      - "--metrics.influxDB2.addEntryPointsLabels=true"
      - "--metrics.influxDB2.addRoutersLabels=true"
      - "--metrics.influxDB2.addServicesLabels=true"
      - "--metrics.influxDB2.pushInterval=3s"
      # TODO: prometheus metrics collection
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "ssl_certs:/ssl-certs"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - routing
    depends_on:
      - influx
      - routing
  influx: # for traefik metrics
    image: influxdb:2.7.1-alpine
    environment:
      # SECURITY: FIXME:
      - DOCKER_INFLUXDB_INIT_USERNAME=admin
      # SECURITY: FIXME:
      - DOCKER_INFLUXDB_INIT_PASSWORD=adminadmin # has to have 8 characters
      # SECURITY: FIXME:
      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=8SKVmszA-V8bI5eLohzG8gQX33xWBZIYcZ-bPij2IDF1_yfrhn1cc61KqkUhK18Y949R0ba-b-gnGTfJBNTeSQ==

      - DOCKER_INFLUXDB_INIT_ORG=traefik
      - DOCKER_INFLUXDB_INIT_BUCKET=traefik-metrics-1
      - DOCKER_INFLUXDB_INIT_MODE=setup
    volumes:
      - influxdb2_data:/var/lib/influxdb2:rw
      - influxdb_config:/etc/influxdb2
    # DEBUG ONLY:
    # DEBUG ONLY:
    ports:
      - 8086:8086 # web UI default port


    # TODO:.network=routing proxy labels
    # labels:
    #   - "traefik.enable=true"
    #   - "traefik.http.routers.influxdb2"
    #   - "traefik.http.routers.influxdb2.rule=PathPrefix(`/influxdb2`)"
    #   - "traefik.http.routers.influxdb2.entrypoints=influx"
    #   - "traefik.http.routers.influxdb2.tls=true"
    #   - "traefik.http.routers.influxdb2.tls.certresolver=staging"
    networks:
      - routing
    depends_on:
      - routing
  whoami:
    image: "traefik/whoami"
    ports:
      - "25545:80"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami_http"
      - "traefik.http.routers.whoami_http.rule=Host(`somedomain.local`)"
      - "traefik.http.routers.whoami_http.entrypoints=web"
      - "traefik.http.services.whoami_http.loadbalancer.server.port=80"
      # - "traefik.http.routers.whoami"
      # - "traefik.http.routers.whoami.rule=Host(`somedomain.local`) && PathPrefix(`/whoami`)"
      # - "traefik.http.routers.whoami.entrypoints=websecure"
      # - "traefik.http.routers.whoami.tls=true"
      # - "traefik.http.routers.whoami.tls.certresolver=staging"
    networks:
      - routing
    depends_on:
    depends_on:
      - routing

I've turned off the https redirect to make it simpler.
Is this a bug?

If you use docker stack deploy, you should have a deploy section inside the service, labels need to go inside deploy.

Did you look at the example in doc?

version: "3"
services:
  my-container:
    deploy:
      labels:
        - traefik.http.routers.my-container.rule=Host(`example.com`)
        - traefik.http.services.my-container-service.loadbalancer.server.port=8080