Wildcard Tunnel - Traefik

I’m trying to configure a cf tunnel with a wildcard CNAME (*.mydomain.org) to send traffic to Traefik. I have the tunnel configured and the Traefik instance defined in the hostname for the service. However, whenever I disable the forwarded ports on my router to use the tunnel, all of my services become inaccessible. I’m not sure what I’m missing.

Wildcard CNAME:

Docker Compose Traefik Config:

  traefik:
    container_name: traefik
    image: traefik:latest
    # profiles:
    #   - traefik-network
    restart: always
    command:
      # CLI arguments
      - --global.checkNewVersion=true
      - --global.sendAnonymousUsage=true
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --api=true
      - --log=true
      - --log.filePath=/logs/traefik.log
      - --log.level=INFO # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
      - --accesslog=true
      - --accesslog.filepath=/logs/access.log
      - --accesslog.format=json
      - --accesslog.filters.statuscodes=400-499
      - --accessLog.bufferingSize=0 # Configuring a buffer of 100 lines      
      - --accesslog.fields.headers.defaultmode=drop
      - --accesslog.fields.headers.names.User-Agent=keep
      - --providers.docker=true
      - --providers.docker.endpoint=tcp://socket-proxy:2375 # My docker-socket-proxy
      - --providers.docker.defaultrule=Host(`{{ index .Labels "com.docker.compose.service" }}.${DOMAIN_NAME}`)
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=traefik_proxy
      - --providers.docker.swarmMode=false
      - --providers.file.directory=/rules # Load dynamic configuration from one or more .toml or .yml files in a directory.
      #      - --providers.file.filename=/path/to/file # Load dynamic configuration from a file.
      - --providers.file.watch=true # Only works on top level files in the rules folder
      # - --certificatesResolvers.cloudflare.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory # LetsEncrypt Staging Server - uncomment when testing
      - --entrypoints.https.http.tls=true
      - --entrypoints.https.http.tls.certresolver=cloudflare
      - --entrypoints.https.http.tls.domains[0].main=${DOMAIN_NAME}
      - --entrypoints.https.http.tls.domains[0].sans=*.${DOMAIN_NAME}
      # - --entrypoints.https.http.tls.domains[1].main=$DOMAIN # Pulls main cert for second domain
      # - --entrypoints.https.http.tls.domains[1].sans=*.$DOMAIN # Pulls wildcard cert for second domain
      - --certificatesResolvers.cloudflare.acme.email=${CLOUDFLARE_EMAIL}
      - --certificatesResolvers.cloudflare.acme.storage=/acme.json
      - --certificatesResolvers.cloudflare.acme.dnsChallenge.provider=cloudflare
      - --certificatesresolvers.cloudflare.acme.dnschallenge.resolvers=${DNS_RESOLVER} # pihole IP
      # Enable Hub communication (open the port 9900 and 9901 by default)
      - --metrics.prometheus.addrouterslabels=true
    networks:
      traefik_proxy:
      socket_proxy:
        #healthcheck:
        #  test: ["CMD", "traefik", "healthcheck", "--ping"]
        #  interval: 5s
        #  retries: 3
    ports:
      - "80:80"
      - "443:443"
    security_opt:
      - no-new-privileges:true # https://docs.docker.com/engine/reference/run/#security-configuration
    volumes:
      - $DOCKER_DIR/traefik/rules:/rules # file provider directory
      # - /var/run/docker.sock:/var/run/docker.sock:ro # Connect to docker-socket-proxy tcp://docker-socket-proxy:2375
      - $DOCKER_DIR/traefik/acme/acme.json:/acme.json # cert location - you must touch this file and change permissions to 600
      - $DOCKER_DIR/traefik/logs:/logs # for fail2ban - make sure to touch file before starting container
    environment:
      - CF_API_EMAIL=${CLOUDFLARE_EMAIL}
      - CF_API_KEY=${CLOUDFLARE_API_KEY}
    #      - CF_API_EMAIL_FILE=/run/secrets/cf-api-email
    #      - CF_API_KEY_FILE=/run/secrets/cf-api-key
    # secrets:
    #   - "cf-api-email"
    #   - "cf-api-key"
    labels:
      - "traefik.enable=true"
      # HTTP Routers
      - "traefik.http.routers.traefik-rtr.entrypoints=https"
      - "traefik.http.routers.traefik-rtr.rule=Host(`traefik.${DOMAIN_NAME}`)"
      - "traefik.http.routers.traefik-rtr.priority=10"
      ## Middlewares
      - "traefik.http.routers.traefik-rtr.middlewares=chain-oauth@file"
      ## Services - API
      - "traefik.http.routers.traefik-rtr.service=api@internal"
      ## API Forward Auth Bypass # Used for willfantom/SUI - automatic traefik dashboard
      - "traefik.http.routers.traefik-bypass.entrypoints=https"
      - "traefik.http.routers.traefik-bypass.rule=Host(`traefik.${DOMAIN_NAME}`) && PathPrefix(`/api/`)"
      # - "traefik.http.middlewares.traefik-basicauth.basicauth.users=$MY_USERNAME:$TRAEFIK_PASSWORD" # password must be htpasswd hash
      - "traefik.http.routers.traefik-bypass.priority=20"
      - "traefik.http.routers.traefik-bypass.service=api@internal"
    healthcheck:
      test: ping -c 1 www.google.com || exit 1
      interval: 30s
      timeout: 10s
      retries: 3```

Here is the configured tunnel:

Hi, @serup,

Did you managed to fix your issue?

I followed this guide https://mattdyson.org/blog/2024/02/using-traefik-with-cloudflare-tunnels/ but it’s not working.

On companion container I’m getting this error:

HTTPSConnectionPool(host='traefik.mydomain.me', port=443): Max retries exceeded with url: /api/api/http/routers

My suspect is that it’s failing because there is no traefik.mydomain.me record at Cloudflare DNS.

The article I used to create my setup it’s not clear about the traefik.mydomain.me or I missed something.

Best regards,

Hello! So I managed to figure out a way to use wildcards with CF Tunnels and Traefik.

The following should hopefully make it work for you too, please also note that I’m not really sure how secure this method is, but with CF handling security I believe it should be secure.

  1. Clear all your DNS records and Tunnel Host names, add a Host Name *.domain.com pointing to Traefik IP and port (Tested with SSL so usually 443).
  2. In Advanced configuration, open TLS tab and add domain.com to Origin Server Name. P.S.: If your licenses aren’t properly configured enable No TLS Verify
  3. Go to your DNS records and check if a CNAME record for domain.com -> <tunnel-id>.cfargotunnel.com was made, if not create it as mentioned. Make sure it’s proxied.
  4. Add another CNAME record this time for * -> <tunnel-id>.cfargotunnel.com. Make sure it’s proxied too.
  5. Add CF IPs to a allowlist middleware in Traefik and you should be good to go.
  6. Test service.domain.com outside of local network, if it works then congrats! If it doesn’t you can try setting the hostname as domain.com and pointing to Traefik, then changing it to *.domain.comafter the DNS record is created.

Best of luck!