Wildcard certificates not being used when issued

I am using the following docker compose file to deploy traefik on a swarm cluster.

version: "3.7"

services:
  traefik:
    image: traefik:v2.1
    command:
      - "--api.dashboard=true"
      - "--accesslog=true"
      - "--log.level=INFO"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.swarmMode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=traefik-public"
      - "--providers.file.watch=true"
      - "--providers.file.filename=/file_provider.yml"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.dnsChallenge.provider=cloudflare"
      - "--certificatesresolvers.letsencrypt.acme.dnsChallenge.delayBeforeCheck=15"
      - "--certificatesresolvers.letsencrypt.acme.dnsChallenge.resolvers=1.1.1.1:53,1.0.0.1:53"
      - "--certificatesresolvers.letsencrypt.acme.email=user@domain.tld"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - 80:80
      - 443:443
    volumes:
      - traefik-certificates:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik-public
    environment:
      - "CF_API_EMAIL=user@domain.tld"
      - "CF_API_KEY=api-key"
    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - "traefik.docker.lbswarm=true"
        - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
        - "traefik.http.routers.http-catchall.entrypoints=web"
        - "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
        - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
        - "traefik.http.routers.api.tls.certresolver=letsencrypt"
        - "traefik.http.routers.api.tls.domains[0].main=*.domain.tld"
        - "traefik.http.routers.api.tls.domains[0].sans=domain.tld"
        - "traefik.http.routers.api.rule=Host(`management.domain.tld`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
        - "traefik.http.routers.api.service=api@internal"
        - "traefik.http.services.api.loadbalancer.server.port=8080"
    configs:
      - file_provider.yml

volumes:
  traefik-certificates:

configs:
  file_provider.yml:
    file: /home/access/docker/traefik-provider.yml

networks:
  traefik-public:
    external: true

I am trying to switch to wildcard certificates over individual certificates for each subdomain. The wildcard certificate is issued successfully for *.domain.tld and domain.tld, but a certificate is also issued for management.domain.tld from the host rule definition. When I navigate to the site, the TLS certificate issued is for management.domain.tld, not *.domain.tld. How do I get Traefik to use the wildcard certificate instead of the one from the host rule?

I am also having this issue. It not only generates a wildcard cert, but also a separate certificate for each service that I have as well.

You have a similar issue?

Maybe share your full Traefik static and dynamic config, and docker-compose.yml if used.

docker compose file

  traefik: 
    container_name: traefik
    image: traefik:latest
    restart: always
    logging: *loki-logging  
    ports:
      - 80:80
      - 443:443
      - 5900:5900
      - 8081:8080
    environment:
      - CF_ZONE_API_TOKEN=${TRAEFIK__CF_ZONE_API_TOKEN}
      - CF_DNS_API_TOKEN=${TRAEFIK__CF_DNS_API_TOKEN}
    security_opt:
      - no-new-privileges:true
    command:
      # - --log.level=DEBUG
      - --api.insecure=true  # FIXME
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.exposedByDefault=false
      - --providers.file.filename=/etc/traefik/config.yml
      - --providers.file.watch=true

      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.web.http.redirections.entryPoint.permanent=true
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls.certResolver=le
      - --entrypoints.websecure.http.middlewares=default-headers@file
      - --entrypoints.idrac.address=:5900

      - --certificatesresolvers.le.acme.storage=acme.json
      - --certificatesresolvers.le.acme.email=${EMAIL}
      - --certificatesresolvers.le.acme.dnschallenge=true
      - --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare
      - --certificatesresolvers.le.acme.dnschallenge.resolvers=carl.ns.cloudflare.com:53,lara.ns.cloudflare.com:53,1.1.1.1:53,1.0.0.1:53
      - --certificatesresolvers.le.acme.dnschallenge.delaybeforecheck=20
      - --certificatesResolvers.le.acme.httpChallenge=true  # needed for duckdns domains, wildcard does not work with httpChallenge
      - --certificatesResolvers.le.acme.httpChallenge.entryPoint=websecure

      - --entrypoints.websecure.http.tls.domains[0].main=${DOMAIN}
      - --entrypoints.websecure.http.tls.domains[0].sans=*.${DOMAIN}
      - --entrypoints.websecure.http.tls.domains[1].main=${DOMAIN_2}

      - --serversTransport.insecureSkipVerify=true

      - --experimental.plugins.plugin-log4shell.modulename=github.com/traefik/plugin-log4shell
      - --experimental.plugins.plugin-log4shell.version=v0.1.2
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.entrypoints=websecure
      - traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`, `proxy.${DOMAIN}`)
      - traefik.http.routers.traefik.service=traefik
      - traefik.http.services.traefik.loadbalancer.server.port=8080
      - traefik.http.routers.traefik.tls=true
      - traefik.http.routers.traefik.tls.certResolver=le

      # FIXME remove?
      # - traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ${PWD}/config/traefik/acme.json:/acme.json
      - ${PWD}/config/traefik/:/etc/traefik/

docker compose label for another service with traefik enabled

    labels:
      - traefik.enable=true
      - traefik.http.routers.whoogle.entrypoints=websecure
      - traefik.http.routers.whoogle.rule=Host(`search.${DOMAIN}`)
      - traefik.http.routers.whoogle.tls=true
      - traefik.http.routers.whoogle.tls.certResolver=le

I think I have figured it out though it doesn't make a lot of sense as to why it needs to be defined like this- I have added these labels to the traefik container on another machine and it seems to have done the trick, though it still generates some regular certs before creating the wildcard cert. I manually removed the site-specific certs from acme.json and everything seems to work with the wildcard, though I'm not sure what will happen when it tries to renew in a few months.

      - traefik.enable=true
      # https
      # - traefik.http.routers.websecure.tls=true
      # - traefik.http.routers.websecure.entrypoints=https
      # - traefik.http.routers.websecure.rule=Host(`traefik.local.mydomain.com`)
      # wildcard certs
      - traefik.http.routers.websecure.tls.certresolver=le
      - traefik.http.routers.websecure.tls.domains[0].main=${ROOT_DOMAIN}
      - traefik.http.routers.websecure.tls.domains[0].sans=*.${ROOT_DOMAIN}

I only use config.yml to define additional services that cannot be created directly inside the docker compose file.

This can not work, only one challenge, remove both http lines:

As far as I can tell, it does- I added that back since getting the wildcard going:

I have not seen the same certresolver le use multiple challenges. I think one will overwrite the other. Check acme.json which certs exist.

I can confirm that not only does it renew properly without adding additional single-domain certs, but I was able to add other completely different domains that use the http challenge (along side the dns challenge) and was able to generate valid certs. Hopefully this can help someone