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:
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: 1 year ago