Traefik 2.2 + Docker: Global entrypoint configuration

Entrypoint defaults with Traefik 2.2
Header image

Image Source

Introduction

With Traefik 2.2 it is now easier then ever to globally configure your entrypoints.

We will show you how you can define a global redirect to https and how to set a default certResolver. So you don’t have to set the https redirect in each docker-compose file.

Prerequisites

In order to follow along, you’ll need to read the advanced Traefik guide and the wildcard guide first!

Update Traefik Configuration

Change the entrypoints in the basic Traefik configuration file (/opt/containers/traefik/data/traefik.yml) as follows:

entryPoints:
  http:
    address: :80
    http:
      redirections:
        entryPoint:
          to: https
  https:
    address: :443
    http:
      middlewares:
        - default-headers@file
      tls:
        certResolver: cloudflare
        domains:
          - main: example.com
            sans:
              - "*.example.com"

The file will then look like this:

api:
  dashboard: true
  debug: true

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
  https:
    address: ":443"
    http:
      middlewares:
        - default-headers@file
      tls:
        certResolver: cloudflare
        domains:
          - main: example.com
            sans:
              - "*.example.com"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml

certificatesResolvers:
  http:
    acme:
      email: email@email.com
      storage: acme.json
      httpChallenge:
        entryPoint: http

We added 2 things:

  1. Global middleware default-headers@file

    By default all containers will now have the defined headers from the /opt/containers/traefik/data/config.yml created in the advanced guide.

  2. Global certResolver cloudflare

    Since we’re using wildcard domains, you’ll need to setup dns challenge first! If you get an error like this:

    level=error msg=”middleware \”default-headers@file\” does not exist” routerName=traefik@docker entryPointName=https”
    

    Please make sure you have the middleware default-headers created in /opt/containers/traefik/data/config.yml. If not, either create it or remove the middleware from the traefik.yml.

Because we defined the https redirect and the certResolver here, you can remove some labels from all your docker-compose.

The Traefik docker-compose (/opt/containers/traefik/docker-compose.yml) now looks like this:

version: "3"

services:
  traefik:
    image: traefik:v2.2
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_API_EMAIL=your-cloudflare@email.com
      - CF_API_KEY=your-cloudflare-api-key
    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
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=https"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=USER:PASSWORD"
      - "traefik.http.routers.traefik.middlewares=traefik-auth"
      - "traefik.http.routers.traefik.service=api@internal"

networks:
  proxy:
    external: true

The Portainer docker-compose (/opt/containers/portainer/docker-compose.yml) now looks like this:

version: "3"

services:
  portainer:
    image: portainer/portainer:latest
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=https"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

As you can see, you only need 5 instead of 11 labels.

Additional Individual Middlewares

If you want to add more individual middlewares, you can still add them to your docker-compose. In this example we’ve added a redirect regex required for Nextcloud (line 4, 5, 6 and 7):

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.example.com`)"
  - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav"
  - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.replacement=https://$$1/remote.php/dav/"
  - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.permanent=true"
  - "traefik.http.routers.nextcloud.middlewares=nextcloud-redirectregex"
  - "traefik.http.routers.nextcloud.service=nextcloud"
  - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
  - "traefik.docker.network=proxy"

Traefik 2.0: Route external services through Traefik

Configure non-Docker backends in Traefik 2.0
Header image

Image Source

Introduction

In this tutorial we will show you how you can route non-Docker services through Traefik.

Let’s suppose you want to access your Pi-hole admin console (http://192.168.0.10:80/admin) by browsing to pihole.example.com.

Prerequisites

You have read our other articles:

and you use this Traefik configuration.

Make sure you configure in the providers section of your /opt/traefik/data/traefik.yml an external configuration file /config.yml.

providers:
  docker:
  endpoint: unix:///var/run/docker.sock
  exposedByDefault: false
  file:
    filename: /config.yml

Setup config.yml

Edit /opt/containers/traefik/data/config.yml and create a new router pihole:

http:
  routers:
    pihole:
      entryPoints:
        - https
      rule: Host(`pihole.example.com`)
      middlewares:
        - addprefix-pihole
      tls:
        certResolver: http
      service: pihole

Still in /opt/containers/traefik/data/config.yml create a service for the new router:

services:
  pihole:
    loadBalancer:
      servers:
        - url: http://192.168.0.10:80
      passHostHeader: true

Because the admin panel of Pi-hole is only reachable at the path /admin, you have to create an additional middleware (also in /opt/containers/traefik/data/config.yml):

middlewares:
  addprefix-pihole:
    addPrefix:
      prefix: /admin

If you have configured Traefik as we’ve described in the advanced tutorial, your config.yml should now look like this:

http:
  routers:
    pihole:
      entryPoints:
        - "https"
      rule: "Host(`pihole.example.com`)"
      middlewares:
        - default-headers
        - addprefix-pihole
      tls:
        certResolver: http
      service: pihole

  services:
    pihole:
      loadBalancer:
        servers:
          - url: "http://192.168.0.10:80"
        passHostHeader: true

  middlewares:
    addprefix-pihole:
      addPrefix:
        prefix: "/admin"

    https-redirect:
      redirectScheme:
        scheme: https

    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true

    default-whitelist:
      ipWhiteList:
        sourceRange:
          - "10.0.0.0/24"
          - "192.168.0.0/16"
          - "172.0.0.0/8"

    secured:
      chain:
        middlewares:
          - default-whitelist
          - default-headers

We also added the middleware default-headers to the new pihole router.

Don’t forget to restart Traefik docker restart traefik to reload the new config.yml!

Wildcard certificates

If you use a wildcard certificate as described in this article, you must leave the tls section empty {}:

http:
  routers:
    pihole:
      entryPoints:
        - https
      rule: Host(`pihole.example.com`)
      middlewares:
        - default-headers
        - addprefix-pihole
      tls: {}
      service: pihole

Bonus example

Here you can find a complete config.yml to route a Synology Diskstation and Pi-hole through Traefik.

http:
  routers:
    pihole:
      entryPoints:
        - "https"
      rule: "Host(`pihole.example.com`)"
      middlewares:
        - default-headers
        - addprefix-pihole
      tls:
        certResolver: http
      service: pihole

    synology:
      entryPoints:
        - "https"
      rule: "Host(`synology.example.com`)"
      middlewares:
        - default-headers
      tls:
        certResolver: http
      service: synology

  services:
    pihole:
      loadBalancer:
        servers:
          - url: "http://192.168.0.10:80"
        passHostHeader: true

    synology:
      loadBalancer:
        servers:
          - url: "http://192.168.0.11:5000"
        passHostHeader: true

  middlewares:
    addprefix-pihole:
      addPrefix:
        prefix: "/admin"

    https-redirect:
      redirectScheme:
        scheme: https

    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true

    default-whitelist:
      ipWhiteList:
        sourceRange:
          - "10.0.0.0/24"
          - "192.168.0.0/16"
          - "172.0.0.0/8"

    secured:
      chain:
        middlewares:
          - default-whitelist
          - default-headers

As you can see, the Synology router has no extra middleware, because a Synology Disksation is accessible without any additional path.

Traefik 2.0: Paranoid about mounting /var/run/docker.sock?

The Problem with mounting docker.sock
Header image

Image Source

The Problem

If you have followed our previous guides, you mount the Docker Socket ( /var/run/docker.sock) into the Traefik container. If someone gets access into the Traefik container, they can gain full access to your host machine. This makes our paranoia level increase slightly…

The Solution

We found a nice little container (Socket-Proxy) which “filters” all requests to the Docker API. We can allow only get requests to the Docker API and restrict it to /containers/*.

The Socket Proxy uses the official Alpine-based HAProxy image. It blocks access to the Docker socket API according to the environment variables you set. It returns a HTTP 403 Forbidden status for those dangerous requests that should never happen.

Let’s create the socket-proxy container (/opt/containers/docker-socket/docker-compose.yml):

version: "3.6"

services:
  socket-proxy:
    image: tecnativa/docker-socket-proxy
    container_name: socket-proxy
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      CONTAINERS: 1
    networks:
      - proxy

networks:
  proxy:
    external: true

The environment variable CONTAINERS: 1 tells the proxy to grant get requests to /containers/* from the Docker API. Post requests are disabled by default.

All possible settings are described here.

Now we have to change the endpoint in the providers section of the traefik.yml file (/opt/containers/traefik/data/traefik.yml):

api:
  dashboard: true
  debug: false

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    endpoint: "tcp://socket-proxy:2375"
    watch: true
    exposedbydefault: false

Restart the Traefik container and feel a little bit more safe!

Traefik 2.0: Wildcard Let's Encrypt Certificates

How to use wildcard certificates with Traefik 2.0
Header image

Image Source

Introduction

In this tutorial we will setup Traefik to obtain wildcard certificates from Let’s Encrypt. This requires DNS challenge to be setup. Usually Traefik obtains a certificate for every subdomain. We can simplify this process by telling Traefik to use a wildcard (*.example.com) certificate instead.

Prerequisites

  • Registered Domain
  • Authoritative DNS Servers from one of these providers (you may need to change your DNS servers of your domain to one of the provider in the list)

In this tutorial we will use Cloudflare as our DNS servers for our domain.

Setup DNS challenge

If you have followed our other guides, chances are you currently use HTTP challenge. These types of challenges define how Let’s Encrypt assures that you are the owner of the domain you want to obtain a certificate for.

In order to get a wildcard certificate, you have to use DNS challenge.

First of all make sure you connect your domain with one of the supported DNS providers. We are using Cloudflare. This depends on where you bought your domain, so we can’t show you exactly how to do it.

In the Traefik Docker compose file we add the following lines:

environment:
  - CF_API_EMAIL=your-cloudflare@email.com
  - CF_API_KEY=your-cloudflare-api-key

Here is the full Traefik Docker compose

Next, we tell Traefik to use DNS challenge (edit the file traefik.yml):

certificatesResolvers:
  cloudflare:
    acme:
      email: your@email.com
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

Here is the full Traefik configuration file

Create a backup of your existing acme.json and clear the current file:

cp -p acme.json acme.json.bak && > acme.json

Setup the wildcard certificate

Change the Traefik Docker compose labels (make sure to change your domain accordingly):

- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik.tls.domains[0].main=example.com"
- "traefik.http.routers.traefik.tls.domains[0].sans=*.example.com"
- "traefik.http.routers.traefik.service=api@internal"

Here is the full Traefik Docker compose

Tell Traefik to use the wildcard certificate for each service

Now we have to remove one label from every service:

- traefik.http.routers.service.tls.certresolver=cloudflare

Here is an example compose file

Once you have removed the line above from all your services, Traefik should always use the wildcard certificate.

Using Pi-hole to route your services internally

Connecting to your local server without looping trough the internet
Header image

Image Source

The Problem

If you have followed our previous guides, chances are that you have a domain, some DNS records pointing to your public IP, port forwarding enabled and a Docker server running some services.

Most likely your domain resolves to your public IP from you internal network as well. This causes a problem: All the traffic between your devices (e.g. your phone) to your server (physically in the same location) gets routed trough the internet, which means you have to utilize your upload and download bandwidth at the same time (e.g. while streaming from Plex), which not only causes a slower connection but also adds an unnecessary high latency.

The Solution

If you have a Pi-hole running at home (which you should) you can configure it to resolve your domain (*.example.com and example.com) to your servers local IP instead of your public IP. This means all your devices will directly connect to your server without looping through the internet, making everything faster. Yay!

Since Pi-hole is nothing else but a DNS server with some special software, we can easily configure the underlying dnsmasq service.

Here’s how we can achieve that:

  1. Connect to your Raspberry Pi (or wherever Pi-hole is running) via SSH

  2. Open the file /etc/dnsmasq.d/05-custom.conf

    sudo nano /etc/dnsmasq.d/05-custom.conf
    
  3. Add the following line (change example.com to your domain and 192.168.1.10 to your servers local IP)

    address=/example.com/192.168.1.10
    
  4. Restart the DNS service

    sudo pihole restartdns
    

You can verify the changes by looking up your domain:

Before

[user@server ~]$ dig +short example.com
216.91.241.176

After:

[user@server ~]$ dig +short example.com
192.168.1.10

If you don’t have dig installed, you can use the following command to install it on Ubuntu:

sudo apt install dnsutils

That’s it!

Traefik 2.0 + Docker: A Simple Step by Step Guide

A simple guide on how to setup Traefik 2.0
Header image

Image Source

Introduction

In this tutorial we will go trough the following things:

  1. Setup and configure Traefik in a Docker container
  2. Let’s Encrypt setup for automatic HTTPS certificates
  3. Deploy a simple service (Portainer) and expose it to the internet

You will find all the required configuration files in our Git repository.

Prerequisites

In order to follow along, you need these things:

  • Docker (obviously)
  • Docker Compose
  • A domain
  • Ports 80 and 443 forwarded to your Docker host

Setup and configure Traefik with Let’s Encrypt

Let’s get started by setting up Traefik.

First, create a directory for our containers:

mkdir -p /opt/containers/{traefik,portainer}

Create the data folder and config files for Traefik:

mkdir -p /opt/containers/traefik/data
touch /opt/containers/traefik/data/acme.json
chmod 600 /opt/containers/traefik/data/acme.json
touch /opt/containers/traefik/data/traefik.yml

The acme.json file is the storage file for the HTTPS certificates.

Now we create the basic Traefik configuration file (/opt/containers/traefik/data/traefik.yml):

api:
  dashboard: true

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  http:
    acme:
      email: email@example.com
      storage: acme.json
      httpChallenge:
        entryPoint: http

Please change the email address for the certificatesresolvers at line 18.

Here is the Docker Compose file for Traefik (/opt/containers/traefik/docker-compose.yml):

version: "3"

services:
  traefik:
    image: traefik:v2.0
    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
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "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.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=http"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true

Using this compose file, Traefik will also expose a dashboard (line 32). Please change the host rule at line 23 and 28 to your subdomain.

In addition, change the credentials at line 24. Those credentials must be in htpasswd format.

To generate htpasswd credentials, you can use the following command (change <USER>and <PASSWORD>):

echo $(htpasswd -nb <USER> <PASSWORD>) | sed -e s/\\$/\\$\\$/g

Once that’s done we can create the proxy network an fire up Traefik:

docker network create proxy
cd /opt/containers/traefik
docker-compose up -d

Visit traefik.example.com and enjoy the new dashboard.

Deploy Portainer

Here is the Docker Compose file for Portainer (/opt/containers/portainer/docker-compose.yml):

version: "3"

services:
  portainer:
    image: portainer/portainer:latest
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.portainer.middlewares=portainer-https-redirect"
      - "traefik.http.routers.portainer-secure.entrypoints=https"
      - "traefik.http.routers.portainer-secure.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer-secure.tls=true"
      - "traefik.http.routers.portainer-secure.tls.certresolver=http"
      - "traefik.http.routers.portainer-secure.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

Again, change the subdomain portainer.example.com at line 18 and 22.

Fire up Portainer:

cd /opt/containers/portainer
docker-compose up -d

You can now visit Portainer by browsing to portainer.example.com.

Traefik 2.0 + Docker: An Advanced Guide

An advanced guide on how to setup and use Traefik 2.0
Header image

Image Source

Introduction

This tutorial is the second part of this article. We will go trough the following configurations:

  1. Add a file provider to traefik.yml
  2. Create a config file for a central configuration for storing middlewares config.yml.
  3. Configure a middleware chain

You will find all the required configuration files in our Git repository.

Prerequisites

In order to follow along, you’ll need to read this post!

Update Traefik configuration

To setup a reusable middleware add an additional provider in the Traefik configuration file traefik.yml (/opt/containers/traefik/traefik.yml) (lines 15 and 16).

api:
  dashboard: true
  debug: true

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml

certificatesResolvers:
  http:
    acme:
      email: email@example.com
      storage: acme.json
      httpChallenge:
        entryPoint: http

Create a file for the central configuration:

touch /opt/containers/traefik/data/config.yml

Add a middleware to redirect http to https (/opt/containers/traefik/data/config.yml):

http:
  middlewares:
    https-redirect:
      redirectScheme:
        scheme: https

Mount the new config.yml file in the docker-compose file for Traefik (/opt/containers/traefik/docker-compose.yml) (line 20):

version: "3"

services:
  traefik:
    image: traefik:v2.0
    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/config.yml:/config.yml:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "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.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=http"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true

Recreate Traefik container:

docker-compose up -d

Attention, Attention:

The redirection in the file provider does not work in the docker-compose for Traefik!

Use the new Middleware

As a template we use the docker-compose of Portainer from the previous article. Replace the lines 19 and 20 with following line:

- "traefik.http.routers.traefik.middlewares=https-redirect@file"

The Portainer docker-compose (/opt/containers/portainer/docker-compose.yml) now looks like this:

version: "3"

services:
  portainer:
    image: portainer/portainer:latest
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer.middlewares=https-redirect@file"
      - "traefik.http.routers.portainer-secure.entrypoints=https"
      - "traefik.http.routers.portainer-secure.rule=Host(`portainer.example.com`)"
      - "traefik.http.routers.portainer-secure.tls=true"
      - "traefik.http.routers.portainer-secure.tls.certresolver=http"
      - "traefik.http.routers.portainer-secure.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

The @file instructs Traefik to look inside config.yml for the corresponding middleware.

So every time you want to redirect http to https, you can add the middleware https-redirect. You can add multiple middlewares separated with a comma.

Middleware-Chain

The chain middleware enables you to define reusable combinations of other pieces of middleware. It makes reusing the same groups easier.

The description above was stolen from here.

So let’s do this! Add some middlewares in the /opt/containers/traefik/data/config.yml:

http:
  middlewares:
    https-redirect:
      redirectScheme:
        scheme: https

    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true

    default-whitelist:
      ipWhiteList:
        sourceRange:
          - "10.0.0.0/24"
          - "192.168.0.0/16"
          - "172.0.0.0/8"
  • The default-header middleware sets some basic security headers.
  • The default-whitelistmiddleware allows only internal IP addresses.

Then we add a middleware chain with the previously created middlewares:

secured:
  chain:
    middlewares:
      - default-whitelist
      - default-headers

The complete /opt/containers/traefik/data/config.yml now looks like this:

http:
  middlewares:
    https-redirect:
      redirectScheme:
        scheme: https

    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true

    default-whitelist:
      ipWhiteList:
        sourceRange:
          - "10.0.0.0/24"
          - "192.168.0.0/16"
          - "172.0.0.0/8"

    secured:
      chain:
        middlewares:
          - default-whitelist
          - default-headers

To use the chain we can add it as any other middleware:

- "traefik.http.routers.portainer-secure.middlewares=secured@file"

With the central middlewares and the middleware chain it’s easy to setup multiple containers with the same configuration.

You can also add additional labels for the same settings. Here an example for Nextcloud:

- "traefik.http.middlewares.nc-header.headers.customFrameOptionsValue=SAMEORIGIN"
- "traefik.http.routers.nextcloud-secure.middlewares=secured@file,nc-header"