Traefik Reverse Proxy for Docker & Swarm

Setting Up a Reverse Proxy for Homelab-Enviroments.

Getting Started


Getting Started

Overview of Traefik Reverse Proxy 3.0 & Key Concepts

logo-traefik-proxy-logo.pngIntroduction

Traefik is an open-source Application Proxy that simplifies the process of exposing and managing services in your infrastructure. It acts as the gateway to your platform, receiving incoming requests and securely routing them to the appropriate services. Traefik is highly flexible and supports dynamic service discovery, automatic routing, and can handle complex routing configurations without requiring manual intervention.

Traefik is based on key concepts like EntryPoints, Routers, Middlewares, and Services, which work together to manage traffic and make your infrastructure more efficient and easier to scale.

traefik-architecture.png


Key Concepts in Traefik


traefik-edge-router.png

Traefik as an Edge Router


As an Edge Router, Traefik manages all incoming requests, applying routing logic to determine which service should handle a given request. It can route traffic based on a variety of criteria, such as URL paths, hostnames, headers, and more. This makes Traefik highly effective as the entry point to your infrastructure.


Automatic Service Discovery

One of the standout features of Traefik is its ability to perform automatic service discovery. Traditional reverse proxies require you to maintain a configuration file that lists all possible routes and services. With Traefik, this process is fully automated. Traefik continuously scans your infrastructure for new or updated services, automatically configuring itself in real time without any need for manual updates.

When a service is deployed, Traefik detects it immediately and updates its routing rules. If a service is removed, Traefik dynamically removes the associated route, ensuring that your routing configuration is always accurate and up to date.

traefik-concepts-2.png

 


 

Decentralized Configuration

With Traefik, configuration is decentralized, meaning services themselves provide the necessary information for routing. This eliminates the need to manually update and synchronize configuration files across multiple nodes or platforms. Traefik ensures that routing rules reflect the current state of your infrastructure at all times.


 

Traefik in Multi-Platform Environments

Traefik supports seamless integration with a variety of container orchestration platforms and cloud services, such as:

It can handle multiple backends simultaneously, allowing you to manage modern microservices alongside legacy applications running on bare metal.

 


 

Conclusion

Traefik Reverse Proxy 3.0 provides a robust and flexible solution for handling routing, load balancing, and service discovery across modern and legacy infrastructure. Whether you're managing containerized microservices, cloud-based services, or traditional applications, Traefik makes routing and service discovery a seamless experience.

Getting Started

Beginner-Guide: Traefik & Docker Swarm

logo-traefik-proxy-logo.pngdocker.png

How Traefik Works with Docker Swarm

Traefik integrates tightly with Docker Swarm, using the Docker API to automatically discover services. In Swarm Mode, Traefik watches for service-level labels rather than container-level labels (which are used in standalone Docker mode). This allows Traefik to dynamically adapt as services are created, updated, or removed.

Benefits of Using Traefik with Docker Swarm:


Example: Deploying Traefik with Docker Swarm

Let’s walk through an example where we deploy Traefik as a reverse proxy in a Docker Swarm environment. We’ll expose a simple web service and configure routing with labels.

1. Setting Up Traefik in Docker Swarm

First, we need to deploy Traefik as a service in the Docker Swarm cluster. Traefik requires access to the Docker socket to monitor the containers and services. Here's how to deploy Traefik with Docker Swarm using Docker Compose:

version: '3.7'
services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.insecure=true"  # Exposes Traefik's dashboard
      - "--providers.docker=true"  # Enables Docker as the provider
      - "--entrypoints.web.address=:80"  # Defines an HTTP EntryPoint on port 80
    ports:
      - "80:80"       # Expose Traefik's HTTP EntryPoint
      - "8080:8080"   # Expose the Traefik Dashboard
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"  # Access Docker API
    deploy:
      placement:
        constraints:
          - node.role == manager  # Only run on Swarm manager nodes

Explanation:


2. Deploying a Service with Routing Labels

Next, let’s deploy a simple web service, such as Nginx, and attach routing labels so that Traefik can automatically route traffic to it.

version: '3.7'
services:
  nginx:
    image: nginx
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.nginx.rule=Host(`nginx.local`)"
        - "traefik.http.services.nginx.loadbalancer.server.port=80"

Explanation:

Now, you can deploy this configuration in your Swarm cluster with:
docker stack deploy -c docker-compose.yml my-stack
Or you can run the Stack in Portainer :)


Understanding Key Configuration Elements

Port Detection in Docker Swarm

Traefik does not automatically detect ports in Docker Swarm mode. You must explicitly set the port label (traefik.http.services.<service_name>.loadbalancer.server.port) to tell Traefik which port to use for the service. This ensures that Traefik can properly route requests to the service.

Host Networking with Traefik

If you are exposing containers configured with host networking, Traefik resolves the host IP based on the following priorities:

  1. host.docker.internal
  2. host.containers.internal
  3. If both fail, it falls back to 127.0.0.1.

IPv4 and IPv6

By default, Traefik prioritizes the IPv4 address of a container, even in an IPv6-enabled Docker stack. If you want Traefik to use the IPv6 address, make sure your Docker configuration supports IPv6 routing.


Scheduling Traefik on Swarm Nodes

In Docker Swarm mode, only manager nodes can access the Docker Swarm API, which Traefik needs to dynamically discover services. Therefore, you must schedule Traefik on manager nodes. Here’s how to do it:

Example for Docker Compose:

services:
  traefik:
    image: traefik:v3.0
    deploy:
      placement:
        constraints:
          - "node.role == manager"


Docker API Access and Security Considerations

Since Traefik requires access to the Docker API via the docker.sock socket, this raises potential security risks. Anyone with access to Traefik can also gain access to the Docker API and, by extension, the underlying host. To mitigate this risk:

Here’s an example of a secure Docker API configuration with TLS:

providers:
  swarm:
    tls:
      cert: "/path/to/cert.crt"
      key: "/path/to/key.key"
      ca: "/path/to/ca.crt"

This configuration ensures that the Docker API connection is secured using TLS.


Conclusion

Traefik’s integration with Docker Swarm provides a powerful, dynamic solution for managing services at scale. By using labels on services, Traefik can automatically discover, configure, and route traffic without the need for manual intervention. It’s particularly useful for dynamic environments where services are frequently added or removed, as Traefik handles these changes in real time.

This beginner-friendly overview of Traefik with Docker Swarm should give you a solid foundation for deploying and routing your services dynamically. As you become more familiar, you can explore advanced configurations such as load balancing strategies, security features, and using external providers like Kubernetes.

Getting Started

Beginner-Guide: Traefik & Docker Standalone Engine

logo-traefik-proxy-logo.pngdocker.png

Step 1: Install Docker

Before setting up Traefik, make sure Docker is installed on your system. You can follow My Dockerengine Guide for instructions on installing Docker Engine.

Step 2: Setting Up Traefik

Create a docker-compose.yml file to define the Traefik service and its basic configuration.
Example docker-compose.yml:

version: "3.7"

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - "--api.insecure=true"  # Enable Traefik dashboard (insecure mode, disable in production)
      - "--providers.docker=true"  # Enable Docker as a provider
      - "--entrypoints.web.address=:80"  # Define HTTP EntryPoint
      - "--entrypoints.websecure.address=:443"  # Define HTTPS EntryPoint
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"  # Enable Let's Encrypt TLS challenge
      - "--certificatesresolvers.myresolver.acme.email=your-email@example.com"  # Email for Let's Encrypt
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"  # Storage for certificates
    ports:
      - "80:80"       # Expose Traefik on port 80 (HTTP)
      - "443:443"     # Expose Traefik on port 443 (HTTPS)
      - "8080:8080"   # Traefik Dashboard
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"  # Allow Traefik to access Docker API
      - "./letsencrypt:/letsencrypt"  # Volume to store Let's Encrypt certificates
    networks:
      - traefik-net

networks:
  traefik-net:
    driver: bridge

Explanation:

Step 3: Run Traefik

To start Traefik, run the following command in the directory containing the docker-compose.yml file:

docker-compose up -d

This command will start Traefik in detached mode. You can check if Traefik is running by visiting http://localhost:8080. You should see the Traefik dashboard.

Step 4: Exposing a Service via Traefik

Now that Traefik is up and running, let’s deploy a simple service, such as an Nginx container, and configure it to route traffic through Traefik.

Create a new docker-compose.yml for the Nginx service:

version: "3.7"

services:
  nginx:
    image: nginx
    container_name: nginx
    labels:
      - "traefik.enable=true"  # Enable Traefik routing for this container
      - "traefik.http.routers.nginx.rule=Host(`nginx.local`)"  # Route traffic based on hostname
      - "traefik.http.services.nginx.loadbalancer.server.port=80"  # Nginx runs on port 80
    networks:
      - traefik-net

networks:
  traefik-net:
    external: true

Explanation:

Run the following command to deploy the Nginx service:

docker-compose up -d

At this point, Traefik should automatically detect the Nginx service and route traffic based on the hostname nginx.local. To test this setup locally, you can add the following line to your /etc/hosts file:

127.0.0.1 nginx.local

Now, visiting http://nginx.local should display the Nginx default welcome page.

Step 5: Routing Configuration with Labels

In Traefik, labels define how traffic is routed to services. These labels are attached to the Docker containers and can configure anything from simple routing rules to advanced load balancing configurations.

Here are some useful labels you can apply to your containers:

Port Detection

By default, Traefik automatically detects which port to use based on the ports exposed by the Docker container:

If Traefik cannot determine the correct port, you can manually define the port using the label:

labels:
  - "traefik.http.services.my-service.loadbalancer.server.port=8080"

Security Considerations

When running Traefik with Docker, there are a few important security considerations:

  1. Docker API Access: Traefik requires access to the Docker socket (/var/run/docker.sock) to monitor container events and retrieve routing configuration. This can expose your Docker environment to potential security risks. Ensure only trusted services have access to the Docker API.

  2. TLS/SSL: Enable SSL certificates for your services by configuring Let’s Encrypt or using your own certificate. Traefik’s ACME integration with Let’s Encrypt allows for automatic certificate management.

  3. Secure the Dashboard: By default, the Traefik dashboard is exposed on port 8080 in insecure mode. In production environments, disable the insecure API or secure the dashboard with authentication.


Conclusion

Traefik makes it incredibly easy to manage traffic and load balancing for your Docker containers. With its dynamic service discovery, routing rules based on labels, and automatic SSL management, Traefik can simplify your Docker environment and reduce the complexity of traditional reverse proxy setups.

By following this guide, you should have a basic understanding of how to set up Traefik with Docker, configure routing with labels, and expose services dynamically. As you gain more experience, you can explore advanced features such as middlewares, sticky sessions, and custom SSL configurations.

Traefik is a powerful tool for anyone looking to manage traffic in a Docker environment, whether you're running a few containers or managing a large-scale microservices architecture.

Configuration

Configuration

Configuration Introduction

static-dynamic-configuration.png

logo-traefik-proxy-logo.png

Configuration in Traefik can refer to two different things:

Elements in the static configuration set up connections to providers and define the entrypoints Traefik will listen to (these elements don't change often).

The dynamic configuration contains everything that defines how the requests are handled by your system. This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.

Incompatible Configuration
Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you are running v2, please ensure you are using a v2 configuration. Old configurations fro Traefik v2.x are NOT compatible.


The Static Configuration

There are three different, mutually exclusive (i.e. you can use only one at the same time), ways to define static configuration options in Traefik:

  1. In a configuration file
  2. In the command-line arguments
  3. As environment variables

These ways are evaluated in the order listed above.

If no value was provided for a given option, a default value applies. Moreover, if an option has sub-options, and any of these sub-options is not specified, a default value will apply as well.

For example, the --providers.docker option is enough by itself to enable the docker provider, even though sub-options like --providers.docker.endpoint exist. Once positioned, this option sets (and resets) all the default values of the sub-options of --providers.docker.

Static files can be Configured in Format of TOML or YAML Format
See More about configuring the Static Config in this Wiki Post: Static Configuration File

See More about configuring the Static Config in this Wiki Post: Static Configuration File


The Dynamic Configuration

Traefik gets its dynamic configuration from providers: whether an orchestrator, a service registry, or a plain old configuration file.

Since this configuration is specific to your infrastructure choices, we invite you to refer to the dedicated section of this documentation.

Configuring Your Routers, Middlewares etc can be done in multiple ways. Either you can add Traefik Labels directly into your Application Docker Compose files Like this Format (- 'traefik.http.routers.bookstack.entrypoints=websecure') But they also can also be configured in Dynamic files. It's a Choice of what you prefer.
See More about configuring the Dynamic Config in this Wiki Post: Dynamic Configuration Files

Dynamic files can be Configured in Format of TOML or YAML Format
See More about configuring the Dynamic Config in this Wiki Post: Dynamic Configuration Files

HTTPS Certificates also belong to the dynamic configuration.
You can add / update / remove them without restarting your Traefik instance like mentioned in the beginning of this Post.


Configuration

Static Configuration File

logo-traefik-proxy-logo.png

There are three different, mutually exclusive (i.e., you can use only one at the same time), ways to define static configuration options in Traefik:

These ways are evaluated in the order listed above. If no value is provided for a given option, a default value applies. Moreover, if an option has sub-options and any of these sub-options are not specified, a default value will apply as well.

Static files can be Configured in Format of TOML or YAML Format.
I Prefer the YAML Format after working with TOML for 6 months because YAML is more intuitive for beginners.

How Traefik Loads the Static Configuration File

At startup, Traefik searches for static configuration in a file named traefik.yml (or traefik.yaml or traefik.toml) in:

Applying This Knowledge to Your Traefik Setup

Traefik will look for files named traefik.yml, traefik.yaml, or traefik.toml at the startup of the container. You need to mount the static configuration file into your Traefik container. Below is basic information on how to apply it in Docker Compose. For more details, refer to this post: Bind Mounts.

I just call my static configuration file on my Linux host "static.yaml" so it is clear what is meant.

Examples of How to Apply

volumes:
  # Example 1
  - '/path/to/your/static.yml:/traefik.yml:ro'
  # Example 2
  - '/path/to/your/static.yaml:/traefik.yaml:ro'
  # Example 3
  - '/path/to/your/static.toml:/traefik.toml:ro'

Minimum Required Information Recommended in Your Static.yaml Example:

# Configuration for Traefik v3.3 by aeoneros

global:
  checkNewVersion: true
  sendAnonymousUsage: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true

  websecure:
    address: ":443"
    http:
      tls:
        certResolver: "leresolver"
        domains:
          - main: 'yourdomain.com'
            sans:
              - '*.yourdomain.com'

tls:
  certificates:
    - stores: ["default"]
  stores:
    default:
      defaultCertificate: {}

log:
  filePath: "/traefik.log"
  level: "DEBUG"

accessLog:
  filePath: "/access.log"
  addInternals: true
  format: "json"
  bufferingSize: 200
  fields:
    defaultMode: "keep"
    headers:
      defaultMode: "keep"
      names:
        X-Forwarded-For: "keep"

api:
  dashboard: false
  insecure: false

providers:
  docker:
    exposedByDefault: false
    network: "your_traefik_network"
  swarm:
    network: "your_traefik_network"
  file:
    watch: true
    directory: "/dynamic/"

certificatesResolvers:
  leresolver:
    acme:
      email: 'your-email@domain.com'
      storage: '/acme.json'
      caServer: 'https://acme-v02.api.letsencrypt.org/directory'
      dnsChallenge:
        provider: 'cloudflare'
        delayBeforeCheck: '0'
        resolvers:
          - '1.1.1.1:53'
          - '1.0.0.1:53'
          - '8.8.8.8:53'

For more about dynamic configuration, see: Dynamic Configuration Files.

Configuration

Dynamic Configuration File/s

logo-traefik-proxy-logo.pngThe dynamic configuration contains everything that defines how the requests are handled by your system. This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss.

How Traefik Loads the Dynamic Config File/s

Refer to the Static Configuration Post for context. Traefik loads the static.yaml, and within that file, the dynamic file(s) are referenced for loading.

To load your dynamic configurations, you can set them up in two ways. Either write all your dynamic content into a single file or split it into multiple files for better organization.

Example: Loading Configuration in One File

Needs to be set up in static.yaml. The /dynamic.yaml is the path inside the container and must be mounted using Docker Compose:

volumes:
  # Dynamic Configuration File
  - '/path/on/your/linuxhost/dynamic:/dynamic.yaml'

Example static.yaml:

providers:
  docker:
    exposedByDefault: false
    network: "management_net"
  swarm:
    network: "management_net"
  file:
    watch: true
    file: "/dynamic.yaml"

Example: Loading Multiple Configuration Files

This setup loads every file in the specified directory with the YAML format. The /dynamic/ path is the path inside the container and must be mounted using Docker Compose:

volumes:
  # Dynamic Configuration Folder
  - '/path/on/your/linuxhost/dynamic:/dynamic/'

Example static.yaml:

providers:
  docker:
    exposedByDefault: false
    network: "management_net"
  swarm:
    network: "management_net"
  file:
    watch: true
    directory: "/dynamic/"

Splitting Dynamic Files

Create multiple paths in your Traefik data folder. Assuming your base Traefik data folder is /mnt/glustermount/data/traefik_data, you can structure it like this:

mkdir -p /mnt/glustermount/data/traefik_data/dynamic
touch /mnt/glustermount/data/traefik_data/dynamic/http.middlewares.yaml
touch /mnt/glustermount/data/traefik_data/dynamic/http.routers.yaml
touch /mnt/glustermount/data/traefik_data/dynamic/http.services.yaml
touch /mnt/glustermount/data/traefik_data/dynamic/tls.options.yaml

Then you can write configurations into these files. Below are examples for each:

Example: http.middlewares.yaml

http:
  middlewares:
    my-secure-headers:
      headers:
        sslRedirect: true
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true

Example: http.routers.yaml

http:
  routers:
    my-router:
      rule: "Host(`example.com`)"
      entryPoints:
        - websecure
      service: my-service
      tls: {}

Example: http.services.yaml

http:
  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://192.168.1.10:8080"

Example: tls.options.yaml

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Providers


Providers

Overview Providers

logo-traefik-proxy-logo.pngConfiguration discovery in Traefik is achieved through Providers.

The providers are infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores. The idea is that Traefik queries the provider APIs in order to find relevant information about routing, and when Traefik detects a change, it dynamically updates the routes.

providers.png

Find out More about Providers here.

Supported Providers

Below is the list of the currently supported providers in Traefik.

Provider Type Configuration Type Provider Name
Docker Orchestrator Label docker
Kubernetes IngressRoute Orchestrator Custom Resource kubernetescrd
Kubernetes Ingress Orchestrator Ingress kubernetes
Kubernetes Gateway API Orchestrator Gateway API Resource kubernetesgateway
Consul Catalog Orchestrator Label consulcatalog
Nomad Orchestrator Label nomad
ECS Orchestrator Label ecs
File Manual YAML/TOML format file
Consul KV KV consul
Etcd KV KV etcd
ZooKeeper KV KV zookeeper
Redis KV KV redis
HTTP Manual JSON format http


 

HTTPS & TLS

HTTPS & TLS

Overview HTTPS & TLS

logo-traefik-proxy-logo.png

Traefik supports HTTPS & TLS, which concerns roughly two parts of the configuration:

For Automated Certification Check this post:
https://wiki.aeoneros.com/books/traefik-reverse-proxy-for-docker-swarm/page/lets-encrypt

Configuring HTTPS in Routers

When a router needs to handle HTTPS traffic, it should include a tls field in its definition. For detailed instructions, refer to the TLS section of the routers documentation.

Managing TLS Connections

To configure the TLS connection itself, you need to:

Example: Configuring HTTPS in a Router

http:
  routers:
    secure-router:
      rule: "Host(`example.com`)"
      entryPoints:
        - websecure
      service: my-service
      tls:
        certResolver: "myresolver"

Example: Defining Certificates in Dynamic Configuration

tls:
  certificates:
    - certFile: "/path/to/cert.crt"
      keyFile: "/path/to/cert.key"

Example: Using Let’s Encrypt with ACME

certificatesResolvers:
  myresolver:
    acme:
      email: "your-email@domain.com"
      storage: "/acme.json"
      httpChallenge:
        entryPoint: "web"

TLS Options Example

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

For a deeper dive into certificate management, TLS options, and other HTTPS configurations, see the official Traefik documentation.

HTTPS & TLS

How SSL Certificates Work: A Breakdown

Cloudflare_Logo.svg.png


What is SSL?

SSL stands for Secure Sockets Layer, a protocol for encrypting, securing, and authenticating communications on the Internet. Although SSL has been replaced by TLS (Transport Layer Security), the term "SSL" is still widely used to describe this technology.

Primary Use Cases

How does SSL/TLS work?

SSL/TLS operates based on several key principles:

The TLS Handshake

The TLS handshake is the process by which two parties establish a secure connection. This involves:

Symmetric Encryption

After the handshake, both parties use the same session key for encryption. These keys are temporary and unique to each session, ensuring high levels of security.

Authenticating the Origin Server

TLS communications include a digital signature (MAC) that authenticates the server and prevents data alteration during transmission.

What is an SSL Certificate?

An SSL certificate is a data file installed on a website's server. It contains:

SSL certificates are essential for enabling encrypted communications using TLS.

Self-Signed Certificates

Website owners can create self-signed certificates, but these are not as trusted as certificates issued by a certificate authority (CA).

Obtaining an SSL Certificate

SSL certificates are issued by certificate authorities (CAs) after verifying the website owner’s identity. The CA maintains a copy of the certificates they issue.

Free SSL Certificates

Many CAs charge for SSL certificates, but some, like Cloudflare, offer them for free to encourage secure Internet practices.

HTTP vs. HTTPS

HTTPS is HTTP with SSL/TLS encryption. A website using HTTPS:

Modern browsers mark HTTP websites as "not secure," making HTTPS essential for trust and security.

For further details on SSL/TLS, visit the official Traefik documentation.

HTTPS & TLS

TLS

logo-traefik-proxy-logo.png

Automated Certification via Let’s Encrypt

For automated TLS certificate management, Traefik integrates with Let’s Encrypt. See detailed instructions in this Let’s Encrypt guide.

 

User-Defined Certificates

To add or remove TLS certificates dynamically, define them in the tls.certificates section of the dynamic configuration:

File (YAML)

# Dynamic configuration
tls:
  certificates:
    - certFile: /path/to/domain.cert
      keyFile: /path/to/domain.key
    - certFile: /path/to/other-domain.cert
      keyFile: /path/to/other-domain.key

File (TOML)

Note: In Kubernetes, certificates must be provided as secrets instead of using the file provider.

Certificates Stores

In Traefik, certificates are grouped in certificate stores:

File (YAML)

# Dynamic configuration
tls:
  stores:
    default: {}

By default, all certificates are stored in the default store. Any additional store definitions are ignored.

File (YAML): Specifying Certificate Stores

# Dynamic configuration
tls:
  certificates:
    - certFile: /path/to/domain.cert
      keyFile: /path/to/domain.key
      stores:
        - default
    - certFile: /path/to/other-domain.cert
      keyFile: /path/to/other-domain.key

Default Certificate

Traefik can use a default certificate for connections without SNI or matching domains. Define the default certificate in a TLS store:

File (YAML)

# Dynamic configuration
tls:
  stores:
    default:
      defaultCertificate:
        certFile: /path/to/cert.crt
        keyFile: /path/to/cert.key

ACME Default Certificate: Traefik can also generate a default certificate using an ACME provider:

File (YAML)

# Dynamic configuration
tls:
  stores:
    default:
      defaultGeneratedCert:
        resolver: myresolver
        domain:
          main: example.org
          sans:
            - foo.example.org
            - bar.example.org

TLS Options

The TLS options allow you to configure parameters of the TLS connection:

Default TLS Option

# Dynamic configuration
tls:
  options:
    default:
      minVersion: VersionTLS12

Minimum and Maximum TLS Version

# Dynamic configuration
tls:
  options:
    default:
      minVersion: VersionTLS12
      maxVersion: VersionTLS13

Cipher Suites

# Dynamic configuration
tls:
  options:
    default:
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

For more information, refer to the official Traefik documentation.

HTTPS & TLS

Let's Encrypt

logo-traefik-proxy-logo.png

Overview

Traefik can automatically generate and renew TLS certificates using an ACME provider, such as Let’s Encrypt. This simplifies certificate management while ensuring secure HTTPS connections.

Let’s Encrypt and Rate Limiting

Let’s Encrypt imposes rate limits for API requests, which last up to one week and cannot be overridden. To avoid reaching these limits:

 

Certificate Resolvers

Certificate resolvers are defined in the static configuration and retrieve certificates from an ACME server. Each router that requires a certificate must reference a resolver explicitly using the tls.certresolver option.

Configuration Reference

 

Configuration Examples

Enable ACME

# Static configuration
dentryPoints:
  web:
    address: ":80"

  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    acme:
      email: your-email@example.com
      storage: acme.json
      httpChallenge:
        entryPoint: web

Single Domain from Router’s Rule

# Dynamic configuration
labels:
  - traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
  - traefik.http.routers.blog.tls=true
  - traefik.http.routers.blog.tls.certresolver=myresolver

Multiple Domains from Router’s Rule

# Dynamic configuration
labels:
  - traefik.http.routers.blog.rule=(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)
  - traefik.http.routers.blog.tls=true
  - traefik.http.routers.blog.tls.certresolver=myresolver

Multiple Domains from Router’s tls.domain

# Dynamic configuration
labels:
  - traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`)
  - traefik.http.routers.blog.tls=true
  - traefik.http.routers.blog.tls.certresolver=myresolver
  - traefik.http.routers.blog.tls.domains[0].main=example.com
  - traefik.http.routers.blog.tls.domains[0].sans=*.example.org

 

ACME Challenges

HTTP-01 Challenge

# Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    acme:
      httpChallenge:
        entryPoint: web

DNS-01 Challenge

# Static configuration
certificatesResolvers:
  myresolver:
    acme:
      dnsChallenge:
        provider: digitalocean
        delayBeforeCheck: 0
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

TLS-ALPN-01 Challenge

# Static configuration
certificatesResolvers:
  myresolver:
    acme:
      tlsChallenge: {}

 

Automatic Renewals

Traefik manages 90-day certificates and renews them automatically 30 days before expiry. For resolvers issuing custom-duration certificates, configure the renewal duration with the certificatesDuration option.

For more details, refer to the official Traefik documentation.

HTTPS & TLS

Setting up Self-Signed Multiple FQDN Certificates for Local Services in Traefik

logo-traefik-proxy-logo.pngOverview

In this article, we will walk through creating a self-signed certificate for multiple local services (e.g., Portainer and Pi-hole) using OpenSSL. We'll also configure Traefik to use this certificate in Docker Swarm. Additionally, we will explain how SSL certificates work, the role of key components like the private key, public key, and Certification Authority (CA). We'll use the provided image for understanding these concepts.

Prerequisites

Whats FQDN?

FQDN (Fully Qualified Domain Name) is the complete domain name of a specific host within the internet or a local network. It includes both the hostname and the domain name, ensuring the address is globally unique. An FQDN typically follows this format: hostname.domain.tld (e.g., www.example.com). For local networks, it can be something like portainer.local or pihole.local. The FQDN provides a precise location for a resource in the DNS hierarchy, making it essential for properly identifying services across networks.

Step 1: Create a Multiple FQDN Certificate with OpenSSL

  1. Generate a private key for the certificate:

    openssl genrsa -out local.key 4096
  2. Create a Certificate Signing Request (CSR) for multiple FQDNs. First, create a configuration file san.cnf:
    touch /mnt/glustermount/data/certs/san.cnf

    [req]  # Request options
    default_bits       = 4096  # Size of the encryption key
    prompt             = no    # No prompts, all values are provided in the config file
    default_md         = sha256  # Use SHA256 for the certificate
    distinguished_name = dn   # Use the 'dn' section for distinguished names
    req_extensions     = req_ext  # Use 'req_ext' for additional extensions like SAN (Subject Alternative Name)
    
    [dn]  # Distinguished Name section
    CN = portainer.local  # Common Name (CN) for the certificate (primary domain)
    
    [req_ext]  # Extensions for the certificate request
    subjectAltName = @alt_names  # Use alternative names (SAN)
    
    [alt_names]  # Alternative domain names
    DNS.1 = portainer.local  # First DNS name (alternative domain)
    DNS.2 = pihole.local     # Second DNS name (alternative domain)

  3. Generate the CSR using the configuration file:
    openssl req -new -key local.key -out local.csr -config san.cnf

  4. Generate a self-signed certificate for 1 year (365 days):
    openssl x509 -req -in local.csr -signkey local.key -out local.crt -days 365 -extfile san.cnf -extensions req_ext

  5. Move the certificate and key to a shared directory accessible by Docker Swarm:
    (If you need help to understand how the Nodes of the Docker Swarm Cluster are sharing the synced Files - Check this Article)
    mkdir -p /mnt/glustermount/data/certs
    mv local.crt local.key /mnt/glustermount/data/certs/

Step 2: Understanding the san.cnf File

The san.cnf file helps OpenSSL create a certificate with multiple domain names (FQDNs). Here’s a breakdown of the file:

This setup creates a certificate that can be used for both portainer.local and pihole.local, ensuring secure access over HTTPS. You can add any other Local DNS Entry to the List. Just make sure to add the Entry to your Pihole under the "Local DNS - DNS Records" Section.


Step 3: Add the Certificate to Traefik's Static Configuration (TOML)

Edit your traefik.toml file to include the certificate you generated:

[entryPoints]
  [entryPoints.websecure]
    address = ":443"

[tls]
  [[tls.certificates]]
    certFile = "/mnt/glustermount/data/certs/local.crt"
    keyFile  = "/mnt/glustermount/data/certs/local.key"
    stores = ["default"]

[tls.stores]
  [tls.stores.default]
    [tls.stores.default.defaultCertificate]
      certFile = "/mnt/glustermount/data/certs/local.crt"
      keyFile  = "/mnt/glustermount/data/certs/local.key"

This configuration tells Traefik to use the multiple FQDN certificate (local.crt) for requests matching portainer.local and pihole.local.


Step 4: Assign the Self-Signed Certificate to Specific Services

Now, configure the dynamic behavior of Traefik using the dynamic.toml file:

[http]
  [http.routers]
    [http.routers.portainer-secure]
      rule = "Host(`portainer.local`)"
      service = "portainer"
      entryPoints = ["websecure"]
      tls = { certResolver = "self-signed" }

    [http.routers.pihole-secure]
      rule = "Host(`pihole.local`)"
      service = "pihole"
      entryPoints = ["websecure"]
      tls = { certResolver = "self-signed" }

  [http.services]
    [http.services.portainer.loadBalancer]
      [[http.services.portainer.loadBalancer.servers]]
        url = "http://portainer:9443"

    [http.services.pihole.loadBalancer]
      [[http.services.pihole.loadBalancer.servers]]
        url = "http://pihole:888"


Step 5: Adjust the Pi-hole Docker Compose Configuration

Here’s the Pi-hole docker-compose.yml adjusted to match the certificate and Traefik settings:

version: '3'

services:
  pihole:
    networks:
      - management_net  # For management via Traefik
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "888:80"
    environment:
      TZ: 'Europe/Zurich'
      WEBPASSWORD: '${PIHOLE_PASSWORD}'
    volumes:
      - '/mnt/glustermount/data/pihole_data/etc:/etc/pihole'
      - '/mnt/glustermount/data/pihole_data/dns:/etc/dnsmasq.d'
    restart: unless-stopped
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.platform.os == linux]
      labels:
        - 'traefik.enable=true'
        - "traefik.http.routers.pihole-secure.rule=Host(`pihole.local`)"
        - "traefik.http.routers.pihole-secure.entrypoints=websecure"
        - "traefik.http.routers.pihole-secure.tls=true"
        - "traefik.http.services.pihole.loadbalancer.server.port=80"

networks:
  management_net:
    external: true


Step 6: Deploy the Updated Stack

Run the following command to apply the updated stack configuration:
(You can also use Portainer running the Stack)

docker stack deploy -c docker-compose.yml your_stack_name


Step 7: Test the Setup

  1. Add the self-signed certificate to your trusted sources on your machine. This can be done by importing the .crt file into your browser or system's trusted certificates store.

  2. Verify the secure connections:

    • Access https://portainer.local:9443
    • Access https://pihole.local:888

Both should now use your self-signed certificate with proper encryption.

Observability

Observability

Logrotation for Log & AccessLog

logo-traefik-proxy-logo.png

Introduction

This post is about enabling log rotation for the Traefik access.log and traefik.log. Some information is sourced from this post, with additional insights by Aeoneros.

Traefik will close and reopen its log files, assuming they’re configured, upon receiving a USR1 signal. This enables the logs to be rotated and processed by external programs like logrotate. However, this does not work on Windows due to the lack of USR signals.

The access.log and traefik.log require proper setup to ensure efficient log management. Below are the steps to manually create log rotation for these logs.

 

Step 1: Configure the Paths for Logs

In your Traefik static configuration file (e.g., traefik.toml), define the file paths for the logs. For example:

[accessLog]
  filePath = "/mnt/glustermount/data/traefik_data/access.log"

[log]
  filePath = "/mnt/glustermount/data/traefik_data/traefik.log"

Refer to the official documentation for access logs and general logs.

 

Step 2: Install Logrotate

Ensure the logrotate package is installed on your Debian-based system. Install it if necessary:

sudo apt update
sudo apt install logrotate

 

Step 3: Create a Logrotate File

Create a new configuration file for Traefik log rotation:

sudo nano /etc/logrotate.d/traefik

 

Step 4: Configure Logrotate

Paste the following content into the file:

/mnt/glustermount/data/traefik_data/access.log
/mnt/glustermount/data/traefik_data/traefik.log {
  compress
  create 0640 root root
  daily
  delaycompress
  missingok
  notifempty
  rotate 5
  postrotate
    # Send USR1 signal to reopen logs
    docker kill --signal=USR1 $(docker ps --filter "name=traefik_traefik" --format "{{.ID}}")
    # Pause to give Traefik time to process the signal
    sleep 5
    # Verify that Traefik is writing to the correct log files
    if [ -s /mnt/glustermount/data/traefik_data/access.log.1 ] || [ -s /mnt/glustermount/data/traefik_data/traefik.log.1 ]; then
      # Restart service if still writing to the rotated file
      docker service update --force traefik_traefik
    fi
  endscript
}

Explanation:

 

Step 5: Debugging Logrotate

Test your logrotate configuration in debug mode:

sudo logrotate -d /etc/logrotate.d/traefik

 

Step 6: Force Logrotate

Force log rotation to execute the script:

sudo logrotate -f /etc/logrotate.d/traefik

 

Step 7: Verify Log Rotation

Check if new files were created and if Traefik is writing to the correct log files:

ls -lh /mnt/glustermount/data/traefik_data/*.log*
tail -f /mnt/glustermount/data/traefik_data/access.log
tail -f /mnt/glustermount/data/traefik_data/traefik.log

 

Troubleshooting

If nothing is working, revert the changes by following these steps:

  1. Rename or delete the logrotate file:
sudo mv /etc/logrotate.d/traefik /etc/logrotate.d/traefik.bak
  1. Edit the logrotate status file to remove entries related to the logs:
sudo nano /var/lib/logrotate/status
  1. Look for and remove entries related to /mnt/glustermount/data/traefik_data/access.log and /mnt/glustermount/data/traefik_data/traefik.log.

Reapply the steps once the issue is resolved.