Post

Traefik

Introduction

In this post, we’ll walk through the steps to install and configure Traefik as a reverse proxy and load balancer for your Docker environment. Traefik is a powerful tool that dynamically discovers backend services and can automatically generate SSL certificates via ACME providers like Let’s Encrypt.

This guide assumes you are familiar with docker and have it installed on your system if you didnt you can follow our detailed Docker installation guide.

Step 1: Download and Extract Traefik

First, download the appropriate version of Traefik you would like to use for your system from the official Traefik GitHub releases page.

1
2
wget https://github.com/traefik/traefik/releases/download/vX.X.X/traefik_linux_amd64.tar.gz
tar -xzvf traefik_linux_amd64.tar.gz

Step 2: Move Traefik to a System Path

Make the Traefik binary executable and move it to a directory in your system’s PATH:

1
2
chmod +x traefik
sudo mv traefik /usr/local/bin/traefik

To allow Traefik to bind to privileged ports (like 80 and 443) as a non-root user, execute the following command:

1
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/traefik

Step 3: Set Up User and Directories

Now, we’ll create the necessary user, group, and directories for Traefik. This ensures that Traefik runs with limited permissions, improving security.

1
2
sudo groupadd -g 321 traefik docker
sudo useradd -g traefik --no-user-group --home-dir /var/www --no-create-home --shell /usr/sbin/nologin --system --uid 321 traefik

Create the configuration directories:

1
2
3
4
sudo mkdir -p /etc/traefik/{acme,dynamic} /var/log/traefik/
sudo touch /var/log/traefik/{traefik.log,debug.log}
sudo chown -R root:root /etc/traefik
sudo chown -R traefik:traefik /etc/traefik/acme

Set appropriate ownership and permissions:

1
2
sudo chown root:root /etc/traefik/traefik.yaml
sudo chmod 644 /etc/traefik/traefik.yaml /etc/traefik/dynamic/config.yml /var/log/traefik/{traefik.log,debug.log}

Step 4: Create and Configure Traefik Files

You need to place the traefik.yaml configuration file in /etc/traefik/ and config.yml configuration file in /etc/traefik/dynamic/config.yaml.

This file defines global settings, entry points, logging, and providers for Docker and file-based configurations.

Update sample traefik.yaml according to your needs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
################################################################
# Global configuration
################################################################
#global:
#  checkNewVersion = true
#  sendAnonymousUsage = true

################################################################
# API and dashboard configuration
################################################################
api:
  dashboard: true
  debug: true

################################################################
# Traefik logs configuration
################################################################
log:
  level: DEBUG
  filePath: /var/log/traefik/debug.log
  #format: json

accessLog:
  filePath: "/var/log/traefik/traefik.log"
  bufferingSize: 100
  #format: json

################################################################
# EntryPoints configuration
################################################################
entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"

serversTransport:
  insecureSkipVerify: true

################################################################
# Docker configuration backend
################################################################
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    useBindPortIP: true
    network: proxy
    watch: true

  file:
    directory: /etc/traefik/dynamic/
    watch: true

################################################################
# Certificate resolvers
################################################################
certificatesResolvers:
  cloudflare:
    acme:
      email: XXXXXXXXXX
      storage: /etc/traefik/acme/acme.json
      dnsChallenge:
        provider: cloudflare
        #disablePropagationCheck: true # uncomment this if you have issues pulling certificates through cloudflare, By setting this flag to true disables the need to wait for the propagation of the TXT record to all authoritative name servers.
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"                                                                                                                                

Update sample config.yaml according to your needs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
http:
  routers:
    test:
      entryPoints:
        - "https"
      rule: "Host(`test.example.com`)"
      middlewares:
        - secured
      tls:
        certResolver: cloudflare
        domains:
          - main: "example.com"
            sans:
              - "*.example.com"
      service: test

  traefik:
    entryPoints:
      - "https"
    rule: "Host(`traefik-detract.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
    middlewares:
      - default-headers
    tls:
      certResolver: cloudflare
      domains:
        - main: "example.com"
          sans:
            - "*.example.com"
    service: api@internal

############################################################################################
### services
############################################################################################
  services:
    test:
      loadBalancer:
        sticky:
          cookie:
            secure: true
            httpOnly: true
        servers:
          - url: "https://$IP:$PORT/"
        passHostHeader: true

############################################################################################
### middlewares
############################################################################################
  middlewares:
    https-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true

    gzip:
      compress: {}

    default-headers:
      headers:
        frameDeny: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 15552000
        customFrameOptionsValue: SAMEORIGIN
        customRequestHeaders:
          X-Forwarded-Proto: https
        customResponseHeaders:
          Access-Control-Allow-Origin: "*"

    cors:
      headers:
        accessControlAllowOriginList: ["*"]
        accessControlAllowCredentials: true
        accessControlAllowHeaders: ["*"]
        accessControlAllowMethods: ["*"]
        accessControlMaxAge: 100
        addVaryHeader: true

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

Step 5: Create Systemd Service

Create a systemd service file for Traefik to manage its lifecycle.

1
2
3
sudo nano /etc/systemd/system/traefik.service
sudo chown root:root /etc/systemd/system/traefik.service
sudo chmod 644 /etc/systemd/system/traefik.service

Update sample traefik.service according to your needs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[Unit]
Description=Traefik
Documentation=https://doc.traefik.io/traefik/
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]

Environment="CF_API_EMAIL=XXXXXXXXXX"
Environment="CF_DNS_API_TOKEN=XXXXXXXXXX"
Environment="CF_API_KEY=XXXXXXXXXX"

Restart=always
RestartSec=3

; User and group the process will run as.
User=traefik
Group=traefik

; Always set "-root" to something safe in case it gets forgotten in the traefikfile.
ExecStart=/usr/local/bin/traefik --configfile=/etc/traefik/traefik.toml --api=true --api.insecure=true --api.dashboard=true --api.debug=true

; Limit the number of file descriptors; see `man systemd.exec` for more limit settings.
LimitNOFILE=1048576

; Use private /tmp and /var/tmp, which are discarded after traefik stops.
PrivateTmp=true

; Use a minimal /dev (May bring additional security if switched to 'true', but it may not work on Raspberry Pis or other devices, so it has been disabled in this dist.)
PrivateDevices=false

; Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
ProtectHome=true

; Make /usr, /boot, /etc and possibly some more folders read-only.
ProtectSystem=full

; … except /etc/ssl/traefik, because we want Letsencrypt-certificates there.
;   This merely retains r/w access rights, it does not add any new. Must still be writable on the host!
ReadWriteDirectories=/etc/traefik/acme

; The following additional security directives only work with systemd v229 or later.
; They further restrict privileges that can be gained by traefik. Uncomment if you like.
; Note that you may have to add capabilities required by any plugins in use.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Reload systemd and start the Traefik service:

1
2
sudo systemctl daemon-reload
sudo systemctl start traefik.service

To enable Traefik to start automatically at boot:

1
sudo systemctl enable traefik.service

traefik

Conclusion

You now have Traefik up and running, configured to work with Docker and your Cloudflare DNS for SSL certificates. For more advanced configurations, such as setting up middlewares or further customizing TLS options, refer to the official Traefik documentation.

This post is licensed under CC BY 4.0 by the author.