$docker.recipes
·15 min read·Updated September 2025

How to Use Traefik as a Reverse Proxy for Docker Services

A complete guide to setting up Traefik v3 with Docker Compose for automatic SSL, routing, and middleware — with practical examples for common services.

traefikreverse-proxyssldocker-compose

01Why Traefik Changed How I Deploy Services

Before Traefik, adding a new service to my home lab meant editing Nginx configuration files, reloading the web server, and manually setting up SSL certificates. It worked, but it was tedious and error-prone. One misplaced semicolon in an Nginx config could take down every service behind the proxy. Traefik changed everything. It automatically discovers Docker containers, routes traffic based on labels you add to your compose files, and handles SSL certificates from Let's Encrypt without any manual intervention. Adding a new service is as simple as adding three labels to your docker-compose.yml. I've been running Traefik in production for three years across personal projects and small business deployments. This guide covers the practical setup I use, including the gotchas that the official docs don't always make clear.

02How Traefik Works with Docker

Traefik has a concept of "providers" — sources of truth for routing configuration. The Docker provider watches the Docker socket for container events. When a container starts with Traefik labels, Traefik automatically creates a route for it. When the container stops, the route is removed. This means zero-downtime deployments work out of the box. Start the new container, Traefik picks it up, stop the old one, Traefik removes it. No configuration reloads needed. The key concepts are: - Entrypoints: The ports Traefik listens on (typically 80 and 443) - Routers: Rules that match incoming requests (usually by hostname) - Services: The backend containers that handle the requests - Middleware: Transformations applied to requests (authentication, redirects, rate limiting) All of these are configured via Docker labels on your service containers.

03Basic Traefik Setup

First, create a Docker network that Traefik and your services will share:
[terminal]
1# Create the shared network
2docker network create proxy
3
4# Create directory for Traefik
5mkdir -p ~/docker/traefik
6touch ~/docker/traefik/acme.json
7chmod 600 ~/docker/traefik/acme.json

04Traefik Docker Compose Configuration

Here's a production-ready Traefik configuration with automatic SSL:
[docker-compose.yml]
1# ~/docker/traefik/docker-compose.yml
2services:
3 traefik:
4 image: traefik:v3.1
5 container_name: traefik
6 restart: unless-stopped
7 ports:
8 - "80:80"
9 - "443:443"
10 volumes:
11 - /var/run/docker.sock:/var/run/docker.sock:ro
12 - ./acme.json:/acme.json
13 command:
14 - "--api.dashboard=true"
15 - "--providers.docker=true"
16 - "--providers.docker.exposedbydefault=false"
17 - "--entrypoints.web.address=:80"
18 - "--entrypoints.websecure.address=:443"
19 - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
20 - "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
21 - "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
22 - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
23 labels:
24 - "traefik.enable=true"
25 - "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
26 - "traefik.http.routers.dashboard.service=api@internal"
27 - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
28 networks:
29 - proxy
30
31networks:
32 proxy:
33 external: true

The Docker socket gives Traefik full access to your Docker daemon. In high-security environments, use a Docker socket proxy like tecnativa/docker-socket-proxy to limit access.

05Adding Services Behind Traefik

Once Traefik is running, expose any service by adding labels to its compose file. Here's Nextcloud as an example:
[docker-compose.yml]
1# ~/docker/nextcloud/docker-compose.yml
2services:
3 nextcloud:
4 image: nextcloud:29
5 container_name: nextcloud
6 restart: unless-stopped
7 volumes:
8 - nextcloud_data:/var/www/html
9 labels:
10 - "traefik.enable=true"
11 - "traefik.http.routers.nextcloud.rule=Host(`cloud.yourdomain.com`)"
12 - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
13 - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
14 networks:
15 - proxy
16 - internal
17
18 db:
19 image: postgres:16-alpine
20 networks:
21 - internal # Database NOT on proxy network
22
23volumes:
24 nextcloud_data:
25
26networks:
27 proxy:
28 external: true
29 internal:

Set exposedbydefault=false in Traefik config and explicitly enable services with traefik.enable=true. This prevents accidentally exposing internal services.

06Useful Middleware

Traefik middleware lets you add authentication, rate limiting, and security headers to any service. Here are the ones I use most: Basic authentication for admin panels — don't expose dashboards without auth. Generate a password hash with: echo $(htpasswd -nB user) | sed -e s/\$/\$\$/g Security headers that improve your score on securityheaders.com and protect against common web attacks. Rate limiting to prevent brute-force attacks on login pages. All middleware is configured via Docker labels, keeping everything in your compose files. Browse our web-servers category for complete Traefik configurations with various middleware combinations.

About the Author

Frank Pegasus

DevOps engineer and self-hosting enthusiast with over a decade of experience running containerized workloads in production. Creator of docker.recipes.