This post tends to give you some custom configuration files to work with Traefik and TLS.
Version | Date | Comment |
---|---|---|
1 | 05/2022 | Post creation |
Goal : Configure Traefik with custom TLS settings
Environment : Debian 11.7
, Docker 23.x
, docker compose (plugin) 2.17.x
, Traefik 2.x
Execution context :
jho@vmi866042:/srv/docker/dc$ tree
.
├── conf
│  ├── acme.json
│  ├── traefik.yml
│  ├── traefikdynamic
│  │  ├── general.yml
│  │  ├── routersservices.yml
├── docker-compose.yml
└── logs
├── traefikAccess.log
├── traefik.log
docker-compose configuration file
Forward, you can't use the two types of configuration (static and dynamic) at the same time, it is only once. I prefer dynamic configuration, here's a quick reminder.
Let's prepare the docker-compose.yml
file:
---
services:
traefik:
image: traefik:v2.6
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
- ./conf/traefikdynamic:/etc/traefik/dynamic:ro
- ./acme.json:/etc/traefik/acme.json
- ./logs/traefik.log:/etc/traefik/applog.log
Traefik configuration
Every configuration files here are stored in the “conf” folder. You can change the path to where you want, but remember to update your docker-compose file for it.
Content of the file traefik.yml
:
---
global:
sendAnonymousUsage: false
checkNewVersion: false
api:
dashboard: true
pilot:
dashboard: false
log:
filePath: "/etc/traefik/applog.log"
format: json
level: "ERROR"
providers:
docker:
endpoint: unix:///var/run/docker.sock
exposedByDefault: false
watch: true
swarmMode: false
file:
directory: "/dynamic"
watch: true
api:
dashboard: true
debug: false
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: contact@domain.local
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
# caServer: https://acme-v02.api.letsencrypt.org/directory
storage: "/etc/traefik/acme.json"
keyType: EC256
httpChallenge:
entryPoint: web
In this file, one important bloc is “provider” with the definition of a “dynamic” folder path. This folder is created locally to have the file “traefik_dynamic.yml”.
The line watch = true
allows Traefik to watch changes in the configuration files and applies them when an update is done.
Certificates are generated with Let's Encrypt ; indeed, Traefik uses its internal tool “lego”. When you are in build mode, you should use “staging” server, which have a less aggressive limiter than the “acme-v02”. In production environment, use the “acme-v02” server from Let's Encrypt.
Dynamic configuration file is the same type as the main configuration file (YAML), difference is the settings. Here's my dynamic configuration file “traefik_dynamic.yml”, in the folder “conf/traefikdynamic” :
---
tls:
options:
default:
minVersion: VersionTLS12
sniStrict: true
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_AES_128_CBC_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
alpnProtocols:
- h2
- http/1.1
mintls13:
minVersion: VersionTLS13
http:
middlewares:
compression:
compress:
excludedContentTypes:
- text/event-stream
security:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
addVaryHeader: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
stsPreload: true
customFrameOptionsValue: SAMEORIGIN
referrerPolicy: "origin-when-cross-origin"
permissionsPolicy: "camera 'none'; microphone 'none'; geolocation 'none'; payment 'none';"
stsSeconds: 315360000
hostsProxyHeaders:
- "X-Forwarded-Host"
Some explanations :
- TLS block specify every needed options to have an optimal configuration. Minimal version of TLS is 1.2 with newer algorithms used by modern navigators ;
- HTTP bloc have 2 “under-blocs” :
- a middleware to compress some flux aside streaming
- a middleware for every security about HTTPS (headers)
Configuration files are ready, you now have to set up your services in the docker-compose.yml file. Here's what you need for every services behind Traefik :
labels:
traefik.enable: "true"
traefik.http.routers.service-https.entrypoints: "websecure"
traefik.http.routers.service-https.middlewares: "security@file, compression@file"
traefik.http.routers.service-https.tls: "true"
traefik.http.routers.service-https.tls.certresolver: "letsencrypt"
Middlewares security@file
and compression@file
are drawn in the file traefik_dynamic.yml
.
When you set the docker labels, don't forget to re-up your containers (docker-compose up -d
).
If you don't use docker labels, you can add these blocs in the “traefikdynamic.yml” – information about “routers” and “services” next to  the TLS configuration, in the bloc http
: (for example, I'm using Portainer)
services:
sc-portainer:
loadBalancer:
servers:
- url: "http://portainer:9000"
routers:
rt-portainer:
entryPoints:
- websecure
middlewares:
- security
- compression
service: sc-portainer
rule: Host(`portainer.domain.local`)
tls:
certResolver: letsencrypt
You don't have to restart containers when you're done updates in the file “traefikdynamic.yml”. Updates (dynamic configuration) are taken when running.