Traefik
This section will cover deploying and configuring Traefik using Docker.
Table of Contents
- Introduction
- Traefik Setup
- Traefik Configuration
- Configuring traefik.yml
- Configuring dynamic.yaml
- Configuration Options
- Routers
- Middlewares
- Services
- Docker Labels
- Logging
- Implementing TLS Certificates
- Example Configurations
Introduction
Traefik is a reverse proxy that is mainly defined using configuration files and Docker labels.
References:
- https://doc.traefik.io/traefik/
- https://doc.traefik.io/traefik/reference/static-configuration/file/
- https://doc.traefik.io/traefik/reference/dynamic-configuration/file/
Traefik Setup
The following Docker Compose stack is an example for routing within the same host without HTTPS.
services:
traefik:
image: traefik:v3.1
restart: always
command:
- "--api.insecure=true"
- "--providers.docker"
ports:
- 80:80
- 8080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
labels:
- "traefik.http.routers.traefik.rule=Host(`traefik.domain.com`)"
#Nginx web server example
nginx:
image: nginx:latest
restart: always
volumes:
- ./web:/usr/share/nginx/html:ro
labels:
- "traefik.http.routers.nginx.rule=Host(`site.domain.com`)"
Breakdown:
--api.insecure=true- Enable the Traefik web UI on HTTP.--providers.docker- Specify Traefik to listen to docker.80- HTTP traffic.8080- Traefik's web UI."traefik.http.routers.nginx.rule=Host(`site.domain.com`)"- Specify the rule for routing. An example will be sub domain.
Traefik Configuration
Traefik can also use configuration files - dynamic.yaml and traefik.yml. Configurations can be defined within the dynamic.yaml file for different services on how to route traffic.
The compose.yaml file will need to be modified slightly to allow the use of the configuration files.
services:
traefik:
image: traefik:v3.1
restart: always
ports:
- 80:80
- 8080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-data/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik-data/dynamic.yaml:/etc/traefik/dynamic.yaml:ro
labels:
- "traefik.http.routers.traefik.rule=Host(`traefik.domain.com`)"
#Nginx web server example
nginx:
image: nginx:latest
restart: always
volumes:
- ./web:/usr/share/nginx/html:ro
labels:
- "traefik.http.routers.nginx.rule=Host(`site.domain.com`)" #Specify the conditions to route the traffic. In this example, sub domain name
The volumes have been added to map the traefik.yml and dynamic.yaml files accordingly. As items such as enabling the dashboard is defined in the traefik.yml file, we can omit the command fields.
Configuring traefik.yml
The traefik.yml file is a static configuration file.
In the traefik.yml file, we can define entry points, which are basically incoming ports. We will also need to define the dynamic.yaml directory and any other providers such as Docker within the file.
entryPoints:
web:
address: ":80" #Expose port 80
providers:
docker: #Allow local Docker routing
endpoint: "unix:///var/run/docker.sock"
file:
directory: "/etc/traefik" #Specify the dynamic.yaml file directory
#Enable Traefik dashboard
api:
dashboard: true
insecure: true
Configuring dynamic.yaml
Once the traefik.yml file is configured, we can specify all services in the dynamic.yaml file. An example will be where a website is running on a different host on port 5050.
http:
routers:
router0:
rule: "Host(`site-1.domain.com`)" #Specify the conditions to route.
service: service-a #Specify the service name in the "services" section
entryPoints:
- web #Specify the incoming ports defined in the traefik.yml file
services:
service-a:
loadBalancer:
servers:
- url: "http://10.10.10.2:5050" #Specify the URL of the target service
The above dynamic.yaml configuration will allow the website at http://10.10.10.2:5050 to be accessed with the site-1.domain.com domain.
Configuration Options
This section will cover some common configuration options for the different items in Traefik.
Routers
The following will list some common rules for the dynamic.yaml file. The rules will define if a particular request matches a specific criteria.
| Rule | Description | Example |
|---|---|---|
Host(`domain`) | Matches requests based on the host domain. | Host(`site.domain.com`) |
Method(`<method>`) | Matches requests based on the method. | Method(`GET`) |
Path(`<path`) | Matches requests based on the path. | Path(`/home/dashboard`) |
ClientIP(`IP`) | Matches requests based on the client IP. Accepts IPv4, IPv6, and CIDR formats. | ClientIP(`10.10.5.0/24`) |
More information can be found in the official documentation.
https://doc.traefik.io/traefik/routing/routers/#rule
Middlewares
Middleware in Traefik are attached to routers and are a means of tweaking requests before they are being sent to the service. This section will cover some useful middleware and their configuration method.
To configure an IP allow list, we can use the following in the dynamic.yaml file.
http:
middlewares:
middleware1:
ipAllowList:
sourceRange:
- 10.10.10.0/24
- 172.30.1.0/10
- 192.168.1.2
Using Docker labels:
labels:
- "traefik.http.middlewares.my-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.2"
To configure basic authentication, we can use the BasicAuth middleware. This allows for authentication before accessing a particular service. We can use the following to do this in the dynamic.yaml file.
Note that the hash must be either MD5 (not recommended), SHA1, or BCrypt. The hashes can be generated using htpasswd on Linux.
http:
middlewares:
middleware02:
basicAuth:
users:
- "<username>:<password hash>"
- "<username>:<password hash>"
- "test:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
Alternatively, an external file that contains the credentials with a username:password-hash format can be used. It can be passed into Traefik with the usersFile.
http:
middlewares:
middleware02:
basicAuth:
usersFile: "/path/to/userfile"
Using Docker labels:
labels:
- "traefik.http.middlewares.auth-1.basicauth.users=username:password-hash,test:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
More information can be found in the official Documentation:
https://doc.traefik.io/traefik/middlewares/overview/
https://doc.traefik.io/traefik/middlewares/http/ipallowlist/
https://doc.traefik.io/traefik/middlewares/http/basicauth/
Services
The Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests. The following options are defined in the dynamic.yaml file.
If a application has multiple instances, it is possible to configure load balancing between the instances. Note that the following configurations also applies to a single instance even if no load balancing is required.
For HTTP:
http:
<router configuration>
services:
<service-name>:
loadBalancer:
servers:
- url: "http://<IP>:<PORT>"
- url: "http://<IP>:<PORT>"
For TCP or UDP:
tcp/udp: #Remove either TCP or UDP accordingly
<router configuration>
services:
<service-name>
loadBalancer:
servers:
- address: "<IP>:<PORT>"
- address: "<IP>:<PORT>"
If load balancing is used, we can use weight to specify weighted load balancing. By default, Traefik uses round robin.
http:
<router configuration>
services:
<service-name>:
loadBalancer:
servers:
- url: "http://10.100.2.1:8000"
weight: 2
- url: "http://10.100.2.2:8000"
weight: 1
More information can be found in the official documentation.
https://doc.traefik.io/traefik/routing/services/
Docker Labels
If there are applications running with Docker containers on the same host as Traefik, Docker labels can be used.
The following will be some common labels that can be used.
services:
website:
#container configuration
labels:
#Match the specified domain to the service
- traefik.http.routers.website.rule=Host(`domain.com`)
#Specify a custom port for the container
- traefik.http.services.website.loadbalancer.server.port=5123
It is also possible to assign a container more than one router and service.
services:
website:
#container configuration
labels:
- traefik.http.routers.web-a.rule(`site.domain.com`)
- traefik.http.routers.web-a.service=web-a-service
- traefik.http.services.web-a-service.loadbalancer.server.port=8080
- traefik.http.routers.admin-web.rule(`admin.domain.com`)
- traefik.http.routers.admin-web.service=admin-service
- traefik.http.services.admin-service.loadbalancer.server.port=2200
More information can be found in the official documentation.
https://doc.traefik.io/traefik/routing/providers/docker/
Logging
To enable logging, we can specify the path to store either traefik logs, access logs, or both in the traefik.yml file.
log: #Store Traefik events
filePath: "/var/log/traefik/traefik.log"
maxSize: 500 #Specify the max file size in Megabytes
maxBackups: 3 #Specify the number of backups to keep
accessLog: #Store access logs
filePath: "/var/log/traefik/access.log"
Once added, we can map the /var/log/traefik to a directory on the host in the compose.yaml file.
volumes:
- ./traefik-data/logs:/var/log/traefik
Implementing TLS Certificates
To use custom TLS certificates, we can define them in the dynamic.yaml file.
tls:
certificates:
- certFile: /path/to/domain.cert
keyFile: /path/to/domain.key
- certFile: /path/to/additional-domain.cert
keyFile: /path/to/additional-domain.key
It is also possible to use a provider such as Let's Encrypt to get wildcard certificates using the following configuration in the traefik.yml file.
entryPoints:
websecure:
address: ":443"
http:
tls:
certResolver: my-resolver
domains:
- main: "my.domain.com"
sans:
- "*.my.domain.com"
certificatesResolvers:
my-resolver:
acme:
email: "example@email.com" #Email for registration
storage: "acme.json"
dnsChallenge:
provider: dns-provider-here
Once set, we can use tls: {} to terminate the TLS requests on the router (proxy) and use HTTP to communicate with the configured service if required.
http:
routers:
router1:
rule: "Host(`domain.com`)"
servcice: myweb
tls: {}
More information can be found in the official documentation.
https://doc.traefik.io/traefik/https/tls/
https://doc.traefik.io/traefik/https/acme/
https://doc.traefik.io/traefik/routing/routers/#tls_1
Example Configurations
compose.yaml:
services:
traefik:
image: traefik:v3.1
restart: always
#command:
#- "--api.insecure=true" #Enable the web UI on HTTP. Not required if using traefik.yml
#- "--providers.docker" #Listen to Docker. Not required if using traefik.yml
ports:
- "80:80"
- "443:443"
#- "8080:8080" #Traefik dashboard
#Additional ports if required
#- "25565:25565/udp"
#- "25565:25565"
volumes:
- /etc/localtime:/etc/localtime:ro #Set the timezone for Traefik
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-data/traefik.yml:/etc/traefik/traefik.yml:ro #Not required for simple single host deployment
- ./traefik-data/dynamic.yaml:/etc/traefik/dynamic.yaml:ro #Not required for simple single host deployment
- ./traefik-data/user-creds:/etc/traefik/user-creds:ro #Pass user credentials for BasicAuth "username:password-hash" format
- ./traefik-data/acme:/etc/traefik/acme #Used to store TLS certificates if using Let's Encrypt
- ./traefik-data/logs:/var/log/traefik/ #Used for storing logs
environment:
- CF_DNS_API_TOKEN=api_token_change_me #Used for DNS challenge for Let's Encrypt
#Nginx with load balancing example
nginx:
image: nginx:latest
restart: always
volumes:
- ./web:/usr/share/nginx/html:ro
deploy:
mode: replicated
replicas: 2
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`site.domain.com`)" #Specify the conditions to route the traffic. In this example, sub domain name
- "traefik.http.routers.nginx.entrypoints=websecure"
- "traefik.http.routers.nginx.tls=true" #Enable TLS
- "traefik.http.routers.nginx.middlewares=my-ipallowlist" #Specify the middlewares to use.
- "traefik.http.middlewares.my-ipallowlist.ipallowlist.sourcerange=127.0.0.1, 172.16.1.0/24, 192.168.0.0/16" #Specify allowed IP addresses
traefik.yml:
entryPoints:
web:
address: ":80"
http:
redirections: #Redirect all traffic from port 80 to 443
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
asDefault: true #Set port 443 as the default port
reusePort: true
http:
tls: #Wildcard certificate setup using cloudflare
certResolver: cf-resolver
domains:
- main: "my.domain.com"
sans:
- "*.my.domain.com"
minecraft:
address: ":25565"
minecraft-udp:
address: ":25565/udp"
providers:
docker: #Allow local Docker routing
endpoint: "unix:///var/run/docker.sock"
file:
directory: "/etc/traefik" #Specify the dynamic.yaml file directory
watch: true #Specify to watch the file for updates.
#Enable logging
log:
filePath: "/var/log/traefik/traefik.log"
maxSize: 500 #Specify the max file size
maxBackups: 3 #Specify the number of backups to keep
accessLog:
filePath: "/var/log/traefik/access.log"
#Enable Traefik dashboard
api:
dashboard: true
insecure: false
global:
checkNewVersion: true
sendAnonymousUsage: false
#TLS Certificates
certificatesResolvers:
my-resolvers:
acme:
email: "example@email.com" #Email for registration with Let's Encrypt
storage: "acme.json"
dnsChallenge:
provider: dns-provider-name #Specify the DNS provider for the DNS challenge
#Cloudflare
cf-resolver:
acme:
email: "change_me@email.com"
storage: "acme.json"
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
#disablePropagationCheck: true
dynamic.yaml:
http:
routers:
router0:
rule: "Host(`site-1.domain.com`)" #Specify the conditions to route. An example will be using the subdomain name
service: service-a #Specify the service name in the "services" section
entryPoints:
- web #Specify the incoming ports defined in the traefik.yml file
router1:
rule: "Host(`site-2.domain.com`)"
service: service-b
entryPoints:
- websecure
tls: {} #Specify to terminate TLS requests on the router (proxy)
dashboard-router: #Traefik dashboard
rule: "Host(`proxy.domain.com`) && Path(`/dashboard/`)"
service: api@internal
middlewares:
- middleware01
- middleware02
entryPoints:
- websecure
tls: {}
services:
service-a:
loadBalancer:
servers:
- url: "http://<IP>:<PORT>" #Specify the URL of the target service
service-b:
loadBalancer:
servers:
- url: "http://<IP>:<PORT>"
- url: "http://<IP>:<PORT>"
middlewares:
middlware01:
ipAllowList:
sourceRange: #Specify the IP addresses that are allowed to use the service
- 10.10.10.0/24
- 127.0.0.1/32
- 192.168.1.1
middleware02:
basicAuth:
users:
- "username:hashed-password"
- "test:$apr1$aKKMfSlx$.ylkR36/LnWluAJeIWkwk0"
- "myuser:$apr1$Chh2tzN4$EtSpG/GkIGM/x8lfj3Jdx1"
#usersFile: "/etc/traefik/user-creds" #Uncomment if using a file to specify user credentials
tcp:
routers:
tcprouter0:
rule: "ClientIP(`0.0.0.0/0`)"
service: mc
entryPoints:
- minecraft
services:
mc:
loadBalancer:
servers:
- address: "10.10.10.10:25565"
udp:
routers:
minecraft-router:
service: service-udp-a
entryPoints:
- minecraft-udp
services:
service-udp-a:
loadBalancer:
servers:
- address: "10.10.10.10:25565"
#Not required if using Let's Encrypt
tls:
certificates:
- certFile: /path/to/domain.cert
keyFile: /path/to/domain.key