Let's Encrypt Wildcard Certificates For A Homelab
Wildcard certificates cover every subdomain under a domain. One cert, many names. For a homelab with a growing service list, that is useful.
Here is a quick primer on what they are, how they work with Let’s Encrypt, and what I set up at home.
What A Wildcard Is
A wildcard cert secures *.example.com
. It validates grafana.example.com
, nextcloud.example.com
, and so on. It does not cover the bare domain example.com
unless you also include it as a Subject Alternative Name.
How Let’s Encrypt Issues Wildcards
- ACME is the protocol the client and CA use to prove control of a domain
- For wildcards you must use the DNS-01 challenge
- DNS-01 works by creating a special TXT record under
_acme-challenge.example.com
- The CA looks up the TXT record and, if it matches the challenge, issues the cert
For homelabs this is ideal. You do not need to expose an HTTP endpoint to the internet. You automate DNS and the certs renew on their own.
Why It Helps At Home
- One certificate for many services behind a reverse proxy
- Clean URLs for internal and external access
- Less per service certificate management
- Easy to add new services without touching the CA
How I Set It Up
The reverse proxy is Traefik on Docker Swarm. The certificate resolver uses DNS-01 with my DNS provider. Here are the steps I used:
- Deploy Traefik on Swarm with the provider integration
- Enable the DNS-01 resolver in Traefik
- Provide the DNS API token as a secret
- Point services at Traefik with HTTPS labels
- Verify the first wildcard issuance, then watch auto renewals
This moved me off per service certificates and into a single, automated flow.
Using Cloudflare DNS On The Free Tier
- Create a scoped API Token in Cloudflare with Permissions set to “Zone DNS Edit” and Resource limited to your zone
- In Traefik, configure the ACME resolver to use the Cloudflare provider
- Store the API token as a Docker secret and reference it with the “_FILE” environment variable variant that Traefik expects (for example
CLOUDFLARE_DNS_API_TOKEN_FILE
) - Traefik creates and deletes the
_acme-challenge
TXT records during issuance and renewal - Propagation is usually fast on Cloudflare free tier. Traefik handles waiting and retries
What I Changed
I set this up while preparing an MDM stack. Before that, Traefik used the HTTP challenge for individual certs. I migrated to DNS-01 and wildcard support and cleaned up the config.
- Deployed Traefik on Swarm and updated to the current provider flags
- Switched from HTTP challenge to DNS-01 for wildcard issuance
- Stored the DNS token as a secret and fixed an environment variable mismatch
- Verified Traefik health and dashboard
- Standardized URLs in the homepage config so services pointed at the proxy
This also made later work easier. Adding services was a matter of labels and DNS.
Common Pitfalls
- Wildcards need DNS-01. The HTTP-01 challenge does not work for
*.
- For Cloudflare in Traefik, use the correct variable:
CLOUDFLARE_DNS_API_TOKEN
or the saferCLOUDFLARE_DNS_API_TOKEN_FILE
with secrets - Remember to include the root domain as a SAN if you need it
- Keep an eye on rate limits during testing
Secrets Instead Of Bind Mounts
Use Docker Swarm secrets for API tokens rather than bind mounting files or baking tokens into env vars. Secrets are mounted as in-memory files only to the container that needs them, are not stored in image layers, and do not show up in docker inspect
environment output.
Example
# create the secret once
printf '%s' "your-cloudflare-token" | docker secret create cloudflare_api_token -
# in your Traefik service definition
services:
traefik:
secrets:
- cloudflare_api_token
environment:
# Traefik reads the token from this path
- CLOUDFLARE_DNS_API_TOKEN_FILE=/run/secrets/cloudflare_api_token
# ... other labels and config ...
secrets:
cloudflare_api_token:
external: true
This keeps credentials out of compose files and logs, and works well with the “_FILE” env variants many tools support.
What I Would Do Again
- Keep certificate automation in the proxy instead of per service
- Use secrets for API tokens as shown above
- Standardize service URLs early so you do not chase internal IPs later
That is the setup that has worked well for me. Short, simple, and ready to grow with the lab.
Ready to Transform Your Career?
Let's work together to unlock your potential and achieve your professional goals.