My beginnings with Traefik
2020-04-29T00:08:08+02:00 | 9 minute read | Updated at 2020-04-29T00:08:08+02:00

I’m sharing with you my beginnings with the “Edge Router” Traefik one its 2.X version.
Introduction
Traefik is an open source reverse-proxy written in Go,
which is also named as a Edge Router.
Its logo proves it :
In version 1, it only rerouted HTTP (S) requests. Since version 2, it works for all TCP type applications.
Writing an article on Traefik is not the easiest … That’s why I’m going to do it in parts (as I learn about the solution). In order to do my best to present its usage, we will deploy some Nginx containers which will be accessible via Traefik. Before that, we will launch Traefik with its dashboard secured with basic authentication. This will allow us to understand the concepts of Traefik.
[!WARNING] This article does not cover the HTTPS part.
I advise you to follow this tutorial on a Linux machine with a web browser. To complicate my life, I give a try on Lubuntu 20.04.
Preparation
To be able to run the examples in this tutorial,
you need to add some entries in your /etc/hosts
file.
sudo cp /etc/hosts /etc/hosts.bak # we do a backup !
echo "#### <Traefik tests> ####" | sudo tee -a /etc/hosts
echo "127.0.0.1 traefik.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 pgo.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 hommell.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 site-audi.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 bmw-site.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 trucexterne.example.com" | sudo tee -a /etc/hosts
echo "#### </Traefik tests> ####" | sudo tee -a /etc/hosts
🚗 These names refer to car brands (except for “trucexterne”
which refer to “someting external” in french…). 🚗
We check our new entries :
for i in traefik pgo hommell site-audi bmw-site; do ping -c 1 ${i}.example.com &> /dev/null && echo OK || echo FAIL $i; done
Of course, you need Docker and also Docker Compose :
sudo apt update
sudo apt install docker.io docker-compose
systemctl start docker
systemctl enable docker # activate Docker on boot
Traefik
First launch
Traefik requests access to the Docker socket, so it will be necessary to launch the docker-compose as root.
I work in the following environment :
sudo -i # we switch to root
mkdir -p docker/traefik
cd docker/traefik
So let’s create our docker-compose.yml
as in the quick-start of the
official documentation :
version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.2
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
So we launch our docker-compose (docker-compose up -d
).
We then browse on the port 8080 (http://localhost:8080)
which give us unsecured connexion to the dashboard.
Port 80 doesn’t give anything because we don’t have any service routed to it yet.
If it works, you are ready to get down to business.
So we take a Panadol and we destroy our container with a docker-compose down
.
Authenticated Dashboard
Concepts
The solution can be configured in several ways. You will find three methods :
- Static configuration
- Dynamic configuration with files
- Dynamic configuration with labels (Docker)
Traefik’s strength lies in its dynamic feature :
once properly configured and launched, no need to reload it
each time new services are added (no systemctl apache reload
for example).
Here, we will cover the three ways of doing those in the following respective way :
- Traefik configuration
- Authenticated Dashboard configuration
- Additional services configuration (next part)
Application
We modify our docker-compose.yml
as follows :
version: '3'
services:
reverse-proxy:
# Traefik v2.2 officiel
image: traefik:v2.2
ports:
# The HTTP port
- "80:80"
# Dashboard
- "8080:8080"
volumes:
# Mapping static configuration
- ./traefik.yml:/etc/traefik/traefik.yml
# Mapping dynamic configuration folder
- ./dyn_traefik/:/etc/dyn_traefik/
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
We therefore simplify this file by removing the command:
directive.
The relative information will be specified in the traefik.yml
file.
The dyn_traefik
folder will contain configuration file for dynamic config :
only one in our case, that of the dashboard which represents our first service.
So, we create the file traefik.yml
in our working folder with
the following content :
entryPoints:
web:
address: ':80'
dashboard:
address: ':8080'
log:
# Default: "ERROR"
level: INFO
api:
dashboard: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
# Expose containers by default in traefik
exposedByDefault: true
# Enable the file provider to define routers / middlewares / services in file
file:
directory: /etc/dyn_traefik/
watch: true
You often have this file in TOML format, I preferred to do it in YAML
to remain consistent with the other files already in this language.
I put the logs at “INFO” level to have a little more info just in case.
The option watch: true
tells Traefik to listen to the updates of this folder.
We then create the folder dyn_traefik
.
In it, I created a dashboard.yml
as follow :
http:
routers:
api:
rule: "Host(`traefik.example.com`)"
service: api@internal
middlewares:
- auth
middlewares:
auth:
basicAuth:
users:
- "admin:$2y$10$sqgVdrmQxXQgYIpg3BycVuZ2J8sFSHheVnmd728KkE7fznFSlxA0u"
- "test:$2y$10$mPcvlMccO2mXjA2ye.uBWuhO36x46K/3b.g1AjJ1YllmKCSAuS.vG"
With this configuration, the dashboard is reachabled with the URL traefik.example.com and will benefit of a basic authentication with the accounts “admin” and “test” which passwords are respectively “admin” and “test”.
To generate hashes of your passwords, you can learn french and check another article.
Hit a docker-compose up -d
and test the dashboard access.
Cool right ? 😎
Adding containers “internal”
We will now add two services to our Docker Compose file.
These two services will simply be Nginx servers with specific
web pages to identify them properly.
So we add the following content to our file :
pgo:
image: nginx:alpine
volumes:
- ./index-pgo.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.pgo.rule=Host(`pgo.example.com`)
hommell:
image: nginx:alpine
volumes:
- ./index-hommell.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.hommell.rule=Host(`hommell.example.com`)
Those “labels” are there to dynamically configure Traefik.
The less obvious line is :
traefik.http.routers.<container_name>.rule=Host(`<some_url>`)
Write as above, it’s more meaningful, isn’t it?
So, we create the home pages for our websites :
echo "<h1>Prévôt : Gilles and Olivier</h1>" > index-pgo.html
echo "<h1>Automobiles Michel Hommel</h1>" > index-hommell.html
Thus, we update our Docker Compose (no need to stop or destroy it) with the usual command.
The dashboard may show new entries in the router section the URLs (pgo.example.com & hommell.example.com) should show their respective website.
You can notice that we didn’t have to map 80 ports of our containers.
It’s normal because the containers were create in the same network as Traefik
(because we are in the same docker-compose.yml
).
Thereby
As a result, it is indeed our routing agent Traefik who performs the routing.
[!IMPORTANT] So I have to put all my container definitions in the same Docker Compose ?
The answer and no and this is what we will see in the next part.
Adding containers “external”
Updating Docker Compose file
To be able to connect other containers to our reverse-proxy,
we are going to use networks within Docker.
We create a autoroute
network definition in bridge called motorway
(you will understand why after 😉).
This feature requires is introduced in version 3.5 of Docker Compose.
So I also changed the version of my file to the last one I can:
3.7 since I have version 1.25 of Docker Compose.
We destroy our current stack with a docker-compose down
and we modify the file.
So here is my updated file :
version: '3.7'
services:
reverse-proxy:
# Traefik v2.2 officiel
image: traefik:v2.2
ports:
# The HTTP port
- "80:80"
# Dashboard
- "8080:8080"
volumes:
# Mapping static configuration
- ./traefik.yml:/etc/traefik/traefik.yml
# Mapping dynamic configuration folder
- ./dyn_traefik/:/etc/dyn_traefik/
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
networks:
- autoroute
pgo:
image: nginx:alpine
volumes:
- ./index-pgo.html:/usr/share/nginx/html/index.html
labels:
- traefik.http.routers.pgo.rule=Host(`pgo.example.com`)
- traefik.port=80
- traefik.enable=true
networks:
- autoroute
hommell:
image: nginx:alpine
volumes:
- ./index-hommell.html:/usr/share/nginx/html/index.html
labels:
- traefik.http.routers.hommell.rule=Host(`hommell.example.com`)
- traefik.port=80
- traefik.enable=true
networks:
- autoroute
networks:
autoroute:
driver: bridge
name: motorway
We “up” all this and we check that our three services are still accessible before moving on.
Creating another Docker Compose
We position ourselves in another folder and we create the files for Audi and BMW like those for PGO and Hommel:
mkdir -p ../german && cd ../german
echo "<h1>Auto Union Deutsches Industrie</h1>" > index-audi.html
echo "<h1>Bayerische Motoren Werke</h1>" > index-bmw.html
And the docker-compose.yml
file :
version: '3.7'
services:
audi:
image: nginx:alpine
volumes:
- ./index-audi.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.audi.rule=Host(`site-audi.example.com`)
networks:
- autobahn
bmw:
image: nginx:alpine
volumes:
- ./index-bmw.html:/usr/share/nginx/html/index.html
labels:
- traefik.enable=true
- traefik.port=80
- traefik.http.routers.bmw.rule=Host(`bmw-site.example.com`)
networks:
autobahn:
external:
name: motorway
After launching this Docker Compose, we test the accessibility of
German car websites and we realize that BMW’s does not work !
This is due to the fact that BMW is not in the “autobahn”
(that the container is not in the defined network).
I take this example a little too seriously…
[!TIP] Containous (the company behind Traefik), PGO and Hommell are french (“autoroute” is the french for motorway) while Audi and BMW are german.
The two docker-composers represent France and Germany ! Hence the network names in their respective official language and a common network name (“highway”) in the international language.
So you understand that, by this example, it is no longer necessary to touch the Traefik container. The ideal would therefore surely be to have a composition with Traefik alone.
Adding external services
Finally, we are going to reverse-proxy the content of an external server.
So I launched an Nginx on another server with a simple docker run
:
docker run --name tteesstt -d -p 999:80 nginx:alpine
I then checked that I have access to the content from the server where Traefik is installed by browsing to the IP address of the server and the specified port.
So, we create a new dynamic configuration file in the dyn_traefik
folder.
I called mine azerty.yml
with the following content :
http:
services:
administration:
loadBalancer:
servers:
- url: "http://192.168.92.17:999/"
routers:
administration:
rule: "Host(`trucexterne.example.com`)"
service: administration@file
I referenced this app under the name administration
because I run out of idea.
The @file
specify that we use the provider “file” (cf. traefik.yml
).
Destruction
Docker
On the external server :
docker stop tteesstt
docker system prune --all --volumes # Removes everything that is not used
On the server where Traefik and launched :
# By positioning myself in the `docker` folder
cd german && docker-compose down && cd ..
cd traefik && docker-compose down && cd ..
docker system prune --all --volumes
In case you want to delete the configuration files :
rm -rf ./*
Don’t forget to delete the entries from your /etc/hosts
file.
If you did it like me:
mv /etc/hosts /etc/hosts.old && mv /etc/hosts.bak /etc/hosts
rm /etc/hosts.old
Conclusion
This article shows (in my own way) how to use Traefik. This tool is very powerful and it’s not very user firendly… Moreover, the official documentation doesn’t really help.
A next tutorial on Traefik (shorter I hope) will present Traefik in HTTPS via Let’s Encrypt certificates with probably other routing options.