Docker compose and Traefik example configuration (domain name + SSL certificate)

Jan 24, 2019 · by Tim Kamanin

Traefik is a great reverse-proxy for Docker, but it can take some time to set it up correctly.

Here I'm posting a reference config that adds a domain name, a certificate generated by letsencrypt and directs all incoming traffic to a container of choice.

Before we begin let's prepare the following directory structure:

- app # this where our app lives
- traefik # directory to hold traefik config
- volumes # here we store our local mounts

At first, we create a docker-compose.yml file:

version: "3"

    build: ./app # A node app
    command: pm2-docker start server.js # Start server via pm2
      - 3000
      - "traefik.enable=true" # Enable reverse-proxy for this service
      - "" # Domain name for the app

    image: traefik
    command: --api # Enables the web UI
      - "80:80" # The HTTP port
      - "443:443" # The HTTPS port
      - "8080:8080" # The web UI
      - /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
      - ./traefik/traefik.toml:/traefik.toml # Traefik configuration file
      - ./volumes/traefik-acme:/acme # Tell Traefik to save SSL certs here

The app service is not essential here; it can be any Docker service, the primary requirement it should fulfill is to have labels defined as in the example.

Note how we mapped ./volumes/traefik-acme:/acme volumes. In official Traefik document the suggested mapping is something like ./volumes/acme.json:/acme.json. But if we map a file to a file instead of a directory to a directory we'll get a nasty error Failed to read new account, ACME data conversion is not available : read acme.json: is a directory. Btw, thanks to this error I'm writing this post.

Now let's add a traefik/traefik.toml file with the following contents:

debug = false

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

  address = ":80"
    entryPoint = "https"
  address = ":443"


exposedByDefault = false

email = ""
storage = "acme/certs.json"
entryPoint = "https"
onHostRule = true
entryPoint = "http"

Notice how we defined acme/certs.json, this is to prevent the acme.json mapping issue I've described earlier.

Now you can go and run docker-compose up on your server, and if everything is done right, you should be able to access your service via If you have issues, please check the Web UI output at and make sure you run this setup on a server, not on your local machine.

This is because acme in Traefik is and to generate a certificate for you, it needs to make a callback to your server and access Traefik reverse-proxy via the domain name that you've defined ( in our case).

Hope this all works for you... or for future me.

Hey, if you've found this useful, please share the post to help other folks find it:

There's even more:

Subscribe for updates

  • via Twitter: @timonweb
  • old school RSS:
  • or evergreen email ↓ ↓ ↓