---
title: "Traefik: managing both HTTP and HTTPS connections separately"
author: Yarmo Mackenbach
slug: traefik-http-https
date: "2020-07-28 00:00:00"
published: true
---

## Introduction

If you have used the wonderful [Traefik](https://containo.us/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](https://letsencrypt.org/).

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](https://docs.traefik.io/https/acme/).

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](https://docs.traefik.io/https/acme/).

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](https://hub.docker.com/_/nextcloud) container, a [Wallabag](https://hub.docker.com/r/wallabag/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](https://www.influxdata.com/time-series-platform/telegraf/) which sends the metrics to an [InfluxDB](https://www.influxdata.com/) database to be analyzed by [Grafana](https://grafana.com/), a setup also known as the [TIG stack](https://hackernoon.com/monitor-your-infrastructure-with-tig-stack-b63971a15ccf). 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](https://pi-hole.net/)) 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](https://docs.traefik.io/middlewares/overview/) whose only responsibility is to redirect HTTP requests to HTTPS requests.

The next few lines applies this `middleware` to a [router](https://docs.traefik.io/routing/routers/). 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](https://hub.docker.com/r/containous/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.
