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
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 = "firstname.lastname@example.org" storage = "acme/certs.json" entryPoint = "https" onHostRule = true [acme.httpChallenge] 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 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.