Traefik Reverse Proxy for Docker Services: Practical Production Setup

When you run multiple Docker services on one host, port management quickly becomes messy. Traefik solves this by acting as a dynamic reverse proxy that discovers containers through labels and routes requests automatically.

This guide shows a production-friendly baseline with automatic TLS, clean routing, and a secure dashboard strategy.

Architecture Overview

A common setup includes:

  • One external entrypoint on ports 80/443
  • One internal Docker network shared by Traefik and apps
  • App-specific labels that define hostnames and middleware
  • ACME certificate resolver for automatic HTTPS

Traefik watches Docker events and updates routes without manual reloads.

1) Create the shared network

docker network create edge

Use this network for Traefik and all exposed application containers.

2) Deploy Traefik with Docker Compose

Example docker-compose.yml for Traefik:

services:
  traefik:
    image: traefik:v3.1
    container_name: traefik
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.email=admin@example.com
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      - --api.dashboard=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - edge

networks:
  edge:
    external: true

Create the ACME file with strict permissions:

mkdir -p letsencrypt
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.json

3) Route an app with labels

Example app service:

services:
  app:
    image: ghcr.io/example/myapp:latest
    restart: unless-stopped
    networks:
      - edge
    labels:
      - traefik.enable=true
      - traefik.http.routers.myapp.rule=Host(`app.example.com`)
      - traefik.http.routers.myapp.entrypoints=websecure
      - traefik.http.routers.myapp.tls.certresolver=letsencrypt
      - traefik.http.services.myapp.loadbalancer.server.port=8080

DNS for app.example.com must point to your server IP.

4) Secure operational endpoints

Avoid exposing dashboard endpoints unauthenticated. If you need dashboard access, protect it with middleware:

labels:
  - traefik.http.middlewares.admin-auth.basicauth.users=admin:$$apr1$$...
  - traefik.http.routers.traefik.rule=Host(`traefik.example.com`)
  - traefik.http.routers.traefik.service=api@internal
  - traefik.http.routers.traefik.entrypoints=websecure
  - traefik.http.routers.traefik.tls.certresolver=letsencrypt
  - traefik.http.routers.traefik.middlewares=admin-auth

5) Production Hardening Tips

  • Set exposedByDefault=false (already enabled above)
  • Keep Docker socket read-only
  • Use firewall rules to allow only required ports
  • Apply rate limiting middleware for public endpoints
  • Add header middleware (HSTS, frame protections, etc.)

Example secure headers middleware:

- traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.secure-headers.headers.browserXssFilter=true
- traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true

Then attach middleware to routers.

Verification Checklist

docker ps
docker logs traefik --tail=100
curl -I https://app.example.com

Expected results:

  • Valid certificate issued
  • HTTP/2 200 (or app expected status)
  • No certificate errors in browser

Summary

Traefik is a strong choice for Docker-first environments where services change frequently. With labels-driven routing and automatic TLS, you get a clean operational model and less manual reverse proxy maintenance.

The biggest reliability gains come from network segmentation, secure dashboard access, and explicit middleware policies per app.