How to set up the Traefik v2 Reverse Proxy for Docker on Debian / Ubuntu
Introduction
Docker alone makes the life of a system administrator quite easy. You install the docker engine on the system you want to deploy your application to, build your own container with the components you need and then run it in the development environment or deploy the container directly to the production system. What can sometimes be a little bit complicated is that you normally can't run multiple web applications at the same time on port 80 & 443, or that you have to create the Let's Encrypt certificates for each service separately. For all these problems there is an elegant solution thanks to Traefik. So today I will write about Traefik (version 2): A reverse proxy that takes some of the tedious work off your hands and which can be easily extended with new services!
Prerequisites
- A system you have access to, preferably a Linux-based system with a public IP address and a domain pointing to it
- Docker & docker-compose installed on the system (see my post about how to do this here)
- Elevated privileges (via sudo) or access to the root user
- Internet connection
Installation & Configuration
Step 1: Update the Linux system
Before setting up an application on your Linux server, it is a good idea to upgrade the system in advance to be up to date. To do this, we call
$ sudo apt update
$ sudo apt upgrade -y
and the upgrade process should start.
It is also worth installing these upgrades automatically and unattended. I've already written a guide on the subject.
After a successful upgrade, it is recommended that you reboot the system to load the new Linux kernel and get the services up and running with the updated binaries.
Step 2: Install apache2-utils
We need to install apache2-utils so we can use htpasswd
to generate our password for the Traefik web interface. Note, only the Apache utils are installed and not the Apache2 web server itself!
# If you haven't done so already, update your package lists
$ sudo apt update
# Now install the package
$ sudo apt install apache2-utils
Step 3.1: Create the required files and directories
The data of the Traefik container and its configuration files must be stored somewhere. Therefore we need to create some directories and the initial files for Traefik to work with.
# First we create a directory that contains all subdirectories, data and configuration files.
$ sudo mkdir -p /opt/containers/traefik
# Now we create some files and directories that we will need later on
$ sudo mkdir -p /opt/containers/traefik/data
$ sudo touch /opt/containers/traefik/data/acme.json
$ sudo chmod 600 /opt/containers/traefik/data/acme.json
$ sudo touch /opt/containers/traefik/data/traefik.yml
Step 3.2: Modify the configuration file of Traefik
Now we need to do our initial configuration for Traefik. The provided configuration should work just fine by replacing youremail@example.org
with your own email address. This is required for Let's Encrypt to work properly, as you will receive notifications if your certificates are about to expire.
# Open the config file with your favourite editor such as vim, nano or joe
$ sudo vim /opt/containers/traefik/data/traefik.yml
# Now paste the content down below into the file
api:
dashboard: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: "./dynamic_conf.yml"
certificatesResolvers:
http:
acme:
email: youremail@example.org # Change this to your valid email address
storage: acme.json
httpChallenge:
entryPoint: http
Step 3.3: Create the docker-compose.yml file
It's time for us to create a Docker compose file for the Traefik service, where we do some additional configuration and point to the files and directories we just created.
$ sudo vim /opt/containers/traefik/docker-compose.yml
# Paste the content down below into the docker-compose.yml file
version: '3.8'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- 80:80
- 443:443
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
- ./data/dynamic_conf.yml:/dynamic_conf.yml
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.example.org`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=USER:PASSWORD"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=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.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=http"
- "traefik.http.routers.traefik-secure.service=api@internal"
- "providers.file.filename=/dynamic_conf.yml"
- "traefik.http.routers.traefik-secure.middlewares=secHeaders@file,traefik-auth"
networks:
proxy:
external: true
We still need to change some things
- Change the hostname from
traefik.example.org
to your own valid (sub-)domain - Set your own username and password for the traefik web interface
Changing the username and password
For this purpose, we installed apache2-utils earlier. Now it's htpasswd's time to shine.
# You have to replace "user" and "password" with the values you want to use later to authenticate against traefik
$ echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
Output should be something like this:
user:$$apr1$$7ciH.Uzt$$DUqDgmpLmFE2Fm7Z7VaMe/
Now we need to replace the placeholder values with the output we've just got.
Change "traefik.http.middlewares.traefik-auth.basicauth.users=USER:PASSWORD"
where USER:PASSWORD is the output you just received.
Step 3.4: Create the dynamic_conf.yml file
This file defines which ciphers we want to use and adds some optional security headers (in the form of a traefik middleware)
$ sudo vim /opt/containers/traefik/data/dynamic_conf.yml
# Paste the content down below into the dynamic_conf.yml file
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
secHeaders:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
sslRedirect: true
# HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
Step 3.5: Create a docker network
We now need to create an internal network through which our containers will communicate with Traefik. In our case we will call it a proxy.
$ sudo docker network create proxy
Step 4: Starting Traefik
We're now able to start Traefik.
sudo docker-compose -f /opt/containers/traefik/docker-compose.yml up -d
You should now be able to log in to your Traefik domain (here: https://traefik.example.org) with your previously configured credentials. After successful authentication, you will be welcomed by the Traefik dashboard.