Traefik: an easy way to secure your applications behing HTTPS
What is Traefik?
Traefik is a very flexible tool :
-
- It can replace Nginx or Apache2 as proxy manager, especially for cloud-based infrastructures for which it has been conceived
- It can manage SSL certificates so that your websites are alway HTTPS-secure using automatically renewed LetEncrypt certificates.
- You can check traffic health for routers, services or middleware using the built-in dashboard
- Official website: https://traefik.io/traefik/
- Documentation: https://doc.traefik.io/traefik/
- Docker images: https://hub.docker.com/_/traefik
How are elements structured ?
For our current need, Traefik will be set as the entrypoint to our private network in which we will be deploying our different ressources.
Traefik will be in charge of redirecting users to the correct server but also generating SSL certificates for all declared sub-domains.
We will also be forcing redirections from HTTP to HTTPS for all available ressources.
Pros and cons
Traefik is a very complete but also complex application so I will only evaluate the implementation described in this article.
Many other possibilities exist and are documented so if you don't find the solution here, either check the Traefik documentation which provides configuration examples for different scenarios or use your favorite search engine.
Important note: the Trafik version described here is V2.
V1 is no longer supported but quite a lot of documentation and articles remains available on-line that are based on it.
And V3 is in it's testing phase as of Oct. 2023 .
Check the release date and support plan.
Setting up Traefik
If you haven't installed docker and docker-compose packages:
Pre-requisites
- A server with Docker installed with the docker-compose package
- Access to the DNS entry management for your domain
- Firewall and network configuration that allows
- HTTP & HTTPS on Traefik server
- communication from Traefik server to our other servers & services in the private network (HTTP/S, TCP, UDP or custom ports)
- Setting up a dedicated Docker Network. In our example, the network traefik has been created running command:
docker network create traefik
Files and folders configuration & setup
For this demonstration, a sub-directory "traefik2
" has been created in /opt containing:
To create the files and folder, go to your chosen directory and run the below commands:
cd /opt/traefik2/
sudo touch acme.json
sudo chmod 600 acme.json
sudo mkdir dynamic
We will then set up the docker-compose.yml to have a working Traefik container and finally add our applications.
docker-compose.yml
version: '3.9' |
Below is a light and quick explaination of what makes the system work. Some elements aren't technically correct but allow for a better understanding of the interactions of the different modules and functions.
If in doubt, always check the official documentation.
-
Setting up the web dashboard
This gives you a visual details of your traefik configurations:
Based on parameters:
command:
- --api.dashboard=true
- --api.insecure=false
[...]
ports:
[...]
# The Web UI (enabled by --api.insecure parameter)
- "8080:8080"
[...]
labels:
- "traefik.enable=true"
###ROUTERS & DASHBOARD##
- "traefik.http.routers.traefik_https.rule=Host(whoami.somedomain.com
)"
[...]
- "traefik.http.routers.traefik_https.middlewares=traefik-auth"
- "traefik.http.routers.http_traefik.middlewares=https_redirect"
##AUTH-DASHBOARD##
- "traefik.http.middlewares.traefik-auth.basicauth.users=dashboarduser:$$2y$$05$$dashboard_hashed_password"
Parameter "--api.dashboard
" will enable the dashboard but with no authentication required.
To make authentication mandatory, "--api.insecure
" is set to false to avoid anonymous API users and "traefik.http.routers.traefik_https.middlewares
" is set to "traefik-auth
".
This will enable a login prompt to appear when accessing the URL set for "traefik.http.routers.traefik_https.rule=Host
":
Parameter "traefik.http.routers.http_traefik.middlewares
" is set for security measures so that we are alway using HTTPS.
And finally, we declare the users we allow access the dashboard to using "traefik.http.middlewares.traefik-auth.basicauth.users
":
- Install apache2-utils package or any other that contains the htpasswd functionnality
- Generate a hashed password
- Double the $ symbols from the resulting string
To make it simple, here is an example with username dashboarduser
:
sudo apt install apache2-utils -y
echo $( sudo htpasswd -nB dashboarduser) | sed -e s/\\$/\\$\\$/g
-
Setting up LetsEncrypt certificate generation
Based on parameters:
command:
[...]
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --certificatesResolvers.letsencrypt.acme.email=contact@somedomain.com
- --certificatesResolvers.letsencrypt.acme.storage=/opt/traefik2/acme.json
- --certificatesResolvers.letsencrypt.acme.caServer=https://acme-v02.api.letsencrypt.org/directory
- --certificatesResolvers.letsencrypt.acme.httpChallenge=true
- --certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=web
[...]
ports:
# The HTTP port
- "80:80"
# The HTTPS port
- "443:443"
[...]
volumes:
[...]
# ACME certificates can be stored in a JSON file with permission mode 600
- ./acme.json:/acme.json
[...]
labels:
- "traefik.enable=true"
###ROUTERS & DASHBOARD##
- "traefik.http.routers.traefik_https.rule=Host(whoami.somedomain.com
)"
- "traefik.http.routers.traefik_https.entrypoints=websecure"
- "traefik.http.routers.traefik_https.tls=true"
- "traefik.http.routers.traefik_https.tls.certResolver=letsencrypt"
The "certificatesResolvers
" parameters are used for the certificate generation and retrieval itself.
Ports 80 and 443 must both be exposed for Traefik even if we will only navigate using 443: port 80 is needed for initial certification.
We will later secure our system by forcing redirection to HTTPS.
File(s) "acme.json
" are declared and must have 600 permissions.
"traefik.http.routers.traefik_https
" parameter calls on the configuration set by "certificatesResolvers
" parameters for a given resolver. For example we could have:
- --certificatesResolvers.letsencrypt.acme.email=contact@somedomain.com
- --certificatesResolvers.letsencrypt.acme.storage=/opt/traefik2/acme.json
- --certificatesResolvers.letsencrypt.acme.caServer=https://acme-v02.api.letsencrypt.org/directory
- --certificatesResolvers.letsencrypt.acme.httpChallenge=true
- --certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=web
- --certificatesResolvers.OVH.acme.email=contact@somedomain.com
- --certificatesResolvers.OVH.acme.storage=/opt/traefik2/ovh/acme.json
- --certificatesResolvers.OVH.acme.dnschallenge.provider=ovh
- --certificatesResolvers.OVH.acme.dnschallenge=true
And then select the certResolver solution depending on weither we want to use LetsEncrypt HTTP Challenge or OVH DNS challenge.
-
HTTP to HTTPS redirection
Based on parameters:
command:
[...]
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
[...]
ports:
# The HTTP port
- "80:80"
# The HTTPS port
- "443:443"
[...]
##REDIRECT-TO SSL##
- "traefik.http.middlewares.https_redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.https_redirect.redirectscheme.permanent=true"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
# AUTOMATIC REDIRECT TO HTTPS
- "traefik.http.routers.redirs.rule=hostregexp({host:.+}
)"
- "traefik.http.routers.redirs.entrypoints=web"
- "traefik.http.routers.redirs.middlewares=redirect-to-https"
Port 80 and 443 must be declared and set as web and websecure adresses.
"traefik.http.middlewares" will allow to redirect and tweak traffic from and to our applications through Traefik.
For example when wanting to send incoming to a non-standard port on your application server.
The "traefik.http.routers" block configured here will:
- take all incoming traffic from the entrypoint "web" which is set as port 80 in "entryPoints.web.address"
- redirect to another URL using the REGEX set in "traefik.http.routers.redirs.rule"
This will force HTTPS redirection at all levels.
-
Providers: defining the applications & servuces managed by Traefik
The provider configuration allows us to set the parameters to be used when managing ressources depending on the type of ressource.
Based on parameters:
command:
[...]
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --providers.file=true
- --providers.file.watch=true
- --providers.file.directory=/opt/traefik2/dynamic/
[...]
volumes:
[...]
- ./dynamic:/opt/traefik2/dynamic:ro
Using "providers.docker.exposedByDefault" ensures that the docker-based applications are only accessible through Traefik if we have labelled them to be so.
In order to be able to manually add services using YAML/TOML, we configure "providers.file.directory" with a directory also declared in the volumes.
"providers.file.watch=true" allows for the addition and removal of services without having to restart Traefik every time.
-
Log management
Logs can be accessed using the "docker logs" command but we can also access logs directly and set the level of logs.
Based on parameters:
command:
[...]
- --accesslog=true
- --accesslog.filePath=/opt/traefik2/logs/access.log
- --log.level=DEBUG
[...]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./logs:/var/log/traefik
-
Docker Network
A network has been created by running command:
docker network create traefik
Based on parameters:
networks:
- traefik
networks:
traefik:
driver: bridge
The bridge network driver is what allows the communication between Traefik and the other ressources.
Configuration is required in the docker-compose.yml but can only work if it is allowed in other networking equipments used such as physical routers (Cisco, Juniper, Fortinet, Netgear...) or software configuration (Ubuntu UFW, AWS Security groups, ...).
Configuring services through file management
In our example, we have set the folder "/opt/traefik2/dynamic/
" in which each service should have its own YML/TOML file to be managed.
For our example, a Redmine server has been set up on a server in our private network using the default port 3000.
Here is the configuration in Traefik:
/opt/traefik2/dynamic/redmine.yml
Content
http:
services:
redmine:
loadBalancer:
servers:
- url: "http://172.192.1.238:3000"
routers:
redmine:
rule: "Host(redmine.nicksopenworld.com
)"
tls:
certResolver: letsencrypt
entryPoints:
- "websecure"
service: redmine
It sets up a service named redmine in the Traefik dashboard that will reroute HTTP communication from/to the private network to/from the HTTPS websecure entrypoint using parameters defined for the "Letsencrypt" certResolver.
In parallel, a DNS entry has been created: sub-domain "redmine" redirects to the traefik server public IP.
Once the DNS update has propagated, Trafik will be able to generate the certificates for HTTPS and service will be made available and secure.
Setup conclusion
This is article is only a starting point for Traefik usage.
In future, we will explore integration with Kubernetes to see how to configure Traefik to manage much more services using the different automation tools available.
We will also be able to explore authentication forwarding using Traefik for example when setting up Single Sign On solutions.
Going further: Docker options, debugging and managing ressources
-
Check logs and debug
If your container restarts all the time, you can check the logs:
sudo docker logs traefik
It will give you the end of the logs. To define how much of the logs to see, option --tail can be used:
sudo docker logs traefik -f --tail 1000
Or if you want to follow the logs as you are using the application
sudo docker logs traefik -f
This is particularly usefull when debuging a specific page loading issue. To check all the log options, you can run:
docker logs --help
Depending on the errors observed, you will need to either:
- correct your docker-compose.yml file
- review your network/database connectivity
-
Accessing the content of the container
Once connected to the Traefik container host, you can log in the container but executing the command:
sudo docker exec -it traefik ash
This can be needed when checking the volumes & files configurations.
-
Example of certificate generation failure due to file permission issues
The Traefik container rarely fails as a service but certificate retrieval and renewal can fail. Unable to add ACME provider to the providers list: unable to get ACME account: permissions 755 for /letsencrypt/acme.json are too open, please use 600
sudo chmod 600 acme.json
sudo docker restart traefik2