#
Traefik
What is Traefik and Why Do I Use It?
Traefik is an HTTP reverse proxy and load balancer that simplifies the deployment of microservices. It integrates with existing infrastructure components like Docker and automatically configures itself dynamically.
I use Traefik to obtain Let's Encrypt wildcard SSL certificates for all of my internal self-hosted services. My setup includes Cloudflare as the DNS provider and Pi-hole as the local DNS, which allows me to securely route internal services with valid SSL certificates. No longer do I have to remember random IP addresses, deal with weird ports, or be haunted by those dreaded HTTPS warnings.
#
1. Prerequisites
- Docker and Docker Compose
- Run and manage multi-container setups.
- Cloudflare Account
- API token for the DNS challenge (Let's Encrypt).
- Domain Name (e.g., from Cloudflare Registrar)
- Configure DNS records for Traefik.
- htpasswd (for Basic Authentication)
- Secure the Traefik dashboard.
For more detailed installation and configuration instructions, please refer to the official Traefik Proxy Documentation.
Before proceeding, ensure that Docker is already installed. If it's not, you can follow the official Docker installation guide.
Before we begin, create a directory for your Docker data (if you haven't already), then create a directory for Traefik:
mkdir docker_volumes
cd docker_volumes
mkdir traefik
cd traefik
By the end of this guide, your directory structure should look something like this:
./traefik
├── cf_api_token.txt
├── data
│ ├── acme.json
│ └── traefik.yml
└── docker-compose.yaml
#
2. Configuring Docker Compose
Create a docker-compose.yaml file inside the traefik directory:
touch docker-compose.yaml
nano docker-compose.yaml
Then add the following content to the docker-compose.yml file:
services:
traefik:
image: traefik
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges: true
networks:
- proxy
ports:
- 80:80
- 443:443
environment:
CF_DNS_API_TOKEN_FILE: /run/secrets/cf_api_token
TRAEFIK_DASHBOARD_CREDENTIALS: ${TRAEFIK_DASHBOARD_CREDENTIALS}
secrets:
- cf_api_token
env_file: .env
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_DASHBOARD_CREDENTIALS}"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik-secure.tls.domains[0].main=example.com"
- "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com"
- "traefik.http.routers.traefik-secure.service=api@internal"
secrets:
cf_api_token:
file: ./cf_api_token.txt
networks:
proxy:
external: true
Note
The highlighted rows must be configured with your own actual domain name (*.example.com and traefik.example.com)
#
3. Set up the Data Directory
After creating and configuring your docker-compose.yml file, create and navigate to the data directory. Inside the data directory, create the acme.json file to store the Let's Encrypt certificates. Then, set the appropriate permissions (read/write for owner, no access for others):
mkdir data
cd data
touch acme.json
chmod 600 acme.json
In the data directory, create the traefik.yml configuration file:
nano traefik.yml
Then, add the following content to the traefik.yml file:
api:
dashboard: true
debug: true
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
cloudflare:
acme:
email: [email protected]
storage: acme.json
caServer: https://acme-v02.api.letsencrypt.org/directory
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
Note
The highlighted rows must be configured with your own email address and DNS provider. For testing purposes, you can point your Certificate Authority (CA) server to Cloudflare's staging server: https://acme-staging-v02.api.letsencrypt.org/directory
After configuring traefik.yml, create a Docker network for Traefik:
docker network create proxy
Finally, create a file to store your Cloudflare API Token secret:
touch cf_api_token.txt
nano cf_api_token.txt
More instruction on how to create an API token can be found on Cloudflare's Fundamentals Documentation.
#
4. Traefik Dashboard Authentication
To secure access to the Traefik dashboard, generate a bcrypt-hashed password using htpasswd. You can install it by running:
apt install apache2-utils
Then, use the following command to generate a bcrypt-hashed password:
echo $(htpasswd -nB exampleUser) | sed -e s/\\$/\\$\\$/g
New password: [REDACTED]
Re-type new password: [REDACTED]
exampleUser:$$2y$$05$$.UQL...RlW
Next, create an .env file:
touch .env
nano .env
Finally, add the following credentials to the .env file:
TRAEFIK_DASHBOARD_CREDENTIALS=exampleUser:$2y$05$abc...xyz
#
5. Start Traefik
With everything set up, (re)start the Docker container to apply changes:
docker compose up -d --force-recreate
Congratulations! You’ve just set up Traefik! However, if you head over to the website specified in your Docker Compose file, it won’t resolve since you're missing a local DNS entry. To fix this, you’ll need a DNS system that can resolve local DNS records. You can either configure your router (if it supports local DNS records) or use Pi-hole. Pi-hole is a DNS sinkhole that also offers network-wide ad blocking, but I primarily use it for managing local DNS domains.
For a guide on setting up Pi-hole, check out my guide here. WIP
#
6. Troubleshooting
WIP