Traefik reverse proxy for Docker
When I needed a reverse proxy to publicly expose a couple of web applications running in Docker, I decided to use Traefik after doing a short research. Now that I successfully configured it, I don't regret the choice. Even without any previous experience, the whole process was much simpler than I expected.
This post is a short getting-started guide for configuring the Traefik itself and for exposing a new Docker container through it. It's something I failed to find while setting up my instance. I plan to use it myself the next time I'll have to expose a new service. Feel free to do the same, but keep in mind that I'm still pretty much a Traefik beginner and the described steps aren't necessarily the recommended best practice.
Of course, I decided to host Traefik in Docker, too, using the official Docker image and a fixed version, as recommended. I used Docker compose to configure it:
image: traefik:v3.3
I set its configuration settings through command line arguments:
- I enabled insecure API to make the dashboard work without authentication on insecure connection:
command: - --api.insecure=true
- I chose the Docker provider for routing configuration. This allowed me to configure routing for Docker containers using labels. I wanted to explicitly select the containers to be exposed:
command: - --providers.docker=true - --providers.docker.exposedByDefault=false
- I configured both HTTP and HTTPS endpoints, and established automatic redirect from HTTP to HTTPS:
command: - --entryPoints.http.address=:80 - --entryPoints.https.address=:443 - --entryPoints.http.http.redirections.entryPoint.to=https - --entryPoints.http.http.redirections.entryPoint.scheme=https
I configured automatic Let's Encrypt certificate generation with TLS challenge. I put my email in the
.env
so that I could safely commit thedocker-compose.yml
without it. And explicitly set the storage file so that I could map it to a volume.command: - --certificatesResolvers.letsEncrypt.acme.storage=/etc/traefik/acme/acme.json - --certificatesResolvers.letsEncrypt.acme.email=${LETSENCRYPT_EMAIL} - --certificatesResolvers.letsEncrypt.acme.tlsChallenge=true
Based on the configuration so far, I had to map and make publicly available the HTTP and HTTPS ports, and also mapped the 8080 port with the dashboard for my internal use only.
ports:
- "80:80"
- "443:443"
- "8080:8080"
In addition to the already mentioned Let's encrypt storage file, Traefik in Docker mode also requires access to the Docker API, so I mapped the Docker socket:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./volumes/traefik/letsencrypt:/etc/traefik/acme
With all that in place, the Traefik container was configured. From here on, I can expose individual containers over HTTPS using labels only:
- I need to explicitly enable Traefik routing first. This will expose the lowest mapped port of the container:
labels: - traefik.enable=true
- All router settings include a unique router name,
myservice
in this example:- I expose the service on a unique host name (read from the
.env
file). Of course, it needs to be entered in the DNS server, as well:labels: - traefik.http.routers.myservice.rule=Host(`${MYSERVICE_DOMAIN}`)
- I make it available via HTTPS using the Let's Encrypt certificate resolver configured in Traefik:
labels: - traefik.http.routers.myservice.tls=true - traefik.http.routers.myservice.tls.certResolver=letsEncrypt
- I assign a set of middlewares by their unique name. Their configuration follows below:
labels: - traefik.http.routers.myservice.middlewares=myservice-compress,myservice-headers
- I expose the service on a unique host name (read from the
- Similar to the router settings, each middleware has its settings grouped by its own unique name, for example:
- Compress middleware being enabled:
labels: - traefik.http.middlewares.myservice-compress.compress=true
- Headers middleware with some headers set:
labels: - traefik.http.middlewares.myservice-headers.headers.forceSTSHeader=true - traefik.http.middlewares.myservice-headers.headers.referrerPolicy=no-referrer-when-downgrade
- Compress middleware being enabled:
That's enough to make the service publicly exposed. Once its container starts, Traefik will automatically obtain a Let's Encrypt certificate for its domain and expose it over HTTPS. And it will take care of certificate renewal as well. I don't think it can get much simpler than this.
Traefik was a really pleasant surprise. It had a somewhat steep learning curve at the beginning. But once I grasped the basics, I was able to efficiently find my way around its documentation, and configure the services to my liking. It's been running without any issues for a while now, and I hope it continues to for much longer.