Traefik entrypoint http to https redirect

If you followed the Traefik docs you would have expected that it's going to work, but as it goes, it's never that straightforward. Let's go over the additional sneaky steps we have to do.


Configuration Confusion

I don't know about you, but the first time I read their docs I was confused about the different configurations Traefik offers. It basically boils down to the following.

Traefik has two types of configurations:

  • Static configuration which is read at startup and defines entry points and provider data for the dynamic configuration.
  • Dynamic configuration which is read runtime and handles everything else: Routers, Services, Middlewares, and Certificates

Static configuration can be in the form of a Yaml/Toml file, ENV arguments, or CLI parameters passed in your docker-compose.yml to your Traefik service. 

Dynamic configuration can be in many forms depending on which provider you are using, for the full list you can read the Supported Providers section of the docs.

It is also possible to cross-reference configurations from different providers or from static to dynamic but let's leave that for another day, if you're keen on reading up on it, you can read the section about Provider Namespaces in the official docs. 

Now that we have this out of the way, let's get to the problem at hand.

 

Entrypoint global redirect from HTTP to HTTPS

In the examples, in this article, we're going to be using the Docker provider for the dynamic configuration and a Yaml file for the static configuration parts. The docs say we should add the following rules under our entryPoints key:

entryPoints:
    web:
        address:  :80
        http:
            redirections:
                entryPoint:
                    to: web-secure
                    scheme: https
                    permanent: true
    
    web-secure:
        address:  :443

web and web-secure keys can be anything, that's user-defined not to be confused like I was the first time I used it. This looks simple enough, and when you run it you would expect it is going to work as I did and then I had an open HTTP port in production for almost a year now for my personal website, which thankfully returned nothing, but still.

 

The catch is when you define your routing rules in your provider dynamic config, for this global redirect to work, you need to have two routers for the same domain, one for HTTP listening on port 80 and one for HTTPS listening on port 443 with the TLS config enabled.

  backend:
    labels:              
      # sasablagojevic.com web (Entrypoint global scheme redirect requires web router definitions)
      traefik.http.routers.sasablagojevic-http.entrypoints: web  
      traefik.http.routers.sasablagojevic-http.rule: "Host(`sasablagojevic.com`, `www.sasablagojevic.com`)"

      # sasablagojevic.com web-secure
      traefik.http.routers.sasablagojevic.entrypoints: web-secure
      traefik.http.routers.sasablagojevic.rule: "Host(`sasablagojevic.com`, `www.sasablagojevic.com`)"
      traefik.http.routers.sasablagojevic.tls: true
      traefik.http.routers.sasablagojevic.tls.certresolver: myresolver
      traefik.http.routers.sasablagojevic.tls.domains[0].main: sasablagojevic.com
      traefik.http.routers.sasablagojevic.tls.domains[0].sans: www.sasablagojevic.com

This is required by Traefik to be able to catch the requests on port 80 and redirect them to port 443.

You can validate if the entry point global scheme redirect is working by looking in the Traefik admin panel, you should see the item underlined with a red line from the screenshot:


Middleware redirect from HTTP to HTTPS

There is also a different approach you can take and instead of a global redirect which redirects all traffic from port 80 to port 443, you can define, a per-service redirect with middlewares. Traefik gives us a middleware for that out of the box, we just need to wire it up in our docker-compose.yml

  backend:
    labels:
      # www -> non-www redirect middleware declaration
      traefik.http.middlewares.www-redirect.redirectregex.regex: "^https://www.(.*)"
      traefik.http.middlewares.www-redirect.redirectregex.replacement: "https://$${1}"
      traefik.http.middlewares.www-redirect.redirectregex.permanent: true

      # http -> https redirect middleware declaration
      traefik.http.middlewares.http-redirect.redirectscheme.scheme: https
      traefik.http.middlewares.http-redirect.redirectscheme.permanent: true

      # sasablagojevic.com web 
      traefik.http.routers.sasablagojevic-http.entrypoints: "web"  
      traefik.http.routers.sasablagojevic-http.rule: "Host(`sasablagojevic.com`, `www.sasablagojevic.com`)"
      traefik.http.routers.sasablagojevic-http.middlewares: "http-redirect"
      
      # sasablagojevic.com web-secure
      traefik.http.routers.sasablagojevic.entrypoints: web-secure
      traefik.http.routers.sasablagojevic.rule: "Host(`sasablagojevic.com`, `www.sasablagojevic.com`)"
      traefik.http.routers.sasablagojevic.tls: true
      traefik.http.routers.sasablagojevic.tls.certresolver: myresolver
      traefik.http.routers.sasablagojevic.tls.domains[0].main: sasablagojevic.com
      traefik.http.routers.sasablagojevic.tls.domains[0].sans: www.sasablagojevic.com
      traefik.http.routers.sasablagojevic.middlewares: "www-redirect"

Once again the .http-redirect. segment of the middleware label is user-defined and can be anything. As you can see from the provided example, each middleware configuration has two parts, the declaration part, and the part where we wire it up with our service.

Hope this saves you some time, I lost a whole day going in circles with this...

Last updated: 8 days ago 1806