Categories
DevOps Networking Server

Traefik 2.5 quick-start guide

How to use TOML, YAML, or Docker Labels to hit the ground running with Traefik 2.5 under Docker Compose.

Dynamic configurations

Now on to the dynamic configurations in /srv/traefik/traefik.d/, where we define our operations!

In this section, I’m going to cover the following:

Administrators

To see how this is used to restrict access to specific users as a part of multiple middlewares being applied, please see the Traefik dashboard section.

/srv/traefik/traefik.d/core-admins.toml

[http.middlewares]
    [http.middlewares.admin-users.basicAuth]
        usersFile = "/users/admins"

/srv/traefik/traefik.d/core-admins.yaml

http:
    middlewares:
        admin-users:
            basicAuth:
                usersFile: "/users/admins"
Bastion hosts

To see how this is used to restrict access to specific hosts as a part of multiple middlewares being applied, please see the Traefik dashboard section.

/srv/traefik/traefik.d/core-bastions.toml

[http.middlewares]
    [http.middlewares.bastion-hosts.ipWhiteList]
        sourceRange = [
            "1.1.1.1",  # Admin Server #1
            "2.2.2.2",  # Admin Server #2
            "3.3.3.3",  # VPN
        ]

/srv/traefik/traefik.d/core-bastions.yaml

http:
    middlewares:
        bastion-hosts:
            ipWhiteList:
                sourceRange:
                    - "1.1.1.1",  # Admin Server #1
                    - "2.2.2.2",  # Admin Server #2
                    - "3.3.3.3",  # VPN
Certificates

To see how these certificates are easily generated (and renewed) and distributed to Traefik instances on a routine schedule, please check out my prior article, Simple certs with Docker-Dehydrated.

If you’re familiar with the concept of SNI (Server Name Indication), Traefik matches hostnames to loaded certificates. Did you just register a domain and generate a new certificate that’s been copied to your Traefik server? Add it into this file, save the changes, and Traefik will pick up on it without needing to be restarted — the same goes for when a certificate is renewed and synchronized to a Traefik server.

/srv/traefik/traefik.d/core-certificates.toml

[[tls.certificates]]
    certFile = "/letsencrypt/thad.getterman.org/fullchain.pem"
    keyFile = "/letsencrypt/thad.getterman.org/privkey.pem"

[[tls.certificates]]
    certFile = "/letsencrypt/ltg.fyi/fullchain.pem"
    keyFile = "/letsencrypt/ltg.fyi/privkey.pem"

/srv/traefik/traefik.d/core-certificates.yaml

tls:

    certificates:

        - certFile: /letsencrypt/thad.getterman.org/fullchain.pem
          keyFile: /letsencrypt/thad.getterman.org/privkey.pem

        - certFile: /letsencrypt/ltg.fyi/fullchain.pem
          keyFile: /letsencrypt/ltg.fyi/privkey.pem
Redirect traffic with regex patterns

I prioritize the following rule (the higher the number, the higher the priority) and strip the www sub-domain from my URL shortener domain with the following:

/srv/traefik/traefik.d/route-ltg.fyi.toml

# Remove WWW
[http.routers.Router-YOURLS-WWW]
    entrypoints = ["websecure"]
    rule = "Host(`www.ltg.fyi`)"
    priority = 90
    service = "nginx"
    middlewares = [
        "YOURLS-Redirect-RemoveWWW",
    ]
    [http.routers.Router-YOURLS-Loader.tls]

# Middlewares
[http.middlewares]

    # Remove WWW
    [http.middlewares.YOURLS-Redirect-RemoveWWW.redirectRegex]
        regex = "^https://www.ltg.fyi/(.*)"
        replacement = "https://ltg.fyi/${1}"

/srv/traefik/traefik.d/route-ltg.fyi.yaml

# Remove WWW
http:
    routers:
        Router-YOURLS-WWW:
            entryPoints:
                - "websecure"
            rule: "Host(`www.ltg.fyi`)"
            priority: 90
            service: nginx
            middlewares:
                - YOURLS-Redirect-RemoveWWW
            tls: {}

# Middlewares
http:
    middlewares:
        YOURLS-Redirect-RemoveWWW:
            redirectRegex:
                regex: "^https://www.ltg.fyi/(.*)"
                replacement: "https://ltg.fyi/${1}"
Block sensitive paths

I use this middleware plug-in extensively, which I define with:

/srv/traefik/traefik.d/block-sensitive.toml

[http.middlewares]
    [http.middlewares.block-sensitive.plugin.blockpath]
        regex   =   [
                        "^/.svn",
                        "^/.git",
                        "^/.ht",
                        "^/.user.ini",
                    ]

/srv/traefik/traefik.d/block-sensitive.yaml

http:
    middlewares:
        block-sensitive:
            plugin:
                blockpath:
                    regex:
                        - "^/.svn"
                        - "^/.git"
                        - "^/.ht"
                        - "^/.user.ini"

Then, I enable this for my sites, such as for LTG.FYI:

/srv/traefik/traefik.d/route-ltg.fyi.toml

[http.routers.Router-YOURLS-Loader]
    entrypoints = ["websecure"]
    rule = "Host(`ltg.fyi`) && Method(`GET`) && Path(`/{[a-zA-Z0-9]+}`)"
    service = "nginx"
    middlewares = [
        "block-sensitive",
    ]
    [http.routers.Router-YOURLS-Loader.tls]

/srv/traefik/traefik.d/route-ltg.fyi.yaml

http:
    routers:
        Router-YOURLS-Loader:
            entryPoints:
                - "websecure"
            rule: "Host(`ltg.fyi`) && Method(`GET`) && Path(`/{[a-zA-Z0-9]+}`)"
            service: nginx
            middlewares:
                - block-sensitive
            tls: {}
Services
Nginx

As you just saw with an excerpt from the configuration for LTG.FYI, I call on the service nginx. With multiple sites using the same service, I need only define that service once:

/srv/traefik/traefik.d/service-nginx.toml

[http.services]
    [http.services.nginx.loadBalancer]
        [[http.services.nginx.loadBalancer.servers]]
            url = "http://nginx:80"

/srv/traefik/traefik.d/service-nginx.yaml

http:
    services:
        nginx:
            loadBalancer:
                servers:
                    - url: "http://nginx:80"
Who am I?

Traefik Labs has made a simple Docker image that displays information about HTTP requests sent to it. I frequently use this when I’m setting up a new route, or want to test middleware before deploying it. Similar to Nginx, I define the service once to be called by my routes:

/srv/traefik/traefik.d/service-whoami.toml

[http.services]
    [http.services.whoami.loadBalancer]
        [[http.services.whoami.loadBalancer.servers]]
            url = "http://whoami:80"

/srv/traefik/traefik.d/service-whoami.yaml

http:
    services:
        whoami:
            loadBalancer:
                servers:
                    - url: "http://whoami:80"
Example.com

Occasionally, I need to pass a request to a remote site that’s been secured with HTTPS. The easiest way for me to see if it works is to send it to example.com.

/srv/traefik/traefik.d/service-example.toml

[http.services]
    [http.services.example.loadBalancer]
        passHostHeader = false
        [[http.services.example.loadBalancer.servers]]
            url = "https://example.com/"

/srv/traefik/traefik.d/service-example.yaml

http:
    services:
        example:
            loadBalancer:
                passHostHeader: false
                servers:
                    - url: "https://example.com/"
Traefik dashboard

This is a bit of an exotic setup:

  • 2 domains (Thad.Getterman.org and LTG.FYI), 1 path (/traefik).
  • Restricted access
    • Bastion hosts
    • Administrative users
  • Fooling the dashboard into thinking that it’s sitting on its own domain — and why you see so many people typically use Traefik as a sub-domain such as traefik.example.com.
    • Stripping /traefik from the path that’s passed to the Traefik dashboard.
    • Replacing all occurrences of /api with /traefik/api.

/srv/traefik/traefik.d/route-traefik-dashboard.toml

[http.routers.Router-Dashboard]
    entrypoints = ["websecure"]
    rule = "(Host(`thad.getterman.org`) || Host(`ltg.fyi`)) && PathPrefix(`/traefik`)"
    service = "api@internal"
    middlewares = [
        "bastion-hosts",
        "admin-users",
        "dashboard-stripprefix",
        "rewrite-dashboard-api",
    ]
    [http.routers.Router-Dashboard.tls]

[http.middlewares]

    # Don't pass /traefik to the service.
    [http.middlewares.dashboard-stripprefix.stripPrefix]
        prefixes = ["/traefik"]

    [http.middlewares.rewrite-dashboard-api.plugin.rewritebody]
        # Keep Last-Modified header returned by the HTTP service.
        # By default, the Last-Modified header is removed.
        lastModified = true
        # Rewrites all "/api" occurences with "/traefik/api".
        [[http.middlewares.rewrite-dashboard-api.plugin.rewritebody.rewrites]]
        regex = "/api"
        replacement = "/traefik/api"

/srv/traefik/traefik.d/route-traefik-dashboard.yaml

http:

    routers:
        Router-Dashboard:
            entryPoints:
                - "websecure"
            rule: "(Host(`thad.getterman.org`) || Host(`ltg.fyi`)) && PathPrefix(`/traefik`)"
            service: "api@internal"
            middlewares:
                - bastion-hosts
                - admin-users
                - dashboard-stripprefix
                - rewrite-dashboard-api
            tls: {}

    middlewares:

        # Don't pass /traefik to the service.
        dashboard-stripprefix:
            stripPrefix:
                prefixes:
                    - "/traefik"

        rewrite-dashboard-api:
            plugin:
                rewritebody:
                    # Keep Last-Modified header returned by the HTTP service.
                    # By default, the Last-Modified header is removed.
                    lastModified: true
                    # Rewrites all "/api" occurences with "/traefik/api".
                    rewrites:
                        regex: "/api"
                        replacement: "/traefik/api"

One reply on “Traefik 2.5 quick-start guide”

Leave a Reply

Your email address will not be published. Required fields are marked *