Configure Traefik to use custom domain name, Let’s Encrypt and Azure DNS Zone
Problem statement
In the previous article we configured Traefik to use magic domain name like traefik.me. In this article we configure it with your domain and Let’s Encrypt certificated authority.
Prerequisites
First of all you need to obtain (buy) custom domain from any domain registrar like Google Domains, GoDaddy or any other.
NOTE: In this article I’m going to use Azure DNS Zone as a domain registrar. But, the steps should be more or less the same for other registrar. The difference mostly in UI.
NOTE: Azure DNS Zone is not a domain registrar, but it allows you to manage you custom domain if you use Azure cloud platform. You can read about how to configure Azure DNS Zone and Google Domains in this article.
Configure Domain Registrar
First, we need to add service subdomain to domain registrar.
- Obtain the public IP address for you server.
- Go to you domain registrar and create A record. If you use Azure DNS Zone steps are following:
- Go to you Azure DNS Zone.
- Click + Record set button.
- Enter Name e.g.
whoami
. - Select Type:
A - Alias record
. - Enter IP address: it is your server IP address. For testing purpose I’m going to use
127.0.0.1
.
Configure Traefik
Create a new docker-compose.yml
file and add Traefik service with basic configuration (set docker as configuration provider, and configure HTTP and HTTPS endpoints).
version: '3.8'
services:
reverse.proxy:
image: traefik:v2.9
container_name: reverse.proxy
command:
- --providers.docker
- --providers.docker.exposedbydefault=false
- --log.level=DEBUG
- --entrypoints.websecure.address=:443
- --entrypoints.web.address=:80
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart:
unless-stopped
Add basic Let’s Encrypt configuration (set Let’s Encrypt as certificate resolver and create docker volume to store obtained certificates).
reverse.proxy:
command:
- --certificatesresolvers.letsencrypt.acme.email=<YOUR EMAIL ADDRESS>
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
#- --certificatesresolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
volumes:
- traefik:/letsencrypt
volumes:
traefik:
NOTE: During development it is highly recommended to use Let’s Encrypt staging environment, because production environment has rate limits that you can easily run out of. To use staging environment just uncomment
caServer
parameter.
NOTE: If you are using Let’s Encrypt staging environment, the browser will show certificate as untrusted.
NOTE: When you switch between Let’s Encrypt environments, do not forget cleanup
traefik
docker volume. Because Traefik will not re-request certificate, until it is valid.
The next step is to decide which ACME challenge type (HTTP-01 or DNS-01) your are going to use.
Before we continue with ACME challenge configuration. Let’s configure our test service, because it’s configuration will be the same for both challenge types.
For testing purposes let’s create the whoami
service.
whoami:
image: containous/whoami
container_name: whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.libertus.dev`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=letsencrypt
- traefik.http.routers.whoami.service=whoami
- traefik.http.services.whoami.loadbalancer.server.port=80
Basically we are telling Traefik to use whoami.libertus.dev
host name over websecure
(HTTPS) endpoint and to use letsencrypt
certificate resolver.
HTTP-01 Challenge
IMPORTANT: the HTTP-01 challenge only works over port 80, so it cannot be used if this port is blocked on your web server.
The configuration is very simple, we just need add two command arguments to our previous configuration. Which are telling Traefik to use HTTP-01 challenge over web
(HTTP) endpoint.
services:
reverse.proxy:
command:
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
Let’s combine all previous steps together.
version: '3.8'
services:
reverse.proxy:
image: traefik:v2.9
container_name: reverse.proxy
command:
- --providers.docker
- --providers.docker.exposedbydefault=false
- --log.level=DEBUG
- --entrypoints.websecure.address=:443
- --entrypoints.web.address=:80
- --certificatesresolvers.letsencrypt.acme.email=<YOUR_EMAIL_ADDRESS>
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
#- --certificatesresolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- traefik:/letsencrypt
restart:
unless-stopped
whoami:
image: containous/whoami
container_name: whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.<YOUR_DOAMIN_NAME>`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=letsencrypt
- traefik.http.routers.whoami.service=whoami
- traefik.http.services.whoami.loadbalancer.server.port=80
volumes:
traefik:
Basically that is it. Now you can deploy this configuration to your server and test it. In your browser navigate to https://whoami.<YOUR DOMAIN>
and in response you should see the whoami
response and valid certificate.
DNS-01 Challenge
The DNS challenge a bit more tricky than HTTP, because it requires access to your DNS provider via API. Basically, we need to provide Traefik access to the our DNS provider via API, that it could create DNS TXT record, and then Let’s Encrypt can use it to validate the subdomain ownership.
First of all, let’s configure Traefik to use DNS challenge. To our previous configuration add following command key.
services:
reverse.proxy:
command:
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
Now, let’s specify which DNS provider we are going to use, in this example we are using azure
. You can find the full list of supported providers here.
services:
reverse.proxy:
command:
- --certificatesresolvers.letsencrypt.acme.dnsChallenge.provider=azure
And now, the hard part. We need to configure provider. The azure provider requires us to create azure application that will be used by Traefik to get access to the Azure DNS Zone. So, we need to fill following environment variables.
services:
reverse.proxy:
environment:
- AZURE_ENVIRONMENT=<AZURE_ENVIRONMENT>
- AZURE_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP_NAME>
- AZURE_ZONE_NAME=<YOUR_DNS_ZONE_NAME>
- AZURE_SUBSCRIPTION_ID=<YOUR_AZURE_SUBSCRIPTION_NAME>
- AZURE_TENANT_ID=<YOUR_AZURE_TENANT_ID>
- AZURE_CLIENT_ID=<YOUR_APP_CLIENT_ID>
- AZURE_CLIENT_SECRET=<YOUR_APP_CLIENT_SECRET>
Where:
AZURE_ENVIRONMENT
- Most likely it should be
public
- Most likely it should be
AZURE_RESOURCE_GROUP
,AZURE_ZONE_NAME
,AZURE_SUBSCRIPTION_ID
- Go to your Azure DNS Zone and on the Overview tab you can find the
DNS Zone Name
,Resource group
andSubscription ID
fields.
- Go to your Azure DNS Zone and on the Overview tab you can find the
AZURE_TENANT_ID
- Go to Azure Active Directory page.
- On the Overview tab, copy Tenant ID field.
Next, we need to create azure app.
- Go to Azure Active Directory page.
- Go to App registrations tab.
- Click New Registration button.
- Enter Name
- And click Register button.
- On the Overview tab of just created app, copy the Application (client) ID to
AZURE_CLIENT_ID
variable. - Go to the Certificates & secrets tab.
- Click New client secret to generate a secret key.
- Copy new secret Value to
AZURE_CLIENT_SECRET
variable.
Almost done. One more thing is left, we need to assign permissions to just created app.
- Go to your subscription Overview page.
- Select Access Control (IAM) tab.
- Click + Add button.
- Select Add role assignment option.
- In the search box, type
dns
. - Select
DNS Zone Contributor
role. - Click Next button.
- Click + Select members button.
- In the search box type app name you created above and select it.
- Click Review + Assign button.
And that is it 😄. Now we can test it.
Let’s combine all previous steps together.
version: '3.8'
services:
reverse.proxy:
image: traefik:v2.9
container_name: reverse.proxy
command:
- --providers.docker
- --providers.docker.exposedbydefault=false
- --log.level=DEBUG
- --entrypoints.websecure.address=:443
- --entrypoints.web.address=:80
- --certificatesresolvers.letsencrypt.acme.email=<YOUR_EMAIL_ADDRESS>
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
#- --certificatesresolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
- --certificatesresolvers.letsencrypt.acme.dnsChallenge.provider=azure
environment:
- AZURE_ENVIRONMENT=<AZURE_ENVIRONMENT>
- AZURE_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP_NAME>
- AZURE_ZONE_NAME=<YOUR_DNS_ZONE_NAME>
- AZURE_SUBSCRIPTION_ID=<YOUR_AZURE_SUBSCRIPTION_NAME>
- AZURE_TENANT_ID=<YOUR_AZURE_TENANT_ID>
- AZURE_CLIENT_ID=<YOUR_APP_CLIENT_ID>
- AZURE_CLIENT_SECRET=<YOUR_APP_CLIENT_SECRET>
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- traefik:/letsencrypt
restart:
unless-stopped
whoami:
image: containous/whoami
container_name: whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.<YOUR_DOAMIN_NAME>`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=letsencrypt
- traefik.http.routers.whoami.service=whoami
- traefik.http.services.whoami.loadbalancer.server.port=80
volumes:
traefik:
Run docker.
docker compose up
On Azure DNS Zone page you should see that a new TXT Record
was created.
In your browser navigate to https://whoami.<YOUR DOMAIN>
and in response you should see the whoami
response and valid certificate.
Source Code
The source code for this article you can find here .
Links
- Traefik
- What is Azure DNS?
- ACME Protocol: What it is and how it works
- Let's Encrypt
- Let's Encrypt. How It Works
- Let's Encrypt. Rate Limits
- What is a DNS record?
- Docker-compose with let's encrypt: HTTP Challenge
- Docker-compose with let's encrypt: DNS Challenge
- Which ACME Challenge Type Should I Use? HTTP-01 or DNS-01?
- Traefik DNS Providers
- Azure DNS Provider