Traefik: managing both HTTP and HTTPS connections separately
Date
Tags
#selfhosting
Introduction
If you have used the wonderful Traefik before to route all your traffic to different docker containers or other services, you'll know how easy it is to add SSL certificates and secure HTTPS connections, simple and free thanks to their integration with Let's Encrypt.
You will first need the following lines in the traefik.toml
file:
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.http]
[entryPoints.web.http.redirections]
[entryPoints.web.http.redirections.entryPoint]
to = "websecure"
scheme = "https"
[entryPoints.websecure]
address = ":443"
To learn more about this setup using traefik.yml
or the CLI, please check out the documentation.
What these lines do is make sure that Traefik listens to the correct ports, 80
for HTTP connections (or web
) and 443
for HTTPS connections (or websecure
). Because we only want secure connections coming from the internet, Traefik is instructed to always redirect web
entrypoint connections to the websecure
entrypoint. Easy and safe!
Now, let us get a SSL certificate and secure those HTTPS connections:
[certificatesResolvers.myresolver.acme]
email = "test@example.com"
storage = "acme.json"
[certificatesResolvers.myresolver.acme.httpChallenge]
entryPoint = "web"
Setting up the certificateResolver
is only half the process, now you need to make sure your docker container uses it by appending a few labels to docker-compose.yml
:
mycontainer:
image: someimage
labels:
- traefik.http.routers.router0.rule=Host(`example.com`)
- traefik.http.routers.router0.tls=true
- traefik.http.routers.router0.tls.certresolver=myresolver
To learn more about this setup using swarm, kubernetes or rancher, please check out the documentation.
You don't often get so much functionality out of a few lines of code: the service provided by mycontainer
, whether it's a Nextcloud container, a Wallabag container or any other service you might enjoy using, is now available by visiting example.com with HTTPS enabled automatically ensuring a secure connection now and in the future as Traefik manages the certificate renewal for you.
Once you start hosting 20, 30, maybe 40 containers and making them accessible to yourself, to friends and family or the entire world through the internet, Traefik really starts to make your self-hosting life a whole lot more enjoyable.
The problem: home connections
There's one use-case where the "HTTPS everything" credo becomes counter-productive: services that should only be accessible via the home network.
In my home, I monitor a lot of services and devices using Telegraf which sends the metrics to an InfluxDB database to be analyzed by Grafana, a setup also known as the TIG stack. All these services are hosted on a server running inside my home.
The thing is, I don't need access to my Grafana dashboards outside my home. In fact, I don't even want those dashboards and the data they display available on the internet. So, I can just make up a domain that doesn't exist, say "grafana.lan", ensure that my home's DNS resolver (this could be your router or, in my case, PiHole) sends any grafana.lan
requests to my server instead of to the internet and just make my Grafana container respond to grafana.lan
requests using Traefik labels:
grafana:
image: grafana/grafana
labels:
- traefik.http.routers.grafana.rule=Host(`grafana.lan`)
- traefik.http.services.grafana.loadbalancer.server.port=3000
I added a server.port
label to make sure Traefik forwards all requests to the correct port that Grafana listens to, in this case 3000
.
I removed the TLS-related labels since I won't be needing HTTPS! Inside my home, I can just visit http://grafana.lan
since I won't be using the dangerous internet connections outside my home.
Simple, right?
Well, no. We have a problem, because this setup won't work.
Redirect HTTP to HTTPS
Remember the first lines we added to traefik.toml
? The ones that redirected all HTTP requests to the HTTPS entrypoint? Well, every time we want to visit http://grafana.lan
, it will be redirected to https://grafana.lan
. In the best case scenario, your browser will display a few flashy warnings that you are about to enter a website over an unsecured connection, with a hidden button that allows you to proceed anyway. In the worst case scenario, your browser will not allow you anywhere close to your own container because there is a certificate problem.
So, the problem is that there is no certificate for grafana.lan
? Well, simple! Let's just add back the TLS labels and have a secure connection within the home!
Again, no can do. A domain needs to exist and be accessible from the internet in order for a SSL certificate to be issued. Since neither criteria are applicable to our grafana.lan
, we can't get a SSL certificate.
Luckily, there is a solution.
The solution: domain-specific HTTP redirection
What we need to do is instruct Traefik to not redirect all HTTP connections to HTTPS, but only those that we can access from the internet. The connections that stay in the house should remain HTTP connections.
Remember these lines?
[entryPoints.web.http]
[entryPoints.web.http.redirections]
[entryPoints.web.http.redirections.entryPoint]
to = "websecure"
scheme = "https"
These need to be removed from traefik.toml
so that you keep the basic entrypoint definitions:
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
Next, we need to add a so-called dynamic file
configuration. Add the following line to the [providers]
section in traefik.toml
:
[providers.file]
filename = "/path/to/traefik_dynamic.toml"
watch = true
Create the file /path/to/traefik_dynamic.toml
and add the following content:
[http]
[http.middlewares]
[http.middlewares.redirect_to_https]
[http.middlewares.redirect_to_https.redirectscheme]
scheme = "https"
[http.routers]
[http.routers.web_redir]
rule = "HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`)"
entryPoints = ["web"]
middlewares = ["redirect_to_https"]
service = "api@internal"
This code instructs Traefik to add a new middleware whose only responsibility is to redirect HTTP requests to HTTPS requests.
The next few lines applies this middleware
to a router. The trick here is that this router is only applied to requests that target example.com
and all its subdomains. You could add as many domains as you need to get them to always redirect to HTTPS. Our home domain grafana.lan
is not in the list, therefore the middleware
will not be applied to it and the connection will remain HTTP!
Note: the router points to the service api@internal
. This is done because a router always needs a service even when, as in this case, the service will never be used because the connection is redirected to HTTPS and after that, this router is no longer used. If you don't like using api@internal
for this purpose, you could always run a harmless whoami container and point the router to that service.
Conclusion
This Traefik setup takes a bit more effort but allows you to gracefully handle two different types of connections.
Connections coming from the internet are secured via SSL certificates and will always happen over HTTPS.
Connections coming from within the house stay within the house, they happen over HTTP and you can feel a lot safer knowing the internet no longer has direct access to that container.