← Back to DevBytes

Traefik Proxy: Complete Setup and Configuration Guide

Introduction to Traefik Proxy

Traefik is an open-source, cloud-native reverse proxy and load balancer designed to make deploying microservices easy and dynamic. Unlike traditional proxies that require manual reloads when configuration changes, Traefik automatically discovers services and updates its routing in real time. It integrates natively with orchestrators like Docker, Kubernetes, Swarm, and others, listening for changes and adjusting traffic routing without downtime.

Originally created by Containous (now Traefik Labs), Traefik has become one of the most popular ingress solutions in the container ecosystem. Its appeal lies in simplicity: you declare what you want, and Traefik figures out how to route traffic to it.

Why Traefik Matters

Traditional reverse proxies like Nginx or Apache HTTP Server were built for static infrastructure. When a new service spins up or scales out, you typically need to regenerate configuration files and reload the proxy. In dynamic, containerized environments where services appear and disappear constantly, this model becomes painful.

Traefik solves this by treating configuration as a living thing. It watches your orchestrator's API, detects new containers, and automatically creates routes. This means:

Core Concepts

Before diving into configuration, it's important to understand Traefik's mental model. Traefik uses several key abstractions:

Providers

A provider is any system that tells Traefik what services exist. Docker, Kubernetes, Consul, and even static YAML files are all providers. Each provider exposes configuration that Traefik consumes to build its routing table.

Entrypoints

Entrypoints are the network ports Traefik listens on. For example, you might define an entrypoint on port 80 for HTTP traffic and another on port 443 for HTTPS. All incoming traffic enters through these ports.

Routers

A router inspects incoming requests and matches them against rules. Rules can match on hostnames, paths, headers, and more. When a request matches a rule, the router forwards it to a service.

Services

A service represents the actual backend that handles the request. It defines how to reach your application, including load balancing strategy across multiple instances.

Middlewares

Middlewares sit between routers and services, modifying requests or responses. They handle concerns like authentication, rate limiting, compression, retries, and header manipulation. Middlewares can be chained together for complex processing pipelines.

Installing Traefik

The most common way to run Traefik is as a Docker container. This keeps it isolated and easy to manage. Let's start with a basic setup using Docker Compose.

Basic Docker Compose Setup

Create a file named docker-compose.yml with the following content:

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

networks:
  proxy:
    external: false

Let's break down what's happening here:

Start Traefik with:

docker compose up -d

You can now visit http://localhost:8080 to see the Traefik dashboard. It will be empty because no services are registered yet.

Routing Your First Service

Let's add a simple web application and route traffic to it. We'll use the popular whoami image, which returns information about the incoming request.

Update your docker-compose.yml to include the whoami service:

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=web"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"
    networks:
      - proxy

networks:
  proxy:
    external: false

Restart the stack:

docker compose up -d

Now test the routing:

curl -H "Host: whoami.localhost" http://localhost

You should see a JSON response containing details about your request, including the hostname, remote address, and headers. Traefik successfully routed the request based on the Host header.

Understanding the Labels

The labels on the whoami service are how Docker provider configuration works. Let's examine each one:

Adding TLS with Let's Encrypt

One of Traefik's standout features is automatic HTTPS via Let's Encrypt. Let's extend our setup to support TLS certificates.

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - proxy

  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"
    networks:
      - proxy

networks:
  proxy:
    external: false

Key additions in this configuration:

Replace you@example.com with your real email address and whoami.example.com with a domain that points to your server. Traefik will automatically obtain and renew certificates.

Using Middlewares

Middlewares are where Traefik gets powerful. Let's explore several common middleware patterns.

Rate Limiting

To protect your services from abuse, you can limit the number of requests per unit of time:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.api.rule=Host(`api.example.com`)"
  - "traefik.http.routers.api.entrypoints=websecure"
  - "traefik.http.routers.api.tls.certresolver=letsencrypt"
  - "traefik.http.routers.api.middlewares=rate-limit"
  - "traefik.http.middlewares.rate-limit.ratelimit.average=100"
  - "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
  - "traefik.http.services.api.loadbalancer.server.port=8080"

This limits the service to an average of 100 requests per second with a burst capacity of 50.

Basic Authentication

You can add HTTP basic authentication to protect sensitive endpoints:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.dashboard.rule=Host(`dashboard.example.com`)"
  - "traefik.http.routers.dashboard.entrypoints=websecure"
  - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
  - "traefik.http.routers.dashboard.middlewares=auth"
  - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz123$$AbCdEfGhIjKlMnOpQrStU"

Generate the password hash using the htpasswd utility:

htpasswd -nb admin "your-secret-password"

Note that dollar signs in the hash must be doubled in Docker Compose files to avoid variable interpolation.

Chaining Multiple Middlewares

You can apply multiple middlewares by listing them comma-separated:

labels:
  - "traefik.http.routers.app.middlewares=rate-limit,auth,compress"
  - "traefik.http.middlewares.rate-limit.ratelimit.average=100"
  - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz123$$hashvalue"
  - "traefik.http.middlewares.compress.compress=true"

Requests will pass through rate limiting, then authentication, then compression, in that order.

Path-Based Routing

Sometimes you want to route different paths to different services under the same domain. Traefik supports this with path rules:

services:
  frontend:
    image: my-frontend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`app.example.com`) && PathPrefix(`/`)"
      - "traefik.http.routers.frontend.entrypoints=websecure"
      - "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
      - "traefik.http.services.frontend.loadbalancer.server.port=80"

  api:
    image: my-api
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`app.example.com`) && PathPrefix(`/api`)"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      - "traefik.http.services.api.loadbalancer.server.port=3000"

Traefik evaluates routers in order of rule specificity. More specific rules should be defined to ensure correct matching. You can also assign priorities explicitly:

- "traefik.http.routers.api.priority=100"
- "traefik.http.routers.frontend.priority=1"

File-Based Configuration

While Docker labels are convenient, sometimes you need more control. Traefik supports a file provider for static configuration. This is useful for defining complex routers, middlewares, and services in a structured way.

Create a directory structure:

mkdir -p /etc/traefik/dynamic

Add a file /etc/traefik/dynamic/dynamic.yml:

http:
  routers:
    my-router:
      rule: "Host(`example.com`)"
      entrypoints:
        - websecure
      service: my-service
      tls:
        certResolver: letsencrypt
      middlewares:
        - rate-limit

  middlewares:
    rate-limit:
      rateLimit:
        average: 100
        burst: 50

  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://10.0.0.10:8080"
          - url: "http://10.0.0.11:8080"

Enable the file provider in your Traefik configuration:

command:
  - "--providers.file.directory=/etc/traefik/dynamic"
  - "--providers.file.watch=true"

With watch=true, Traefik automatically reloads when files change, giving you dynamic configuration without restarts.

Load Balancing Strategies

Traefik provides several load balancing algorithms to distribute traffic across service instances.

Round Robin (Default)

By default, Traefik uses weighted round robin. This distributes requests evenly across all servers:

http:
  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://server1:8080"
          - url: "http://server2:8080"

Weighted Load Balancing

You can assign weights to control traffic distribution:

http:
  services:
    my-service:
      weighted:
        services:
          - name: primary
            weight: 9
          - name: canary
            weight: 1

This sends 90% of traffic to the primary service and 10% to a canary deployment, useful for gradual rollouts.

Sticky Sessions

For applications that require session affinity, enable sticky sessions:

http:
  services:
    my-service:
      loadBalancer:
        sticky:
          cookie:
            name: session_cookie
            secure: true
            httpOnly: true
        servers:
          - url: "http://server1:8080"
          - url: "http://server2:8080"

Traefik sets a cookie on the first response, and subsequent requests with that cookie are routed to the same server.

Health Checks

Traefik can actively check the health of your backends and stop sending traffic to unhealthy instances:

http:
  services:
    my-service:
      loadBalancer:
        healthCheck:
          path: /health
          interval: 10s
          timeout: 3s
        servers:
          - url: "http://server1:8080"
          - url: "http://server2:8080"

If a server fails the health check, Traefik removes it from the rotation until it recovers.

Observability

Production systems need visibility. Traefik integrates with popular observability tools.

Access Logs

Enable access logs to record every request:

command:
  - "--accesslog=true"
  - "--accesslog.filepath=/var/log/traefik/access.log"
  - "--accesslog.format=json"

Metrics with Prometheus

Expose metrics for Prometheus to scrape:

command:
  - "--metrics.prometheus=true"
  - "--metrics.prometheus.entrypoint=metrics"
  - "--entrypoints.metrics.address=:8082"

Configure Prometheus to scrape http://your-traefik-host:8082/metrics.

Dashboard Security

In production, never expose the dashboard without authentication. Secure it properly:

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

The api@internal service is a special built-in service that serves the dashboard.

Best Practices

Security

Performance

Configuration Management

High Availability

For production deployments, run multiple Traefik instances behind a load balancer. If using Let's Encrypt, configure a shared storage backend (like Consul or Redis) so only one instance performs the ACME challenge at a time:

command:
  - "--certificatesresolvers.letsencrypt.acme.storage=/acme/acme.json"
  - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"

Mount the same shared storage across all Traefik instances, or use the Consul provider for distributed locking.

TCP and UDP Routing

Traefik isn't limited to HTTP. It can also route TCP and UDP traffic, making it suitable for databases, message queues, and other non-HTTP services.

TCP Routing Example

tcp:
  routers:
    mysql-router:
      entrypoints:
        - mysql
      rule: "HostSNI(`*`)"
      service: mysql-service

  services:
    mysql-service:
      loadBalancer:
        servers:
          - address: "10.0.0.20:3306"

Define the entrypoint in your static configuration:

command:
  - "--entrypoints.mysql.address=:3306"

UDP Routing Example

udp:
  routers:
    dns-router:
      entrypoints:
        - dns
      service: dns-service

  services:
    dns-service:
      loadBalancer:
        servers:
          - address: "10.0.0.30:53"

Conclusion

Traefik has established itself as a first-class reverse proxy for modern, dynamic infrastructure. Its ability to automatically discover services, provision TLS certificates, and adapt to changing environments without reloads makes it an excellent choice for containerized applications. By understanding the core concepts of providers, entrypoints, routers, services, and middlewares, you can build robust routing configurations that scale with your needs. Whether you're running a simple homelab or a large production deployment, Traefik's combination of simplicity, flexibility, and powerful features makes it a compelling alternative to traditional reverse proxies. Start with the basic Docker Compose setup, add TLS and middlewares as needed, and follow the best practices outlined above to build a secure and observable proxy layer for your applications.

— Ad —

Google AdSense will appear here after approval

← Back to all articles