Basic Traefik Configuration for HTTP and HTTPS

Configuring Traefik for serving HTTP and HTTPS is fairly simple, but requires a few steps to get working correctly.

Basic Traefik Configuration for HTTP and HTTPS
Photo by Ferenc Almasi / Unsplash
ℹ️
Hey there! I hope this has been useful to you! I've started blogging again; if you're interested in short, easy reads about productivity and mental/physical health, sign up for my mailing list. I've gotten a bunch of positive feedback on one of my recent posts named The Fall, in case you're looking for a sample of what to expect.

Configuring Traefik for serving HTTP and HTTPS is fairly simple, but requires a few steps to get working correctly. In short, the steps are as follows:

  • Listen on the required ports
  • Configure your ACME provider
  • Configure your Docker containers to send traffic to the required ports
  • Optional: redirect HTTP to HTTPS

All configuration file settings will be shown in TOML format.

Configure Your ACME Provider

Traefik supports automatic SSL certificate creation via the ACME protocol, the biggest provider of which is Let's Encrypt. We first need to define our certificate resolver and our challenge format. This will configure a DNS challenge with Cloudflare, but you can set yours up with whichever DNS provider you use.

[certificatesResolvers.my-resolver.acme]
  email = "[email protected]"
  storage = "/acme.json"
  [certificatesResolvers.my-resolver.acme.dnsChallenge]
    provider = "cloudflare"

In addition to this, you will need to provide a Cloudflare API key via an environment variable. All of the environment variables are documented here for your DNS provider.

Listening On The Required Ports

We now need to add some configuration options to our Traefik config file.

[entrypoints]
  [entrypoints.web]
  	address = ":80"
  [entrypoints.websecure]
    address = ":443"
    [entrypoints.websecure.http.tls]
      certresolver = "my-resolver"

Here, two entrypoints are defined, named web and websecure. The first port listens on port 80, the second listens on port 443 and expects connections to be secured by TLS. Your certificates will be created via my-resolver.

Configure Docker Containers

Time for some labels. A more comprehensive guide for how labels work is coming later. But for now, you can use this as an example.

traefik.enable=true
traefik.http.routers.blog.entrypoints=web,websecure
traefik.http.routers.blog.tls=true
traefik.http.routers.blog.rule=Host(`blog.example.com`)

This does the following:

  • Exposes this container by Traefik (not required if you expose by default, which you probably shouldn't)
  • Lets this container be exposed on both ports 80 and 443 via the web and websecure endpoints
  • Enable TLS for this container
  • Any connections coming through with a hostname of blog.example.com will route to this container.

Optional: Redirect HTTP to HTTPS

Redirection is done in two steps:

  • Create a redirection middleware
  • Assign that middleware to the above Docker container

I personally assign my middleware definitions to my Traefik container, but they can hypothetically go anywhere and still work. Let's define our redirection middleware with the below labels, which we'll call force-secure:

traefik.http.middlewares.force-secure.redirectscheme.scheme=https
traefik.http.middlewares.force-secure.redirectscheme.permanent=true

The first line is required. This says "any request that goes through this middleware should be redirected to the HTTPS scheme". The second line is optional but strongly recommended. It determines whether the HTTP response code is a temporary redirect or a permanent redirect.

Once this is defined, we need to modify our original label definition for the web entrypoint, then create an insecure route that will redirect to the secure version.

traefik.enable=true

traefik.http.routers.blog.entrypoints=websecure # Remove `web`
traefik.http.routers.blog.tls=true
traefik.http.routers.blog.tls.certresolver=my-resolver
traefik.http.routers.blog.rule=Host(`blog.example.com`)

traefik.http.routers.blog-insecure.entrypoints=web
traefik.http.routers.blog-insecure.rule=Host(`blog.example.com`)
traefik.http.routers.blog-insecure.middlewares=force-secure

Alternatively, you can create a catch-all route that will redirect all insecure connections to their secure equivalent, which is what I do. You will still need to remove web from the list of entrypoints you provided in the original definition.

traefik.http.routers.blog.entrypoints=websecure # Remove `web`

traefik.http.routers.http-catchall.rule=HostRegexp(`{any:.+}`)
traefik.http.routers.http-catchall.entrypoints=web
traefik.http.routers.http-catchall.middlewares=force-secure