In this article we are gonna get into setting up Traefik to request dynamic certs from Lets Encrypt. I had a few issues getting this up and running and the documentation is a little fuzzy. In my case I decided to go with the DNS challenge route. Really the only reason I went with this option is because I was having issues with the TLS and HTTP challenges. Well as it turns out my issues didn’t have as much to do with my configuration as they did with my router.
Sometime in the past I had set up some special rules on my router to force all clients on my network to send DNS requests through a self hosted DNS server. I did this to keep some of my “smart” devices from misbehaving by blocking there access to the outside world. As it turns out some devices will ignore the DNS servers that you hand out via DHCP and will use their own instead. That is of course unless you force DNS redirection but that is another post for another day.
Let’s revisit our current configuration:
version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.11
# Enables the web UI and tells Traefik to listen to docker
command:
- --api.insecure=true
- --providers.docker=true
- --providers.file.filename=/config.yml
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
# Set up LetsEncrypt
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.letsencrypt.acme.email=mikeconrad@onmail.com
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --entryPoints.web.http.redirections.entryPoint.to=websecure
- --entryPoints.web.http.redirections.entryPoint.scheme=https
- --entryPoints.web.http.redirections.entrypoint.permanent=true
- --log=true
- --log.level=INFO
# - '--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory'
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
ports:
# The HTTP port
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./volumes/traefik/logs:/logs
- ./traefik/config.yml:/config.yml:ro
networks:
- traefik
ots:
image: luzifer/ots
container_name: ots
restart: always
environment:
# Optional, see "Customization" in README
#CUSTOMIZE: '/etc/ots/customize.yaml'
# See README for details
REDIS_URL: redis://redis:6379/0
# 168h = 1w
SECRET_EXPIRY: "604800"
# "mem" or "redis" (See README)
STORAGE_TYPE: redis
depends_on:
- redis
labels:
- traefik.enable=true
- traefik.http.routers.ots.rule=Host(`ots.hackanooga.com`)
- traefik.http.routers.ots.entrypoints=websecure
- traefik.http.routers.ots.tls=true
- traefik.http.routers.ots.tls.certresolver=letsencrypt
networks:
- traefik
redis:
image: redis:alpine
restart: always
volumes:
- ./redis-data:/data
networks:
- traefik
networks:
traefik:
external: true
Now that we have all of this in place there are a couple more things we need to do on the Cloudflare side:
Step 1: Setup wildcard DNS entry
This is pretty straightforward. Follow the Cloudflare documentation if you aren’t familiar with setting this up.
Step 2: Create API Token
This is where the Traefik documentation is a little lacking. I had some issues getting this set up initially but ultimately found this documentation which pointed me in the right direction. In your Cloudflare account you will need to create an API token. Navigate to the dashboard, go to your profile -> API Tokens and create new token. It should have the following permissions:
Zone.Zone.Read
Zone.DNS.Edit
Also be sure to give it permission to access all zones in your account. Now simply provide that token when starting up the stack and you should be good to go:
CF_DNS_API_TOKEN=[redacted] docker compose up -d