Skip to content

Traefik

This guide on Traefik will demonstrate how the application is set up and how to use this reverse proxy tool. The examples used in this document are basic configurations. This set‑up includes using Authelia as middleware.

INFO

Traefik is a leading modern reverse proxy and load balancer that makes deploying microservices easy. Traefik integrates with your existing infrastructure components and configures itself automatically and dynamically.

First, ensure that you have created a custom Docker network; we will discuss why this is the preferred method further into the guide. For this example, we will use the custom Docker network called "proxy".

bash
docker network create proxy

Let's create the folder to add this Compose file to. You might save your app's data in another location, so adjust the path accordingly.

bash
mkdir -p /opt/appdata/traefik

Traefik needs a file called acme.json to store the SSL certificate information, and this needs to be secure. We'll create this file and change the permissions accordingly.

bash
touch /opt/appdata/traefik/acme.json; chmod 600 /opt/appdata/traefik/acme.json

Docker Compose

WARNING

It is crucial all containers used with Traefik share a common network. In this case proxy is being used. They must all be defined under networks: at the bottom of each Compose file.

yaml
version: "3"
services:

  traefik:
    container_name: traefik
    image: traefik:latest
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/appdata/traefik/files:/etc/traefik/
    networks:
      - proxy
    labels:
      traefik.enable: true
      traefik.http.routers.api.rule: Host(`traefik.DOMAIN.COM`)
      traefik.http.routers.api.entryPoints: https
      traefik.http.routers.api.service: api@internal
      traefik.http.routers.api.middlewares: auth@file
    environment:
      CF_DNS_API_TOKEN: CLOUDFLARE_API_KEY_HERE # required when Let's Encrypt cannot contact the IP to verify the domain
    restart: unless-stopped

networks:
  proxy:
    driver: bridge
    external: true

Traefik Configuration

A configuration file called traefik.yml can be created. This will host most of the configuration needed for Traefik to run. Any changes to this file will require the container to be restarted for them to apply. Once this configuration is set, it is uncommon for it to be edited very frequently.

yaml
global:
  checkNewVersion: true
  sendAnonymousUsage: false

serversTransport:
  insecureSkipVerify: true
  forwardingTimeouts:
    dialTimeout: 1s

entryPoints:
  # Not used in apps, but redirect everything from HTTP to HTTPS
  http:
    address: :80
    forwardedHeaders:
      trustedIPs: &trustedIps
        - 100.64.0.0/10 # Tailscale network
        - 172.19.0.0/16 # Docker network
        - 173.245.48.0/20 # List of CF IPs
        - 103.21.244.0/22
        - 103.22.200.0/22
        - 103.31.4.0/22
        - 141.101.64.0/18
        - 108.162.192.0/18
        - 190.93.240.0/20
        - 188.114.96.0/20
        - 197.234.240.0/22
        - 198.41.128.0/17
        - 162.158.0.0/15
        - 104.16.0.0/12
        - 172.64.0.0/13
        - 131.0.72.0/22
        - 2400:cb00::/32
        - 2606:4700::/32
        - 2803:f800::/32
        - 2405:b500::/32
        - 2405:8100::/32
        - 2a06:98c0::/29
        - 2c0f:f248::/32
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https

  # HTTPS endpoint, with domain wildcard
  https:
    address: :443
    forwardedHeaders:
      trustedIPs: *trustedIps
    http:
      tls:
        certResolver: letsencrypt
        domains:
          - main: domain.xyz
            sans:
              - '*.domain.xyz'

          - main: domain2.com
            sans:
              - '*.domain2.com'

          - main: domain3.lol
            sans:
              - '*.domain3.lol'

          - main: domain4.co.uk
            sans:
              - '*.domain4.co.uk'
      middlewares:
        - securityHeaders@file

providers:
  providersThrottleDuration: 2s

  # File provider for connecting things that are outside of Docker / defining middleware
  file:
    filename: /etc/traefik/config.yml
    watch: true

  # Docker provider for connecting all apps that are inside the Docker network
  docker:
    watch: true
    network: proxy
    defaultRule: "Host(`{{ lower (trimPrefix `/` .ContainerName )}}.domain.xyz`)" # .ContainerName uses container name
    exposedByDefault: true

# Enable Traefik UI
api:
  dashboard: true
  insecure: true

# Log level INFO|DEBUG|ERROR
log:
  level: error

# Use Let's Encrypt to generate SSL certificates
certificatesResolvers:
  letsencrypt:
    acme:
      email: traefik@domain.xyz
      storage: /etc/traefik/acme.json
      dnsChallenge:
        provider: cloudflare
        # Used to make sure the dns challenge is propagated to the rights dns servers
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

With the example above, Traefik is set to automatically detect the name of the Docker container and use it as the subdomain. This is set as the container_name in the docker-compose.yml. Setting the subdomain explicitly is shown later in the container labels step.

Configuration file

Next, create a config.yml. The path to this file is set within traefik.yml. In this configuration file we need to define the routes and services that Traefik will control.

Some of the routes below are defined here because they are not Docker applications.

yaml
http:
  ## Manually proxy apps that are not on docker network
  routers:
     unraid: # UNRAID
       entryPoints:
         - https
       rule: 'Host(`unraid.domain.xyz`) || Host(`drogon.domain.xyz`)'
       service: unraid
       middlewares: # Enable authelia
         - "auth"

     router: # Router
       entryPoints:
         - https
       rule: 'Host(`router.domain.xyz`)'
       service: router
       middlewares:
         - "auth"

     homebridge: # homebridge
       entryPoints:
         - https
       rule: 'Host(`homebridge.domain.xyz`)'
       service: homebridge
       middlewares:
         - "auth"

  services:
    unraid:
      loadBalancer:
        servers:
          - url: http://192.168.0.10:2610

    router:
      loadBalancer:
        servers:
          - url: http://192.168.0.1

    rtsp-relay:
      loadBalancer:
        servers:
          - url: http://192.168.0.10:8700

    homebridge:
      loadBalancer:
        servers:
          - url: http://192.168.0.10:8581


  ## Middlewares ##

  middlewares:
    auth:
      forwardauth:
  address: http://auth:9091/api/verify?rd=https://auth.DOMAIN.COM/ # replace auth with your Authelia container name
        trustForwardHeader: true
        authResponseHeaders:
          - Remote-User
          - Remote-Groups
          - Remote-Name
          - Remote-Email

    # Authelia basic auth guard
    auth-basic:
      forwardauth:
  address: http://auth:9091/api/verify?auth=basic # replace auth with your Authelia container name
        trustForwardHeader: true
        authResponseHeaders:
          - Remote-User
          - Remote-Groups
          - Remote-Name
          - Remote-Email

    # Security headers
    securityHeaders:
      headers:
        customResponseHeaders:
          X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
          server: ""
          X-Forwarded-Proto: "https"
        sslProxyHeaders:
          X-Forwarded-Proto: https
        referrerPolicy: "strict-origin-when-cross-origin"
        hostsProxyHeaders:
          - "X-Forwarded-Host"
        customRequestHeaders:
          X-Forwarded-Proto: "https"
        contentTypeNosniff: true
        browserXssFilter: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsSeconds: 63072000
        stsPreload: true

# Only use secure ciphers - https://ssl-config.mozilla.org/#server=traefik&version=2.6.0&config=intermediate&guideline=5.6
tls:
  options:
    default:
      minVersion: VersionTLS12
      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

In this file we are mainly passing the middleware to force all traffic to Authelia before any further action is taken by Traefik, and defining TLS and other security headers that are relevant.

Container example

Below is a working example of Vaultwarden being protected by Authelia and routed through vault.domain.com.

yaml
version: "3"
services:

  vaultwarden:
    image: 'vaultwarden/server:latest'
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - /opt/appdata/vaultwarden/files:/data
    ports:
      - 8099:80
    networks:
      - proxy
    labels:
      traefik.enable: true
      traefik.http.routers.vaultwarden.entryPoints: https
      traefik.http.routers.vaultwarden.middlewares: auth@file
      traefik.http.routers.vaultwarden.rule: Host(`vault.DOMAIN.COM`)
      traefik.http.services.vaultwarden.loadbalancer.server.port: 80

networks:
  proxy:
    driver: bridge
    external: true

First, we need to ensure the network is set up correctly, specifying proxy and declaring this network at the bottom under networks. Once that's done we can move on to the labels.

Enable Traefik

This label simply enables Traefik to see this container and bring it into the load balancers and proxy.

yaml
traefik.enable: true

Force HTTPS

The following label ensures that all traffic is forwarded to https. If traffic is not secure, it will not touch it.

Probably not needed as the config forces everything from HTTP→ HTTPS.

yaml
traefik.http.routers.vaultwarden.entryPoints: https

Force middleware

This middleware label is required to ensure that all traffic to this container is checked with auth@file, where auth is defined as a middleware within config.yml. If you don't want Authelia to sit in front of your site, don't include this in the labels of your container.

yaml
traefik.http.routers.vaultwarden.middlewares: auth@file

Custom subdomain

If you don't wish Traefik to use the container_name as the subdomain, you can specify the domain in the format below. Ensure the subdomain exists on your DNS server. In this case I am using Cloudflare.

yaml
traefik.http.routers.vaultwarden.rule: Host(`vault.DOMAIN.COM`)

A nest of technical knowledge.