There are many ways to expose your containers to the outside world, but I’ve yet to come across something as cool as traefik! Whom am I kidding, there’s a lot of options out there that accomplish similar goals, but I found traefik to be the best at integrating them all into one package, and it’s yet to fail me. Throw any reasonable task at it, and traefik adapts - it supports a variety of integrations, what it calls Providers (see docs for all integrations) right out of the box. The reason I love traefik is that it’s a perfect fit as an ambassador for your other containers.

To give you an idea of what class of application we’re looking at tooday, we’re looking at reverse proxy’ing and handling TLS termination. Some well-known alternatives to traefik include:

Each of these takes a somewhat different approach; there are pros and cons of each. We’ll walk through an example deployment together and deploy the environment using Docker Compose.

Pre-requisites

You’ll need an internet connection that’s capable of accessing https://hub.docker.com/.

You must first have Docker and Docker Compose installed, and you should verify you can run the two commands below:

docker version
docker-compose version

If these commands succeed, you’re good to go. If you don’t have one of them installed, check out Get Docker CE for Ubuntu. There are links on the left menu for alternative steps for other distributions. There’s also a document for Installing Docker Compose.

Only Three Files

It’s pretty simple to get started off; we only need three files.

  • docker-compose.yml
  • traefik.toml
  • acme.json

docker-compose.yml is for defining our container infrastructure and deployment parameters. We’ll also define labels on our containers which traefik looks for when it configures itself. The labels allow us to define how traefik routes network traffic to our containers.

traefik.toml is our base traefik configuration. We define what ports traefik listens on. We configure traefik to integrate with Docker. Traefik calls this integration with Docker a Provider, where Docker is a Provider to traefik to tell it of what services are available for it to act as a reverse proxy. Finally, we specify how to get free certificates through Let’s Encrypt.

acme.json initially be an empty file with specific Unix file permissions, but traefik uses this file to store the certificates it requests from Let’s Encrypt.

Let’s now make these three files, starting with the hard one.

Create docker-compose.yml

version: '3.7'

services:

  traefik:
    image: traefik:1.7.12
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.toml:/traefik.toml
      - ./acme.json:/acme.json

  adminer:
    image: adminer:latest
    restart: always
    expose:
      - "8080"
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:adminer.mysite.com"
      - "traefik.port=8080"
      - "traefik.protocol=http"
      - "traefik.frontend.whiteList.sourceRange=192.168.0.0/24"

We start by defining our traefik deployment. Here we’re using version 1.7.12; we tell it to listen on ports 80 and 443 and map them to the host with the ports key in our YAML. Finally, we map 3 volumes. The docker.sock volume is mapped so traefik can interface with Docker on our local system. We have to do this because we are running traefik inside of Docker. The other two volumes are to map the next files we’re going to create.

Below that, we define an adminer deployment. Adminer is a neat little database management utility I love to use, you can swap this out for any web service you want, but I’m using it for this example. We use the expose keyword to allow other containers to connect to these ports, but this will not map port 8080 to the host. Finally, we set some labels which configure traefik to accept traffic for adminer.mysite.com and forward it to the adminer container to port 8080 with HTTP. We also specify a whitelist for source IPs, if you omit this line it allows traffic from any destination.

Change the adminer container to match whatever container you want behind traefik. Also, change the line for traefik.frontend.rule=Host:adminer.mysite.com to whatever domain you want to use for your service.

Create traefik.toml

debug = false

logLevel = "ERROR"
defaultEntryPoints = ["https","http"]

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

[retry]

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "mysite.com"
watch = true
exposedByDefault = false

[acme]
email = "webmaster@mysite.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"

We configure some Entrypoints for traefik, which are the ways that network traffic can first get into traefik. We define a redirect to https for any HTTP traffic that comes in, and we tell traefik to use TLS for the https Entrypoint. Next, we configure traefik to use Docker as a Provider, and to watch for changes in Docker. Last, we define the acme configuration for Let’s Encrypt so that traefik can automatically obtain certificates.

Change and reference to mysite.com to match your domain. All services in docker-compose.yml should have their host rules under this domain.

Create acme.json

We make an empty file and apply the read/write permissions for our own user only. Traefik writes to this file, but it must have the correct permissions set otherwise traefik won’t use it.

touch acme.json
chmod 600 acme.json

Starting Things Up

To bring our services up, we run the following command:

# run this to start the containers, but do not attach to them.
docker-compose up -d

We should now be able to browse to https://adminer.mysite.com. We may get a certificate error the first time we visit the site, but give it about 30 seconds and refresh. After that, you should have a certificate. You can add in other containers with different labels and traefik will automatically proxy to them to, based on the host match rule label. It’s an easy to way to ensure HTTPS everywhere for all of your services.

If you need to troubleshoot anything, I recommend looking at the output of your containers by attaching to them when they start up

# run this to start the containers, then attach to them.
docker-compose up

Change https://adminer.mysite.com to whatever domain you set in docker-compose.yml