Configuring Traefik Reverse Proxy for Container Deployments

Configuring Traefik Reverse Proxy for Container Deployments

What You’ll Need

  • A cloud server like a Hetzner VPS or DigitalOcean running Ubuntu 24.04 LTS
  • A registered domain name managed via Namecheap or your preferred DNS provider
  • Docker Engine and Docker Compose installed on your host machine
  • An orchestration or workflow tool like n8n Cloud or self-hosted container applications ready for deployment

Table of Contents

Setting Up Docker and Traefik Static Configuration

When I manage multi-container environments, relying on legacy web servers like Nginx or Apache often creates configuration friction. Standard reverse proxies require you to manually write site configs, expose internal ports, reload daemon processes, and explicitly execute Certbot scripts every time a new container spins up.

Traefik changes this model entirely. It acts as an edge router that listens directly to your container engine socket. As soon as you deploy a Docker container with specific labels attached, Traefik detects the event, generates SSL certificates through Let’s Encrypt, configures dynamic routing rules, and attaches middleware automatically without dropping a single active HTTP connection.

To get started with Traefik v3, I divide configuration into two distinct categories: static configuration and dynamic configuration. Static configuration defines entry points, backend logging level, provider integrations, and ACME challenge mechanisms. This is loaded when Traefik boots up. Dynamic configuration defines the actual routes, services, tls settings, and middleware pipeline attached to your containers, which Traefik updates in real time based on active runtime states.

First, spin up your server instance on a high-performance host like a Hetzner VPS. Ensure your domain DNS A records hosted on Namecheap point directly to your public server IP address.

Log into your server via SSH and build a isolated system directory structure for your Traefik core platform stack:

mkdir -p /opt/traefik/config
cd /opt/traefik
touch config/dynamic.yml
touch acme.json
chmod 600 acme.json

The acme.json file stores retrieved SSL/TLS certificates generated by Let’s Encrypt. Strict file permissions (600) are mandatory; Traefik will refuse to start if this file is globally readable.

Next, create the main static configuration file /opt/traefik/config/traefik.yml using your preferred text editor:

global:
  checkNewVersion: false
  sendAnonymousUsage: false

log:
  level: INFO
  format: json

accessLog:
  format: json
  filters:
    statusCodes:
      - "200-299"
      - "400-599"

api:
  dashboard: true
  insecure: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    watch: true
  file:
    filename: "/etc/traefik/config/dynamic.yml"
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: "admin@example.com"
      storage: "/acme.json"
      httpChallenge:
        entryPoint: web

Now, create the primary orchestration stack file /opt/traefik/docker-compose.yml. This runs Traefik inside its own isolated Docker container while binding ports 80 and 443 to your public network interface:

services:
  traefik:
    image: traefik:v3.1
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    ports:
      - "80:80"
      - "443:443"
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/traefik/config/traefik.yml:/etc/traefik/traefik.yml:ro
      - /opt/traefik/config/dynamic.yml:/etc/traefik/config/dynamic.yml:ro
      - /opt/traefik/acme.json:/acme.json
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$q8312z1x$$Y3O4V902S9.qL9W.aP2n10"

networks:
  proxy:
    external: true

Create the required bridge network before launching the deployment stack:

docker network create proxy
docker compose up -d

💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.

Dynamic Routing for Container Microservices

With Traefik active on the external proxy network, you can launch application microservices without ever editing static files or restarting web servers again. Traefik inspects metadata declared inside container labels to dynamically map incoming hostnames to backend container endpoints.

When I run complex backend systems, I frequently rely on distinct service layers. For instance, when building distributed Python task schedulers with Dramatiq, having a robust reverse proxy routing client requests directly to async API instances while isolating task broker stores (like Redis or RabbitMQ) from the public internet is essential.

Let’s look at a multi-service docker-compose.yml file illustrating how to expose an API task manager alongside an internal web UI while keeping internal worker stores hidden:

services:
  task-api:
    image: python:3.11-slim
    container_name: task-api
    restart: always
    command: uvicorn main:app --host 0.0.0.0 --port 8000
    environment:
      - REDIS_URL=redis://redis-backend:6379/0
    networks:
      - proxy
      - internal-mesh
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.taskapi.rule=Host(`api.example.com`)"
      - "traefik.http.routers.taskapi.entrypoints=websecure"
      - "traefik.http.routers.taskapi.tls.certresolver=letsencrypt"
      - "traefik.http.services.taskapi.loadbalancer.server.port=8000"

  redis-backend:
    image: redis:7-alpine
    container_name: redis-backend
    restart: always
    networks:
      - internal-mesh
    labels:
      - "traefik.enable=false"

networks:
  proxy:
    external: true
  internal-mesh:
    driver: bridge

Notice how redis-backend only exists on internal-mesh and sets traefik.enable=false. It is entirely inaccessible from the outside world. Traefik routes incoming public traffic meant for api.example.com directly to port 8000 on task-api over the shared proxy network.

Similarly, if you are deploying Appsmith on budget Hetzner Cloud VPS, putting your low-code apps and operational dashboards behind Traefik guarantees automated SSL certificate generation, domain routing, and seamless load balancing without managing raw server blocks.

Here is a full manifest showing how to attach an Appsmith web interface to Traefik using custom dynamic router parameters:

services:
  appsmith:
    image: appsmith/appsmith-ce:latest
    container_name: appsmith-ui
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      - APPSMITH_SERVER_PORT=8080
    networks:
      - proxy
    volumes:
      - /opt/appsmith/stacks:/appsmith-stacks
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.appsmith.rule=Host(`dashboard.example.com`)"
      - "traefik.http.routers.appsmith.entrypoints=websecure"
      - "traefik.http.routers.appsmith.tls.certresolver=letsencrypt"
      - "traefik.http.services.appsmith.loadbalancer.server.port=8080"
      - "traefik.http.routers.appsmith.middlewares=sec-headers@file"

networks:
  proxy:
    external: true

By leveraging traefik.http.services.<service_name>.loadbalancer.server.port, you explicitly inform Traefik which port to target inside the container network payload, eliminating ambiguity when containers expose multiple standard ports (like 80, 443, and 8080 simultaneously).

Advanced Middleware: Rate Limiting, TLS, and Webhook Retries

Middlewares allow you to transform requests before they hit your backend services. You can chain multiple middleware modules together to handle security, compression, rate-limiting, and error handling at the proxy layer instead of clogging your application runtime code.

I maintain critical middleware patterns inside Traefik’s dynamic file provider (/opt/traefik/config/dynamic.yml). This decoupled design lets me update system-wide global policies without editing container deployment files.

Edit /opt/traefik/config/dynamic.yml and add the following complete configuration:

http:
  middlewares:
    sec-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        customFrameOptionsValue: "SAMEORIGIN"

    api-rate-limit:
      rateLimit:
        average: 100
        burst: 50
        period: 1s

    backend-retry:
      retry:
        attempts: 4
        initialInterval: 100ms

    webhook-auth:
      basicAuth:
        users:
          - "webhookuser:$apr1$c91p8x0a$4P3nK92lS81j.qL9W.aP2n"

  tls:
    options:
      default:
        minVersion: "VersionTLS12"
        cipherSuites:
          - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
          - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
          - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
          - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
          - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
          - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"

The backend-retry middleware is an essential piece of network resilience infrastructure. If a target application container is temporarily unresponsive during a rolling update, Traefik automatically resends the HTTP request up to four times using an incremental delay before returning a 502 Bad Gateway response to the end user.

While network-level retries in Traefik help salvage transient HTTP 502 or 503 errors during container lifecycle events, high-volume transactional integrations require comprehensive error strategies. I recommend pairing Traefik retry policies with handling webhook retries using exponential backoff strategies inside your application code to handle persistent multi-minute service outages safely.

To apply dynamic middlewares to any container, simply reference the middleware name in your container labels:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.webhook-service.rule=Host(`hooks.example.com`)"
  - "traefik.http.routers.webhook-service.entrypoints=websecure"
  - "traefik.http.routers.webhook-service.tls.certresolver=letsencrypt"
  - "traefik.http.routers.webhook-service.middlewares=sec-headers@file,api-rate-limit@file,backend-retry@file"
  - "traefik.http.services.webhook-service.loadbalancer.server.port=5000"

The suffix @file explicitly tells Traefik to look for those middleware definitions in the dynamic configuration file rather than inspecting the container’s Docker labels. You can chain comma-separated middlewares sequentially; Traefik executes them in the exact order specified from left to right.

Getting Started

Building an automated, resilient, and secure container infrastructure starts with selecting robust host infrastructure and reliable routing components. You can deploy this entire Traefik stack in under ten minutes by provisioning a cloud server on Hetzner VPS or DigitalOcean, mapping your custom domains via Namecheap, and orchestrating automated workflow applications like n8n Cloud right behind your proxy.

Outsource Your Automation

Don’t have time? I build production n8n workflows, WhatsApp bots, and fully automated YouTube Shorts pipelines. Hire me on Fiverr, mention SYS3-HUGO for priority. Or DM at chasebot.online.

Want to automate this yourself?

Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.

Want this engine running on your own VPS?

This blog publishes itself — daily, unattended, on free API tiers. The full engine, Hugo theme, and setup guide are available as System 3.

Get System 3
system online