Traefik 2.x configuration
Getting started with Traefik 2 can be a handful (…even if you are migrating from v1). It’s high configurability, an element that makes Traefik a truly powerful reverse proxy, also makes comparability across setup guides difficult. And since no two systems are seldom alike, multiple guides often need referencing to complete a setup. The process is supposed to be easy, it’s certainly billed as such….
…but hands-on can be a time-consuming and frustrating experience …unless you understand the underlying configuration architecture. Traefik’s own documentation in this respect is a bit muddled and as I have yet to see a clear and concise summary of this process online, I thought I’d try to provide one. What follows then will be more of a conceptual overview of Traefik’s configuration rather than a step-by-step guide. Some of the guides I have found helpful are listed at the end of this post and hopefully by then, digesting the relevant detail from those guides will be a little easier. Let’s begin.
The big hurdle with the Traefik 2 configuration is to understand two main concepts:
- The configuration is split between static and dynamic elements
- How and where the static and dynamic configurations are defined is determined by your infrastructure choices
Put another way, you have a static configuration bucket, a dynamic configuration bucket, and if you are using Docker, a container configuration bucket (via Docker Compose in this post). That’s three configuration buckets, and depending on your needs and preferences, these buckets may be represented in three separate configuration files, two files, or possibly even in a single Docker Compose file.
It sounds like a lot, but hopefully you’ll see it really is not. To get started, let’s set the stage with a basic initial Docker Compose file.
(traefik-docker-compose.yml)
services:
traefik:
container_name: traefik
image: traefik:2.2
restart: always
ports:
- 80:80
- 443:443
networks:
- traefik
volumes:
- ${CONTAINERPATH}/traefik:/etc/traefik
- ${CONTAINERPATH}/traefik/acme/acme.json:/acme.json
- ${CONTAINERPATH}/traefik/traefik.yml:/traefik.yml
- ${CONTAINERPATH}/traefik/dynamic_config.yml:/config.yml:ro
environment:
- TZ=${TZ}
Pretty vanilla so far. Let’s put this aside for a bit and take a look at the static configuration.
Static Configuration
If you glossed over the image at the start of this post it’s worth your time viewing it again in detail (larger image here). You’ll notice the static configuration is essentially Traefik’s startup configuration. Entrypoints (the ports Traefik listens to) and providers (connections to the services you want Traefik to proxy) are defined here as well as other infrastructure and security related options (api, logs, certificationResolvers, etc…).
You have a few options in how to define the static configuration. The default method is to store the configuration as a standalone file in either the TOML or YAML formats (note: the expected file name is “traefik”, ex. traefik.yml).
Here’s a sample of what the contents of the static configuration file may look like:
Standalone Static File (traefik.yml)
log:
level: DEBUG
filepath: "/etc/traefik/log/traefik.log"
api:
dashboard: true
insecure: false
debug: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
docker:
exposedByDefault: false
endpoint: "tcp://dockerproxy:2375"
network: "traefik"
defaultRule: "Host(`{{ trimPrefix `/` .Name }}.example.com`)"
file:
filename: "/etc/traefik/dynamic_config.yml"
watch: true
certificatesResolvers:
namecheap:
acme:
email: anyname@anymail.com
storage: "/etc/traefik/acme/acme.json"
dnsChallenge:
provider: namecheap
delayBeforeCheck: 120
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
TIP: The example above is in YAML but what if you are more familiar with TOML? Traefik’s documentation examples provide a toggle to let you see the same example in multiple formats.
Optionally, you can skip the stand alone file if you use either CLI arguments or environment variables to define the static configuration in your Docker Compose file.
Here is an abbreviated example for each method:
Docker CLI Arguments (traefik-docker-compose-staticCLI.yml)
services:
traefik:
container_name: traefik
image: traefik:2.2
restart: always
ports:
- ...
networks:
- ...
volumes:
- ...
command:
- "--log.level=DEBUG"
- "--log.filepath=/etc/traefik/log/traefik.log"
- "--api.insecure=false"
- "--api.dashboard=true"
- "--api.debug=true"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--providers.docker"
- "--providers.docker.exposedByDefault=false"
- ...
environment:
- TZ=${TZ}
Docker Environment Variables - (traefik-docker-compose-staticENV.yml)
services:
traefik:
container_name: traefik
image: traefik:2.2
restart: always
ports:
- ...
networks:
- ...
volumes:
- ...
environment:
- TZ=${TZ}
- TRAEFIK_LOG_LEVEL="DEBUG"
- TRAEFIK_LOG_FILEPATH="/etc/traefik/log/traefik.log"
- TRAEFIK_API_INSECURE="false"
- TRAEFIK_API_DASHBOARD="true"
- TRAEFIK_API_DEBUG="true"
- TRAEFIK_ENTRYPOINTS_WEB_ADDRESS=":80"
- TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS=":443"
- TRAEFIK_PROVIDERS_DOCKER="true"
- TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT="false"
- ...
The above three methods to define a static configuration are functionally equivalent. This means the method you choose is laregly a matter of prefence. Just keep in mind they are mutually exclusive so you will need to pick one and stick with it.
Dynamic Configuration
The dynamic configuration tells Traefik how to process requests. In it, routers (a Traefik term) are defined and pick-up inbound requests (through the entrypoints) and direct them to the appropriate back-end service. A router is generally paired with a service/server. For example, a request for subdomainfoo.example.com is captured by Router1 (via a rule) then directed to Server1, while Router2 captures requests for subdomainfoobar.example.com and routes it to Server2. Middlewares (another Traefik term) can be defined to modify a request. A Middleware sits between the router and server and can perform a redirect (http to https), a header modification, an authentication, or something else. A list of all the available Middlewares can be found here.
Dynamic Configuration - Docker
When Docker is used as a service provider (recall a provider is defined in the static config) the dynamic configuration is defined by the labels associated with each container at the time of the container’s start up.
For example, to enable Traefik on a Nextcloud container in Docker Compose, the associated labels may look similar to the below:
services:
nextcloud:
container_name: nextcloud
image: nextcloud
restart: always
volumes:
- ...
ports:
- ...
networks:
- ...
environment:
- ...
labels:
- traefik.enable=true
- traefik.http.routers.nextcloud-http.entrypoints=web
- traefik.http.routers.nextcloud-http.rule=Host(`nextcloud.${DOMAINNAME}`)
- traefik.http.routers.nextcloud-https.entrypoints=websecure
- traefik.http.routers.nextcloud-https.rule=Host(`nextcloud.${DOMAINNAME}`)
- traefik.http.routers.nextcloud-https.tls=true
- traefik.http.routers.nextcloud-https.tls.certresolver=default
- traefik.http.routers.nextcloud-http.middlewares=nextcloud-https@docker
- traefik.http.middlewares.nextcloud-https.redirectscheme.scheme=https
- traefik.http.middlewares.nextcloud-https.redirectScheme.permanent=true
- ...
Decomposition:
-
- traefik.enable=true
- Enables Traefik on the container and must be present
-
nextcloud-http
&nextcloud-https
- Two separately named routers * are defined. They use different entrypoints (naming convention up to you …both for routers & entrypoints)
-
traefik.http.routers.nextcloud-https.tls=true
- Enables TLS on the
nextcloud-https
router
- Enables TLS on the
-
- traefik.http.routers.nextcloud-https.tls.certresolver=default
- Assigns a certificate to the
nextcloud-https
router
- Assigns a certificate to the
-
- traefik.http.routers.nextcloud-http.middlewares=nextcloud-https@docker
&- traefik.http.middlewares.nextcloud-https.redirectscheme.scheme=https
- Taken together these create the https redirect
*NOTE: Traefik is generally able to resolve the service/server IP from Docker so a server specification (in relation to a router) is not needed in the labels. More detail here
Dynamic Configuration - File Based
If you are not using Docker (or another orchestrator or service registry) then the dynamic configuration needs to be defined using a standalone file. Like the static configuration file, this can be written in TOML or YAML. The first thing you’ll need to do is to tell Traefik where to find the dynamic configuration. This is accomplished by defining the filename and path (to the dynamic configuration) under the providers section in the static configuration.
(traefik.yml)
...
providers:
file:
filename: "/etc/traefik/dynamic_config.yml"
watch: true
Having defined the path and filename, the dynamic configuration can now be entered. As per the example below, the basic structure will have sections to define any routers, services, and middlewares.
(dynamic_config.yml)
http:
routers:
router1-http:
rule: "Host(`example.com`)"
entryPoints:
- web
middlewares:
- https-redirect
router2-https:
rule: "Host(`example.com`)"
entryPoints:
- websecure
service: site_name_example.com
tls:
certResolver: default
services:
site_name_example.com:
loadBalancer:
servers:
- url: "http://172.2.2.100:90"
middlewares:
https-redirect:
redirectScheme:
scheme: https
...
Wrapping up
My goal here was to help make sense of the different parts of Traefik 2’s configuration and to show that while it may appear complicated, it really isn’t. If your own configuration now appears a little more understandable, or if you find pulling together a new configuration a little easier then I’m glad to have helped. If you have ideas for improvement…lemme know :-)
Here’s a few setup guides that I found useful:
- https://www.simplecto.com/traefik-2-0-docker-and-letsencrypt/
- https://mattsch.com/2020/01/16/notes-on-traefik-v2-nextcloud-etc/
- https://chriswiegman.com/2020/01/running-nextcloud-with-docker-and-traefik-2/
- https://www.smarthomebeginner.com/traefik-2-docker-tutorial/#Traefik_2_Setup
- https://medium.com/@containeroo/traefik-2-0-docker-an-advanced-guide-d098b9e9be96
See Also:
Was this post helpful? or drop me a note in the comments. Thanks.