Enabling HTTPS termination in Traefik

Let's Encrypt my Blog!

Posted on 25 February 2017

In a previous blog post I showed you how I set up a fully dockerized environment for my VPS hosting my blog. I also mentioned that I wanted to enable HTTPS for my blog. In this short blog post I’ll show you how to enable automatic Let’s Encrypt certificate retrieval in Traefik.

Introduction

So first of all, why HTTPS? I only have a blog with static content right? Correct! But there are two main reasons why you’d want HTTPS even for a site with only static content. First of all; with plain HTTP anyone between your server and the client can insert information in transit. So an Internet Service Provider could if they wanted insert their own advertisements. You think ISP’s won’t do that? Think again! Yes; I was just as appalled as you are right now.

Secondly not having HTTPS will affect your Google Rank. When Google is indexing a page it tries to find a HTTPS link to it instead. If it finds a HTTPS link that one is used for indexing instead of the HTTP link. This is why you want to have HTTPS enabled even on static content.

My Traefik Deployment

Traefik fortunately supports the free Let’s Encrypt certificates out of the box. All that is needed for Let’s Encrypt is an e-mail address and you 'proving' that you own a domain by providing some content on it. Traefik handles this last bit for you, however there are some caveats.

What went wrong

The way this 'proof' works is that Let’s Encrypt does a request to your domain over HTTP. This makes sense since you’re setting up a new domain; there is no HTTPS certificate yet so it can’t reach your server (Traefik). So don’t enable forwards from HTTP to HTTPS yet!

What also went wrong for me initially was that my docker-compose files had hosts rules like "blog.localhost", "jenkins.localhost", etc. Since Traefik doesn’t understand that these should not have certificates it failed on trying to get certs for these. So I had to change the docker-compose.yml files for a few services to remove the localhost entries, so to take my blog for example I had to change it from this:

labels:
  - "traefik.backend=blog"
  - "traefik.frontend.rule=Host: blog.localhost, niels.nu, www.niels.nu"
  - "traefik.port=80"

To this:

labels:
  - "traefik.backend=blog"
  - "traefik.frontend.rule=Host: niels.nu, www.niels.nu"
  - "traefik.port=80"

Traefik config

So since you need to configure Let’s Encrypt in your Traefik config file (traefik.toml) I had to change my deployment a bit. So this is my .toml file:

defaultEntryPoints = ["http", "https"]

[web]
address = ":8080"

[entryPoints]

[entryPoints.http]
address = ":80"
#[entryPoints.http.redirect]
#entryPoint = "https"

[entryPoints.https]
address = ":443"

[entryPoints.https.tls]

[acme]
email = "[email protected]"
storage = "acme.json"
entryPoint = "https"
onDemand = false
OnHostRule = true

You can see that this config has the HTTP to HTTPS redirect disabled. I had to disable this to make sure that the verification from Let’s Encrypt to my domain would work.

I created a simple Dockerfile to add traefik.toml to the image:

FROM traefik
ADD traefik.toml .
EXPOSE 80
EXPOSE 8080
EXPOSE 443

And slightly changed my docker-compose.yml to use this Dockerfile instead of just pulling the image:

version: '2'

services:
  proxy:
    build: .
    restart: always
    command: --web --docker --logLevel=DEBUG
    networks:
      - webgateway
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

networks:
  webgateway:
    driver: bridge

I then deployed the new Treafik instance with docker-compose up -d --build (the --build was added to force Docker compose to always rebuild the container from the Dockerfile).

When I check the logs on the Treafik container I now get this output:

time="2017-02-25T11:48:20Z" level=debug msg="Challenge GetCertificate niels.nu"
time="2017-02-25T11:48:20Z" level=debug msg="ACME got domain cert niels.nu"

And voila; my blog is now reachable on https://niels.nu !

Conclusion

I certainly put off enabling HTTPS long enough! I really like how Traefik does all the heavy lifting for me. The only main issues I had were having a HTTP to HTTPS redirect enabled and having some 'invalid' public domains in the docker-compose files for my applications.