A complete Traefik configuration 🚥
Tags: traefik, docker, devops
Published: 2021-09-10 00:39:37

---
title: A complete Traefik configuration 🚥
published: true
date: 2021-08-19 23:15:00 UTC
tags: traefik, docker, devops
canonical_url: https://www.benjaminrancourt.ca/a-complete-traefik-configuration
cover_image: https://www.benjaminrancourt.ca/images/pexels-mohamed-almari-1485894-1.jpg
---
If you're lucky, someone else in your organization may have already configured [**Traefik**](https://doc.traefik.io/traefik/), an HTTP reverse proxy and load balancer for microservices. Otherwise, you can follow their [tutorial](https://doc.traefik.io/traefik/getting-started/quick-start/) to quickly launch the application with docker-compose.

But, if you are ready to improve your installation, you can read the [**official documentation**](https://doc.traefik.io/traefik/). Or, if you are like me, you may want to check other people's setups. 😉

I have decided to share with you my personal configuration of Traefik below. It can inspire you to explore concepts that you are not yet familiar with. I won't particularly describe each instruction, so if in doubt, check their documentation! 🤷

> This configuration below is made for Docker Swarm and all files are written in YAML. If your configuration is in [TOML](https://en.wikipedia.org/wiki/TOML) format, you should be able to switch easily between them.

## Static configuration (traefik.yml)

```yaml
# Traefik static configuration file (/etc/traefik/traefik.yml)
# See https://doc.traefik.io/traefik/getting-started/configuration-overview/#the-static-configuration
# and https://doc.traefik.io/traefik/reference/static-configuration/cli/

api:
  dashboard: true # Enable the dashboard

# Certificate Resolvers are responsible for retrieving certificates from an ACME server
# See https://doc.traefik.io/traefik/https/acme/#certificate-resolvers
certificatesResolvers:
  letsEncrypt:
    acme:
      email: "letsEncrypt@benjaminrancourt.ca" # Email address used for registration
      storage: "/etc/traefik/acme/acme.json" # File or key used for certificates storage
      tlsChallenge: {}

entryPoints:
  http:
    address: ":80" # Create the HTTP entrypoint on port 80
    http:
      redirections: # HTTPS redirection (80 to 443)
        entryPoint:
          to: "https" # The target element
          scheme: "https" # The redirection target scheme
  https:
    address: ":443" # Create the HTTPS entrypoint on port 443

global:
  checknewversion: true # Periodically check if a new version has been released.
  sendanonymoususage: true # Periodically send anonymous usage statistics.

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock" # Listen to the UNIX Docker socket
    exposedByDefault: false # Only expose container that are explicitly enabled (using label traefik.enabled)
    network: "traefik-net" # Default network to use for connections to all containers.
    swarmmode: true # Activates the Swarm Mode (instead of standalone Docker).
    swarmModeRefreshSeconds: 15 # Defines the polling interval (in seconds) in Swarm Mode.
    watch: true # Watch Docker Swarm events
  file:
    filename: "/etc/traefik/config.yml" # Link to the dynamic configuration
    watch: true # Watch for modifications
  providersThrottleDuration: 10 # Configuration reload frequency

```
<figcaption>The <strong>static configuration</strong> file, in the <code>traefik.yml</code> file.</figcaption>
## Dynamic configuration (config.yml)

> Psst, if you want to replace a value from any of the middleware below, check out my post titled [How to override an HTTP header in Traefik](https://www.benjaminrancourt.ca/how-to-override-an-http-header-in-traefik)!

```yaml
# Traefik dynamic configuration file
# See https://doc.traefik.io/traefik/getting-started/configuration-overview/#the-dynamic-configuration

http:
  middlewares:
    # A basic authentification middleware, to protect the Traefik dashboard to anyone except myself
    # Use with traefik.http.routers.myRouter.middlewares: "traefikAuth@file"
    traefikAuth:
      basicAuth:
        users:
          - "admin:PASSWORD_HASHED"

    # Recommended default middleware for most of the services
    # Use with traefik.http.routers.myRouter.middlewares: "default@file"
    # Equivalent of traefik.http.routers.myRouter.middlewares: "default-security-headers@file,error-pages@file,gzip@file"
    default:
      chain:
        middlewares:
          - default-security-headers
          - error-pages
          - gzip

    # Add automatically some security headers
    # Use with traefik.http.routers.myRouter.middlewares: "default-security-headers@file"
    default-security-headers:
      headers:
        browserXssFilter: true # X-XSS-Protection=1; mode=block
        contentTypeNosniff: true # X-Content-Type-Options=nosniff
        forceSTSHeader: true # Add the Strict-Transport-Security header even when the connection is HTTP
        frameDeny: true # X-Frame-Options=deny
        referrerPolicy: "strict-origin-when-cross-origin"
        sslRedirect: true # Allow only https requests
        stsIncludeSubdomains: true # Add includeSubdomains to the Strict-Transport-Security header
        stsPreload: true # Add preload flag appended to the Strict-Transport-Security header
        stsSeconds: 63072000 # Set the max-age of the Strict-Transport-Security header (63072000 = 2 years)

    # Serve the error pages when the status is included inside the following ranges
    # Use with traefik.http.routers.myRouter.middlewares: "error-pages@file"
    error-pages:
      errors:
        query: "erreur{status}/"
        service: traefik-error-pages
        status:
          - "403-404"
          - "500"
          - "503"

    # Enables the GZIP compression (https://docs.traefik.io/middlewares/compress/)
    # if the response body is larger than 1400 bytes
    # if the Accept-Encoding request header contains gzip
    # if the response is not already compressed (Content-Encoding is not set)
    # Use with traefik.http.routers.myRouter.middlewares: "gzip@file"
    gzip:
      compress: {}

  services:
    # Error pages
    traefik-error-pages:
      loadBalancer:
        servers:
          - url: "https://www.usherbrooke.ca/error-pages/"

# See https://doc.traefik.io/traefik/https/tls/
tls:
  options:
    # To use with the label "traefik.http.routers.myrouter.tls.options=modern@file"
    modern:
      minVersion: "VersionTLS13" # Minimum TLS Version
      sniStrict: true # Strict SNI Checking
    
    # To use with the label "traefik.http.routers.myrouter.tls.options=intermediate@file"
    intermediate:
      cipherSuites:
        - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
        - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
        - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
        - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
        - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
        - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
      minVersion: "VersionTLS12" # Minimum TLS Version
      sniStrict: true # Strict SNI Checking
    
    # To use with the label "traefik.http.routers.myrouter.tls.options=old@file"
    old:
      cipherSuites:
        - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
        - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
        - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
        - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
        - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
        - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
        - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
        - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
        - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
        - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
        - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
        - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
        - "TLS_RSA_WITH_AES_128_GCM_SHA256"
        - "TLS_RSA_WITH_AES_256_GCM_SHA384"
        - "TLS_RSA_WITH_AES_128_CBC_SHA256"
        - "TLS_RSA_WITH_AES_128_CBC_SHA"
        - "TLS_RSA_WITH_AES_256_CBC_SHA"
        - "TLS_RSA_WITH_3DES_EDE_CBC_SHA"
      minVersion: "TLSv1" # Minimum TLS Version
      sniStrict: true # Strict SNI Checking

# Generated 2021-08-12, Mozilla Guideline v5.6, Traefik 2.4.8
# https://ssl-config.mozilla.org/#server=traefik&version=2.4.8&config=old&guideline=5.6
# https://ssl-config.mozilla.org/#server=traefik&version=2.4.8&config=intermediate&guideline=5.6
```
<figcaption>The <strong>dynamic configuration</strong> file, in the <code>config.yml</code> file.</figcaption>
## docker-compose.yml

```yaml
version: "3.8"

services:
  traefik:
    deploy:
      labels:
        traefik.docker.network: "traefik-net"
        traefik.enable: "true"
        traefik.http.routers.traefik.entrypoints: "https"
        traefik.http.routers.traefik.middlewares: "traefikAuth@file,default@file"
        traefik.http.routers.traefik.rule: "Host(`${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}`)"
        traefik.http.routers.traefik.service: "api@internal"
        traefik.http.routers.traefik.tls.certresolver: "letsEncrypt"
        traefik.http.routers.traefik.tls.options: "modern@file"
        traefik.http.routers.traefik.tls: "true"
        traefik.http.services.traefik.loadbalancer.server.port: 8080
        traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly: "true"
        traefik.http.services.traefik.loadbalancer.sticky.cookie.secure: "true"
      mode: global
      # Schedule Traefik on the Swarm manager nodes, as the Swarm API is only exposed on the manager nodes
      # See https://docs.traefik.io/providers/docker/#docker-api-access_1
      placement:
        constraints:
          - node.role == manager
    # Published on https://hub.docker.com/_/traefik?tab=tags
    image: traefik:2.4.8 # See https://github.com/containous/traefik/releases
    networks:
      - traefik-net
    ports:
      # To be able to listen on port 80 (http)
      - mode: host
        published: 80
        target: 80
      # To be able to listen on port 443 (https)
      - mode: host
        published: 443
        target: 443
    volumes:
      - /etc/localtime:/etc/localtime:ro # Set the container timezone by sharing the read-only localtime
      - /home/ranb2002/traefik/config.yml:/etc/traefik/config.yml:ro # Set the dynamic configuration for the file provider
      - /home/ranb2002/traefik/traefik.yml:/etc/traefik/traefik.yml:ro # Set the static configuration
      - /var/opt/traefik:/etc/traefik/acme # Set the location where my ACME certificates are saved to
      - /var/run/docker.sock:/var/run/docker.sock:ro # Give access to the UNIX Docker socket

networks:
  traefik-net:
    driver: overlay
    external: true

```
<figcaption>The <code>docker-compose.yml</code> file for Traefik.</figcaption>

> If you want an example of another application using the Traefik labels, check out the **Code section** of my [_Testing certificates generated by Traefik and Let's Encrypt_](https://www.benjaminrancourt.ca/testing-certificates-generated-by-traefik-and-lets-encrypt#code) post.

If you have any tips for improving this setup, let me know! 😎