I run most of my services in Docker and previously I was using nginx as a reverse and TLS termination proxy together with Let's Encrypt. That worked great but everytime I wanted to try something new I had to copy-paste another conf and change a few values. I probably could have automated that to some extent and there are others who have but with my recent migration to VPSes I figured I'd give Traefik a try, if nothing else for their awesome logo!

Here I'll show you how to set up Traefik with GUI, http redirection and automatic Let's Encrypt certificates. We'll also add basic auth to the Traefik GUI.

⚠️ Update ⚠️

There's a vulnerability in old versions of Traefik so I've updated this post with a safe version. It should work just the same but the GUI will look different from the image below.

Prerequisites

This guide assumes some general knowledge of Linux and that you have a server available with these services installed:

For cheap and good servers, checkout DigitalOcean or Hetzner. Also I always recommend this guide when setting up a new VPS.

Setup

This is based on the official guide but with a few additions.

First start with creating a network for your web-facing containers to connect to.

docker network create web

Then we create a directory and the necessary files, as sudo if needed.

sudo su
mkdir -p /opt/traefik
touch /opt/traefik/docker-compose.yml
touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.json
touch /opt/traefik/traefik.toml

Now let's add our docker-compose...

nano /opt/traefik/docker-compose.yml
version: '2'

services:
  proxy:
    # Always use a proper version! (edited)
    image: traefik:v1.6.6-alpine
    # Feel free to change the loglevel if needed
    command: --web --docker --logLevel=INFO
    restart: unless-stopped
    # Here's the network we created
    networks:
      - web
    # The traefik entryPoints
    ports:
      - "80:80"
      - "443:443"
    labels:
      # Make sure this domain points to your IP so that traefik can request a cert
      - "traefik.frontend.rule=Host:traefik.example.com"
      # Traefik will proxy to its own GUI
      - "traefik.port=8080" 
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/traefik/traefik.toml:/traefik.toml
      - /opt/traefik/acme.json:/acme.json
networks:
  web:
    external: true

☝️ Remember to replace example.com in traefik.frontend.rule.

... and the config for Traefik...

nano /opt/traefik/traefik.toml
debug = false

defaultEntryPoints = ["https","http"]

# The syntax is somewhat esoteric IMHO so this is mostly copy-paste
[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 = "traefik.example.com"
watch = true
exposedbydefault = false

[acme]
email = "youremail@example.com"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true
[acme.httpChallenge]
entryPoint = "http"

# Enable web configuration backend
[web]

# Web administration port, proxied in docker-compose.yml
address = ":8080"

☝️ Add your domain and email under [docker] and [acme], respectively.

... and we should be good to go!

docker-compose up -d

Check the logs (docker-compose logs) and head to your configured domain and you should see something like this.

Screen-Shot-2018-03-13-at-22.19.45

Since we're gonna expose the GUI of Traefik we'd like to have some authentication. Basic auth is supported so let's add that. Run this for the username you want - for example admin - and enter your password.

htpasswd -n username

Here's what I got for admin/admin.

admin:$apr1$IBj9Hfsd$kf7vXLpY4/9XD365jcp/n1

Now that needs to go in the docker-compose.yaml but to work any $ signs have to be escaped with another $.
Add this to the labels-section.

- "traefik.frontend.auth.basic=admin:$$apr1$$IBj9Hfsd$$kf7vXLpY4/9XD365jcp/n1"

Now stop and rebuild your service...

docker-compose stop
docker-compose up -d

...and you should have basic auth!

Screen-Shot-2018-03-13-at-22.30.58

Add a container

Now of course to have any use for this we need a container! Why not a blog with ghost?

Create a directory and a docker-compose.yml, remember to change the domain and add the hostname to your DNS! 👍

mkdir -p /opt/ghost
nano /opt/ghost/docker-compose.yml
version: '2'
services:
  server:
    image: ghost:alpine
    container_name: ghost
    restart: unless-stopped
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:blog.example.com"
      - "traefik.port=2368"
      - "traefik.docker.network=web"
    volumes:
      - /opt/ghost/blog:/var/lib/ghost/content
    environment:
      - NODE_ENV=production
      - url=https://blog.example.com

networks:
  web:
    external: true

Run the usual docker-compose up -d and voilà blog up with SSL/TLS and all, pure magic 😀