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"
services:
app:
build: ./app # A node app
command: pm2-docker start server.js # Start server via pm2
ports:
- 3000
labels:
- "traefik.enable=true" # Enable reverse-proxy for this service
- "traefik.frontend.rule=Host:example.com" # Domain name for the app
reverse-proxy:
image: traefik
command: --api # Enables the web UI
- "80:80" # The HTTP port
- "443:443" # The HTTPS port
- "8080:8080" # The web UI
volumes:
- /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"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[docker]
exposedByDefault = false
[acme]
email = "admin@example.com"
storage = "acme/certs.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
Notice how we defined acme.storage
: 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 https://example.com. If you have issues, please check the Web UI output at https://example.com:8080 and make sure you run this setup on a server, not on your local machine.
This is because acme
in Traefik is letsencrypt.org 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 (example.com 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: