Docker-compose with Let's Encrypt: DNS Challenge & Cloudflare (Recommended)
Introduction
This guide aims to demonstrate how to create a certificate with the Let's Encrypt DNS-01 Challenge to use HTTPS on a simple service exposed with Traefik.
Why Use DNS-01 Challenge Instead of TLS?
Using the DNS-01 Challenge instead of TLS-ALPN-01 provides several advantages:
- Wildcard Certificates: DNS-01 is the only challenge type that supports wildcard domains (e.g.,
*.example.com
), simplifying the management of multiple subdomains. - No Open Ports Required: Unlike TLS-ALPN, DNS-01 doesn’t rely on ports 443 or 80 being open, offering better security and flexibility for non-web services.
- Multi-Server and Complex Setups: DNS-01 works in distributed or multi-server environments without requiring direct communication from Let's Encrypt to each server.
- Behind Proxies or Firewalls: Ideal for servers behind NAT, private networks, or reverse proxies where direct access to the server is limited.
Overview of DNS-01 Challenge
The DNS-01 Challenge is a method used by Let's Encrypt to verify domain ownership by creating a specific DNS TXT record for the domain. This challenge is particularly useful for issuing wildcard certificates (*.example.com
), securing services that are not publicly accessible, and environments where direct access to ports 80 or 443 is not possible. It provides flexibility and higher security, especially when combined with automated DNS providers like Cloudflare.
Prerequisite
- A publicly accessible host allowing connections on port
443
with Docker and Docker Compose installed. - A working DNS provider (e.g., Cloudflare) with credentials to create and remove DNS records.
- If you use a 3rd-party hosting provider, make sure your domain uses Cloudflare's nameservers. Learn more about changing nameservers in this guide.
Step 0: Add Domain to Cloudflare
To add your domain to the Cloudflare dashboard, follow Cloudflare's full setup guide: Cloudflare Guide.
Step 1: Change Nameservers to Cloudflare
Log in to your hosting provider's control panel and change your domain's nameservers to Cloudflare's. This process may take up to 24 hours to propagate. For more information or an Example, check this guide.
When changing the NS, most Hosting Providers take up to 24h to update them.
Make Sure to ask your Hoster for more Informations
Step 2: Create a Custom Cloudflare API Token
Log in to Cloudflare and navigate to API Tokens. Click "Create Token".
Steps to create the token:
- Give your token a descriptive name (e.g., "Homelab Traefik API-Token").
- Set the permissions as shown in the example image (Zone → Zone [Read], Zone → Zone Settings [Read], Zone → DNS [Edit]).
- Select your domain.
- Click "Continue to Summary" and create the token.
What Does These Permissions do?
Zone → Zone (Read):
Allows read-only access to basic information about the specified zone (e.g., DNS records, configuration, status, etc.).
Zone → Zone Settings (Read):
Grants read-only access to view the zone’s settings (e.g., SSL/TLS settings, security settings, and performance configurations).
Zone → DNS (Edit):
Allows full control over DNS records in the specified zone. This means you can create, edit, and delete DNS records.
Step 3: Create a Local API Token File
In This Step you could also Work with Docker Secrets. I did not get it Working with the Docker Secret, that why i put it in a File. If you want to use a Docker Secret, please visit Official Docker Docs: https://docs.docker.com/compose/how-tos/use-secrets/
Go to your Traefik folder and create a file to store your Cloudflare API token securely:
nano ./traefik_data/cloudflare_api_token
Paste your token in the file, then save and close it (CTRL+O, CTRL+X).
Step 4: Create the ACME.json File
The acme.json
file stores Let's Encrypt certificates, keys, and account information in JSON format for Traefik's ACME integration.
Ensure the file is created and secured with the Rights 600:
mkdir ./letsencrypt
touch ./letsencrypt/acme.json
chmod 600 ./letsencrypt/acme.json
Step 5: Adjust Your Traefik Docker-Compose File
In This Step you could also Work with Docker Secrets. I did not get it Working with the Docker Secret, that why i put it in a File. If you want to use a Docker Secret, please visit Official Docker Docs: https://docs.docker.com/compose/how-tos/use-secrets/
Mount your Cloudflare API token file and set the appropriate environment variables:
Example Docker Compose Configuration:
services:
traefik:
image: "traefik:v3.3"
volumes:
- "./traefik_data/cloudflare_api_token:/cloudflare_api_token:ro"
- "./letsencrypt:/letsencrypt"
environment:
- TZ=Europe/Zurich
- CF_API_EMAIL=yourmail@example.com
- CF_DNS_API_TOKEN_FILE=/cloudflare_api_token
Step 6: Adjust your Traefik Config
You can also use a static.yaml
or static.toml
file for this configuration. Check out this guide for more information.
You can Change the Value "leresolver" to your own Resolvername. Make sure to adjust your Traefik Router Labels/Settings.
Make Sure to Adjust the Variable "yourmail@example.com" to your actual Email.
Example for Traefik CLI:
command:
- --certificatesresolvers.leresovler.acme.email=yourmail@example.com
- --certificatesresolvers.leresovler.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.myresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory
- --certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.leresovler.acme.dnschallenge.delaybeforecheck=0
- --certificatesresolvers.leresovler.acme.dnschallenge.resolvers=1.1.1.1:53,1.0.0.1:53,8.8.8.8:53
Example for a static.yaml:
certificatesResolvers:
leresovler:
acme:
email: 'yourmail@example.com'
storage: '/letsencrypt/acme.json'
caServer: 'https://acme-v02.api.letsencrypt.org/directory'
dnsChallenge:
provider: 'cloudflare'
delayBeforeCheck: '0'
resolvers:
- '1.1.1.1:53'
- '1.0.0.1:53'
- '8.8.8.8:53'
Example for static.toml:
[certificatesResolvers.leresolver.acme]
email = "yourmail@example.com"
storage = "/letsencrypt/acme.json"
caServer = "https://acme-v02.api.letsencrypt.org/directory"
[certificatesResolvers.leresolver.acme.dnsChallenge]
provider = "cloudflare"
delayBeforeCheck = 0
resolvers = ["1.1.1.1:53", "1.0.0.1:53", "8.8.8.8:53"]
Step 7: Restart Traefik
Restart Traefik and make sure your application routers are configured to use the leresolver
for certificate generation.
Have fun Troubbleshooting. You can Change your Traefik-Log-Level to DEBUG for further Troubbleshooting.
Additional Tips
To improve security, you can add a plugin to allow only Cloudflare traffic to access your services. Check out this guide.
No Comments