If you’re running multiple self-hosted services on Docker, managing access to each one can quickly become a mess. Different ports, manual SSL certificate management, and complex nginx configurations are enough to make anyone want to give up. That’s where Traefik comes in—a modern, Docker-native reverse proxy that automatically discovers your services and handles SSL certificates without you lifting a finger.

💡 This article contains affiliate links. If you buy through them, we earn a small commission at no extra cost to you. Learn more.

Traefik v3, released in 2024, brings significant improvements over v2, including better performance, enhanced middleware options, and improved configuration syntax. In this complete guide, you’ll learn how to set up Traefik v3 from scratch, configure automatic SSL certificates with Let’s Encrypt, and connect your Docker services—all without touching a single nginx config file.

What Is Traefik and Why Use It?

Traefik is an open-source reverse proxy and load balancer designed specifically for modern containerized environments. Unlike traditional reverse proxies like nginx or Apache, Traefik automatically detects when you add or remove Docker containers and updates its routing configuration in real-time.

Key benefits of Traefik:

  • Automatic service discovery: Add a few Docker labels, and Traefik automatically routes traffic to your containers
  • Built-in Let’s Encrypt integration: Automatic SSL certificate provisioning and renewal
  • Dynamic configuration: No need to restart or reload when adding new services
  • Dashboard: Web UI to monitor your routes, services, and middleware
  • Docker-native: First-class support for Docker, Kubernetes, and other orchestrators
  • Middleware support: Built-in authentication, rate limiting, compression, and more

For self-hosters running 5, 10, or 50+ services on Docker, Traefik eliminates the tedious manual work of maintaining reverse proxy configurations.

Prerequisites

Before you begin, you’ll need:

  • A Linux server running Docker and Docker Compose (Ubuntu, Debian, or similar)
  • A domain name with DNS pointed to your server’s public IP
  • Root or sudo access to your server
  • Basic understanding of Docker and Docker Compose

If you’re running a homelab on a mini PC or a dedicated server, you’re all set. Make sure Docker and Docker Compose are installed:

1
2
docker --version
docker compose version

If not installed, follow the official Docker installation guide for your distribution.

Project Structure

We’ll organize our Traefik setup in a dedicated directory:

1
2
mkdir -p ~/traefik
cd ~/traefik

Create the following structure:

~/traefik/
├── docker-compose.yml
├── traefik.yml
├── config/
│   └── dynamic.yml
└── acme.json

This keeps everything organized and makes it easy to manage your reverse proxy separately from your services.

Step 1: Create the Traefik Configuration File

Traefik v3 uses a static configuration file (traefik.yml) for core settings and dynamic configuration for routes and services.

Create traefik.yml:

1
nano traefik.yml

Add the following configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# traefik.yml

# API and Dashboard
api:
  dashboard: true
  insecure: false  # Disable insecure dashboard access

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

# Certificate Resolvers
certificatesResolvers:
  letsencrypt:
    acme:
      email: your-email@example.com  # Change this!
      storage: /acme.json
      httpChallenge:
        entryPoint: web

# Providers
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false  # Only expose containers with traefik.enable=true
    network: traefik-public  # Use this Docker network
  file:
    filename: /config/dynamic.yml
    watch: true

# Logging
log:
  level: INFO

# Access Logs (optional)
accessLog:
  filePath: /var/log/traefik/access.log

Key configuration points:

  • entryPoints: Port 80 (web) redirects to 443 (websecure)
  • certificatesResolvers: Let’s Encrypt HTTP challenge for automatic SSL
  • providers.docker: Traefik monitors Docker containers on the traefik-public network
  • exposedByDefault: false: Services must explicitly opt-in with traefik.enable=true

Important: Replace your-email@example.com with your actual email for Let’s Encrypt notifications.

Step 2: Create the Dynamic Configuration File

Dynamic configurations handle dashboard access and custom middleware.

Create the directory and file:

1
2
mkdir -p config
nano config/dynamic.yml

Add:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# config/dynamic.yml

http:
  routers:
    traefik-dashboard:
      rule: "Host(`traefik.yourdomain.com`)"  # Change this!
      service: api@internal
      middlewares:
        - auth
      tls:
        certResolver: letsencrypt

  middlewares:
    auth:
      basicAuth:
        users:
          - "admin:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"  # admin:password (CHANGE THIS!)

Change these:

  • Replace traefik.yourdomain.com with your actual subdomain
  • Replace the basicAuth user with your own credentials

To generate a secure password hash:

1
2
sudo apt install apache2-utils -y
htpasswd -nb admin yourpassword

Copy the output and paste it into the users section. Make sure to escape any $ characters by doubling them ($$).

Step 3: Prepare the acme.json File

Let’s Encrypt stores certificates in acme.json. Create it with proper permissions:

1
2
touch acme.json
chmod 600 acme.json

Traefik requires this file to be readable only by the owner (mode 600).

Step 4: Create the Docker Compose File

Now create the Docker Compose file for Traefik:

1
nano docker-compose.yml

Add:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik-public
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./config:/config:ro
      - ./acme.json:/acme.json
      - traefik-logs:/var/log/traefik
    labels:
      - "traefik.enable=true"

volumes:
  traefik-logs:

networks:
  traefik-public:
    external: true

Key points:

  • Mounts Docker socket (read-only) for container discovery
  • Exposes ports 80 and 443
  • Uses the external traefik-public network (we’ll create this next)
  • Persistent volume for logs

Step 5: Create the Docker Network

Traefik and your services need to share a Docker network:

1
docker network create traefik-public

All containers you want Traefik to route must be connected to this network.

Step 6: Start Traefik

Start Traefik:

1
docker compose up -d

Check the logs:

1
docker logs -f traefik

You should see Traefik start successfully and register the Docker provider. If there are errors about acme.json permissions, double-check that it’s set to 600.

Step 7: Access the Traefik Dashboard

Point your DNS for traefik.yourdomain.com to your server’s IP address. Wait a few moments for DNS propagation and Let’s Encrypt certificate provisioning (usually under 60 seconds).

Navigate to:

https://traefik.yourdomain.com

You’ll be prompted for basic authentication (username: admin, password: whatever you set). Once logged in, you’ll see the Traefik dashboard with an overview of routers, services, and middleware.

Step 8: Add Your First Service

Let’s add a simple service (Whoami) to test Traefik routing.

Create a new docker-compose.yml in a different directory (e.g., ~/whoami):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: '3.8'

services:
  whoami:
    image: traefik/whoami
    container_name: whoami
    restart: unless-stopped
    networks:
      - traefik-public
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)"  # Change this!
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"

networks:
  traefik-public:
    external: true

Change whoami.yourdomain.com to your actual subdomain.

Start the service:

1
docker compose up -d

Within seconds, Traefik will:

  1. Detect the new container
  2. Request a Let’s Encrypt certificate for whoami.yourdomain.com
  3. Route HTTPS traffic to the container

Visit https://whoami.yourdomain.com — you should see a response from the Whoami service with request headers and IP information.

Step 9: Add More Services

Adding additional services follows the same pattern. For example, to add Nextcloud:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: '3.8'

services:
  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    networks:
      - traefik-public
    volumes:
      - nextcloud-data:/var/www/html
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`cloud.yourdomain.com`)"
      - "traefik.http.routers.nextcloud.entrypoints=websecure"
      - "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
      - "traefik.http.services.nextcloud.loadbalancer.server.port=80"

volumes:
  nextcloud-data:

networks:
  traefik-public:
    external: true

This pattern works for any Docker service—just adjust the host rule, port, and add the traefik-public network.

Advanced Configuration Tips

1. Adding Middleware (Authentication, Rate Limiting, etc.)

Traefik supports powerful middleware for adding authentication, rate limiting, IP whitelisting, and more.

Example: Add basic auth to a service:

1
2
labels:
  - "traefik.http.routers.myservice.middlewares=auth@file"

In config/dynamic.yml:

1
2
3
4
5
6
http:
  middlewares:
    auth:
      basicAuth:
        users:
          - "user:$apr1$..."

2. Wildcard Certificates

For wildcard certificates (*.yourdomain.com), use DNS challenge instead of HTTP challenge. This requires DNS provider API credentials.

Example for Cloudflare:

1
2
3
4
5
6
7
8
9
certificatesResolvers:
  letsencrypt:
    acme:
      email: your-email@example.com
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"

Add your Cloudflare API credentials as environment variables in the Traefik docker-compose.yml:

1
2
3
environment:
  - CF_API_EMAIL=your-email@example.com
  - CF_API_KEY=your-api-key

3. Custom Headers and Security

Add security headers with middleware:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
http:
  middlewares:
    secureHeaders:
      headers:
        sslRedirect: true
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        frameDeny: true
        contentTypeNosniff: true
        browserXssFilter: true

Apply to a router:

1
2
labels:
  - "traefik.http.routers.myservice.middlewares=secureHeaders@file"

4. Separate Internal and External Networks

For services that don’t need internet exposure (databases, Redis, etc.), use separate Docker networks and don’t attach them to traefik-public.

Troubleshooting Common Issues

Certificate Not Provisioning

  • Check logs: docker logs traefik | grep acme
  • DNS propagation: Ensure your domain points to your server
  • Port 80 open: Let’s Encrypt HTTP challenge requires port 80 accessible
  • Rate limits: Let’s Encrypt has rate limits; wait if you’ve hit them

Service Not Routing

  • Network: Ensure the container is on traefik-public
  • Labels: Verify traefik.enable=true is set
  • Port: Check loadbalancer.server.port matches the container’s exposed port
  • Dashboard: Check the Traefik dashboard to see if the router is registered

Dashboard Not Accessible

  • DNS: Ensure traefik.yourdomain.com points to your server
  • Password hash: Verify the basicAuth hash is correct and $ are escaped as $$

Performance and Resource Usage

Traefik v3 is lightweight and efficient. On a typical homelab mini PC, Traefik uses:

  • RAM: ~50-100 MB
  • CPU: Minimal (<5% during normal operation)

Even with dozens of services, Traefik remains performant and responsive.

Security Best Practices

  1. Never expose the Docker socket publicly: Keep /var/run/docker.sock read-only and local
  2. Use strong basicAuth passwords: Generate with htpasswd
  3. Enable security headers: Use middleware for HSTS, CSP, and XSS protection
  4. Firewall rules: Only expose ports 80 and 443 to the internet
  5. Keep Traefik updated: Regularly update to the latest v3.x release
  6. Monitor logs: Watch for suspicious access patterns

When to Use Traefik vs. Other Reverse Proxies

Use Traefik if:

  • You’re running Docker or Kubernetes
  • You want automatic SSL certificate management
  • You frequently add/remove services
  • You value automatic service discovery

Use nginx/Caddy if:

  • You’re running traditional VMs or bare-metal apps
  • You need ultra-high performance for static content
  • You prefer file-based configuration

Traefik shines in dynamic, containerized environments—exactly what most modern self-hosters are running.

Conclusion

Traefik v3 simplifies reverse proxy management for Docker-based self-hosted services. With automatic service discovery, Let’s Encrypt integration, and a powerful middleware system, it eliminates the manual configuration headaches of traditional reverse proxies.

Once you’ve set up the initial Traefik container, adding new services is as simple as adding a few Docker labels. No config reloads, no manual certificate renewals, no editing nginx files—just add a container and go.

Whether you’re running a homelab on a compact mini PC or a full server rack, Traefik v3 is the reverse proxy that grows with your self-hosting journey.

Next steps:

  • Explore Traefik middleware (rate limiting, authentication, compression)
  • Set up monitoring with Prometheus and Grafana
  • Configure Traefik for high availability with multiple instances

Happy self-hosting!