This is a how-to guide inspired by “Quick and Easy SSL Certificates for Your Homelab!”" focus on Traefik reverse proxy server. Although this guide focuses on DuckDNS, a similar configuration can apply to any DNS provider.
The trick is by setting private IP for the domain name you own, in my case DuckDNS.
Get DuckDNS Sub-Domain
Sign-up an account in duckdns.org, choose a sub-domain(As I choose a dummy sub-domain lser.duckdns.org
) and add your home server IP address(In my case 192.168.0.120
)
Copy token
which will be used later for DNS challenge
Configure Traefik
Reference docs https://doc.traefik.io/traefik/https/acme/
Define certificatesResolvers
Below is an example toml config snippet. You can find the complete configuration in my Github repo veerendra2/raspberrypi-homeserver/services/traefik/config/traefik.toml
...
[certificatesResolvers.whatever-resolver-name-here.acme]
email = "veerendra2@github.com"
storage = "/etc/traefik/acme.json"
[certificatesResolvers.whatever-resolver-name-here.acme.dnsChallenge]
provider = "duckdns"
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
...
I defined certificatesResolvers
with name whatever-resolver-name-here
with dnsChallenge
(DNS challenge)
email
- A manditory option to identify userstorage
- Storage file location to store private key and other certificate detailsprovider
-duckdns
(List of other dns provider supported by Traefik here)
SSL Certificate for the Domain
As Traefik docs says
Defining a certificate resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must reference it.
Use defined certificatesResolvers
(In my case, it is whatever-resolver-name-here
) by adding it in labels like below docker-stack.yml
π You can also find below docker swarm
docker-stack.yml
in my Github repo. https://github.com/veerendra2/raspberrypi-homeserver/tree/main/services/traefik
...
labels:
- "traefik.enable=true"
- "traefik.docker.network=network_public"
- "traefik.http.routers.api.rule=Host(`lser.duckdns.org`) && PathPrefix(`/dashboard`) || Host(`lser.duckdns.org`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.tls.certresolver=whatever-resolver-name-here"
- "traefik.http.routers.api.entrypoints=https"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.services.dummy.loadbalancer.server.port=9999"
env_file:
- .env_traefik
secrets:
- duckdns
...
As you see in the above docker-stack.yml
, I mentioned duckdns
secret. To complete the DNS challenge, you must pass the DuckDNS token you copied earlier as environmental variables to Traefik
π Reference docs https://go-acme.github.io/lego/dns/duckdns/
Here is a directory tree for a better understanding
veerendra at atom in ~/raspberrypi-homeserver/services/traefik on main
$ tree .
.
βββ config
βΒ Β βββ acme.json
βΒ Β βββ traefik.toml
βββ docker-stack.yml
βββ network.yml
βββ secrets
βββ duckdns.txt
3 directories, 7 files
$ cat .env_traefik
DUCKDNS_TOKEN_FILE=/run/secrets/duckdns
$ cat secrets/duckdns.txt
[REDACTED]
Once everything is placed, deploy the stack by running below command
$ docker stack deploy -c docker-stack.yml traefik
...
That’s it!, Traefik completes the DNS challenge and gets a SSL certificate for your DuckDNS domain. If you want to create a sub-domain for any other service, you can simply add a domain name and resolver in docker labels like below
...
- "traefik.http.routers.api.rule=Host(`my-service.lser.duckdns.org`)"
- "traefik.http.routers.api.tls.certresolver=whatever-resolver-name-here"
- "traefik.http.routers.api.entrypoints=https"
...