Using HTTPS certificates with Traefik and Docker for a development environment

Traefik is a great “cloud” router that is perfect for use in a development environment to route traffic to different Docker hosts, but when I came to try and add some self-signed certificates to it so that my development environment more realistically mirrored the staging and production environments I ran into some problems and the Traefik documentation, whilst good, unfortunately, is a little vague around the subject of certificates in a general, so it took some Googling and putting various different things together to come up with a final solution that works well.

I already had several development sites set up using Traefik as the router to send traffic to the appropriate site based on the domain name, and after reading the docs, I thought it should be as easy as:

  1. Creating some self-signed certificates using openssl.
  2. Adding and trusting the certificates to the certificate store on my Mac.
  3. Telling Traefik to use the certificates where appropriate.

With this, I was almost right, but I discovered a few “gotchas” along with way.

Generating Certificates

Whilst it is easy enough to generate a self-signed certificate using openssl, it seems it is more difficult to get the browser to trust that certificate than it was previously, and in the case of Chrome, nearly impossible. There is, however, a very nice, free open source solution to this by the way of mkcert, which is also cross-platform, so can be used on Windows, Mac and Linux. This handy little tool will add itself as a certificate authority to your computers certificate store and then allow you to generated certificates, signed by its own “authority”, which means your browser will believe it is a “true” and “trusted” certificate.

Simply follow the installation instructions and note there is an extra step for Firefox, and once you have it installed you can generate certificates using the command:

mkcert [list of domains]

So you could do:

mkcert www.mydomain.local www.mydomain2.local test.mydomain.local

This command will generate one certificate file that contains a certificate with these three domains listed as valid for that certificate.

It also supports wildcard domains as well, so you could make a certificate like this:

mkcert "*.mydomain.local"

Then, you could use this certificate for any subdomain of mydomain.local, so test.mydomain.local, www.mydomain.local, tasks.mydomain.local and so on.

So, now we have certificates that the browser will recognise and trust, we need to add them to Traefik, and this is where the documentation let me down.

Adding Certificate to Traefik

The way I have Traefik configured is with a very simple YAML configuration file that is bound to the Traefik docker container via a bind on startup, so the traefik.yml on my Mac is seen by the Traefik docker container as being /etc/traefik/traefik.yml on the container.

From reading the documentation, I was under the impression all I needed to do was:

  1. Bind the directory containing my certificates to a directory on the Traefik docker container.
  2. Add a tls: section to my traefik.yml file to declare the certificate files to Traefik on the path they were bound to in step 1.
  3. Add a couple of labels to the docker containers that would be using the certificate to turn on TLS and tell it which domains would be on TLS.

After doing all this, I could connect to the site on HTTPS but it kept giving me the “default certificate”, e.g. one Traefik generates automatically and not a certificate the browser sees as trusted. After much searching around, however, I found the solution. The tls: configuration actually needs to be in a separate file, that Traefik refers to as a “dynamic configuration”. To do this, you need to tell Traefik about this “dynamic configuration” file in your main traefik.yml file and then bind this new file into the Docker container at the point you have specified in your traefik.yml file. So I ended up with this:

traefik.yml

## traefik.yml

## Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

# Docker configuration backend
providers:
  docker:
    network: "my-bridge-network"
    exposedByDefault: false
    watch: true
  file:
    filename: /etc/traefik/dynamic_conf.yml
    watch: true

# API and dashboard configuration
api:
  insecure: true

dynamic_conf.yml

# Dynamic configuration
tls:
  certificates:
    - certFile: "/etc/traefik/certs/www.domain1.andrew.pem"
      keyFile: "/etc/traefik/certs/www.domain1.andrew-key.pem"
    - certFile: "/etc/traefik/certs/_wildcard.domain2.andrew.pem"
      keyFile: "/etc/traefik/certs/_wildcard.domain2.andrew-key.pem"
    - certFile: "/etc/traefik/certs/www.domain3.andrew+2.pem"
      keyFile: "/etc/traefik/certs/www.onlytease.andrew+2-key.pem"

With the following binds:

HostContainer
/Users/andrew/certs//etc/traefik/certs
/Users/andrew/dynamic_conf.yml/etc/traefik/dynamic_conf.yml
/Users/andrewdixon/traefik.yml/etc/traefik/traefik.yml

Then, on each of the web site containers I added the following labels:

traefik.http.routers.[site_router_name].entrypoints
traefik.http.routers.[site_router_name].tls
traefik.http.routers.[site_router_name].tls.domains[0].main
traefik.http.routers.[site_router_name].tls.domains[0].sans

So, for example, it might look like this if the site_router_name was mydomain and the site was served on the domains www.mydomain.local, tasks.mydomain.local and test.mydomain.local:

traefik.http.routers.mydomain.entrypoints = websecure
traefik.http.routers.mydomain.tls = true
traefik.http.routers.mydomain.tls.domains[0].main = www.mydomain.local
traefik.http.routers.mydomain.tls.domains[0].sans = tasks.mydomain.local test.mydomain.local

After this is done and everything has been restarted, you can then access your development sites on HTTPS and with no browser warning. If you need to add more in future, it is as simple as generating another certificate, adding it to the dynamic_conf.yml file and adding the labels to the container.

4 Replies to “Using HTTPS certificates with Traefik and Docker for a development environment”

  1. Thank you for this great article… It saved my day 🙂

    Reply

    1. No problem, glad it helped 😀

      Reply

  2. Just wanted to say thank you for posting this, helped me and my team figure it out immediately!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *