Dynamically configured Traefik via docker compose with DuckDNS DNS challenge

I recently got Traefik up and running for my self-hosted applications on my LAN. I'm sharing my configuration below in case it's helpful (I also referenced this tutorial). This is my first time with reverse proxies and Traefik, so please chime in if there are any suggestions or improvements I can make!

Goal: Provide SSL certs for local-only applications dynamically based on docker tags. Do not allow external access for security. Deploy in a single docker compose file and use DNS-01 challenge with a free DuckDNS URL.

compose.yml

services:
  traefik:
    image: traefik #3.1.2
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    environment:
      - DUCKDNS_TOKEN=<token>
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=web"
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.example.duckdns.org`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=<password>" #echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.example.duckdns.org`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=duckdns"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=example.duckdns.org"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.duckdns.org"
      - "traefik.http.routers.traefik-secure.service=api@internal"
    command: #https://doc.traefik.io/traefik/reference/static-configuration/cli/
      - --api.dashboard=true
      - --api.debug=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.asDefault=true
      #- --serversTransport.insecureSkipVerify=true #Comment out once working
      - --providers.docker.endpoint=unix:///var/run/docker.sock
      - --providers.docker.exposedByDefault=false
      - --certificatesresolvers.duckdns.acme.email=<mail@email.com>
      - --certificatesresolvers.duckdns.acme.storage=/letsencrypt/acme.json #sudo touch acme.json && sudo chmod 600 acme.json
      #- --certificatesresolvers.duckdns.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory #Staging to avoid rate limiting, comment out for production
      - --certificatesresolvers.duckdns.acme.dnschallenge.disablepropagationcheck=true
      - --certificatesresolvers.duckdns.acme.dnschallenge.provider=duckdns
      - --certificatesresolvers.duckdns.acme.dnschallenge.delaybeforecheck=120
      - --certificatesresolvers.duckdns.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53

networks:
  proxy: #docker network create proxy
    external: true

Example service that is automatically configured based on docker tags:
compose.yml

services:
  nginx:
    image: nginxdemos/nginx-hello
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.rule=Host(`nginx.example.duckdns.org`)"
      - "traefik.http.routers.nginx.entrypoints=websecure"
      - "traefik.http.routers.nginx.tls=true"
      - "traefik.http.services.nginx.loadbalancer.server.port=8080"
    networks:
      - proxy

networks:
  proxy:
    external: true

Does the domain exist? Note that you can simply point the public DNS record to your private IP. dnschallenge will still work, but the service will only be accessible inside your network.

My "example.duckdns.org" isn't used for anything external, so in duckdns.org I set the DNS record to my server's local IP address (e.g., 192.168.1.100).

I think you forgot to assign the certresolver to entrypoint or router.

I already included a label - "traefik.http.routers.traefik-secure.tls.certresolver=duckdns". Is an additional label needed? If so, would you mind writing out the line/label I should add?

If nginx should use LE, then you need to assign it to the router, too.

Or you assign it globally to entrypoint, compare to simple Traefik example.

Okay, thanks for the feedback. I added that line to my existing config. I didn't notice a difference, but thanks for the feedback!

Line added:
- --entrypoints.websecure.http.tls.certresolver=duckdns

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