Use LetsEncrypt wildcard certificates with Traefik
For one of my use cases in my homelab, I wanted to avoid requesting a Let’s Encrypt certificate for each subdomain through Traefik every time. For this reason, I considered using a wildcard certificate.
In my homelab I have Traefik installed in a LXC container and run it as a systemd service. Please have a look at the Traefik documentation to use the Binary Distrubtion installation method.
traefik.service
I prefer to use the DNS challenge in Traefik to request certificates. For this reason, I adopted the provided systemd example to pass the Cloudflare DNS API token as an environment variable by combining EnvironmentFile and PassEnvironment:
[Unit]
Description=Traefik
Documentation=https://doc.traefik.io/traefik/
After=network-online.target
[Service]
User=traefik
EnvironmentFile=/var/lib/traefik/.env
PassEnvironment=CLOUDFLARE_DNS_API_TOKEN
AmbientCapabilities=CAP_NET_BIND_SERVICE
# configure service behavior
Type=notify
ExecStart=/usr/bin/traefik --configFile=/etc/traefik/traefik.yml
Restart=always
WatchdogSec=1s
[Install]
WantedBy=multi-user.target
traefik.yml
To do the DNS challenge with Cloudflare, I defined the Let’s Encrypt certificate resolver as follows:
---
certificatesResolvers:
letsEncrypt:
acme:
email: YOUR_EMAIL
storage: /var/lib/traefik/acme.json
dnsChallenge:
provider: cloudflare
delayBeforeCheck: "30"
resolvers:
- "coraline.ns.cloudflare.com:53"
- "kyrie.ns.cloudflare.com:53"
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
scheme: https
to: https
https:
address: ":443"
api:
dashboard: true
metrics:
prometheus: {}
providers:
file:
filename: /var/lib/traefik/dynamic.yml
dynamic.yaml
In this configuration file I have defined all routers and services that Traefik should use. To get the wildcard certificate for home.example.tld
I had to request it the first time with a router by specifying the domains
section.
During startup, Traefik requests a wildcard certificate for our main domain and uses it for each subdomain from now on.
---
http:
routers:
traefik:
rule: Host(`traefik.home.example.tld`)
service: api@internal
tls:
certResolver: letsEncrypt
domains:
- main: `home.example.tld`
sans:
- "*.home.example.tld"
grafana:
rule: Host(`grafana.home.example.tld`)
service: grafana
tls:
certResolver: letsEncrypt
domains:
- main: `home.example.tld`
sans:
- "*.home.example.tld"
prometheus:
rule: Host(`prometheus.home.example.tld`)
service: prometheus
tls:
certResolver: letsEncrypt
domains:
- main: `home.example.tld`
sans:
- "*.home.example.tld"
services:
grafana:
loadBalancer:
servers:
- url: "http://monitoring:3000/"
prometheus:
loadBalancer:
servers:
- url: "http://monitoring:9090/"