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