Traefik Proxy

Exploring Reverse Proxies in My Homelab: From Nginx Proxy Manager to Traefik

When I completed my homelab project, I was excited by its endless possibilities. Suddenly, I could experiment freely without worrying about accidentally breaking something important. Before setting up my dedicated homelab environment, I had no choice but to test and practice directly on my primary workstation, an approach that inevitably carried significant risks. Having a safe, isolated environment means I can confidently plan, test, and implement new ideas without impacting my day-to-day tasks or productivity.

One key area I was eager to explore was the use and deployment of reverse proxies, a crucial component in many enterprise IT infrastructures. Initially, I considered using Nginx Proxy Manager, a well-known solution in the homelab community. Nginx Proxy Manager simplifies exposing internal web services securely to the Internet and automates obtaining SSL certificates through Let’s Encrypt, significantly streamlining the process of securing web applications.

What is a reverse proxy?

A reverse proxy is an intermediary server that forwards client requests to backend services or servers. It’s helpful in homelab setups for:

  • Securing access with SSL/TLS encryption.
  • Simplifying external access to internal services (Nextcloud, Plex, Docker apps, etc.).
  • Managing multiple services under one domain or IP address.
  • Handling authentication, access control, and load balancing.

However, I decided to challenge myself further by exploring Traefik Proxy, an open-source solution similar in concept to Nginx Proxy Manager, but with distinct advantages, particularly well-suited to enterprise scenarios. Traefik offers several powerful features that intrigued me:

  • Native Integration with Container Orchestration Platforms:
    Seamlessly integrates with technologies like Kubernetes and Docker Swarm, automatically detecting and configuring services without manual intervention.
  • Dynamic Configuration:
    Automatically adapts to infrastructure changes, eliminating the need for manual reloads or restarts whenever services or routes are modified.
  • Built-in Metrics, Tracing, and Advanced Load Balancing:
    It provides native observability, detailed metrics, and efficient load balancing capabilities, which is ideal for managing complex microservice architectures.
  • Cloud and Platform Compatibility:
    Compatible with cloud platforms such as AWS, making it an excellent choice for hybrid or multi-cloud environments.
  • Scalability for Microservices:
    Explicitly designed to scale gracefully in environments running numerous microservices, this is a typical pattern in modern enterprise applications.

Traefik’s robust feature set made it particularly appealing. I aimed to gain practical, hands-on experience with tools widely adopted in large-scale, production-level environments. By embracing Traefik, I took another important step toward deepening my technical expertise and preparing myself for future professional opportunities in the IT industry.


Overview

FeatureNginx Proxy ManagerTraefik
Core TechNginx (traditional reverse proxy)Native Go-based proxy/load balancer
UIBuilt-in Web UI (very user-friendly)Dashboard (for monitoring); config via files or labels
SSL (Let’s Encrypt)Automatic, via UIAutomatic, fully integrated
Docker IntegrationGood (manual container setup)Excellent (dynamic routing via labels)
Load BalancingBasic (round robin via Nginx config)Built-in advanced (sticky sessions, etc.)
Routing LogicManual configurationDynamic, rule-based (host, path, headers, etc.)
Ease of SetupVery easy, great for beginnersModerate, better for intermediate users
PerformanceHighVery high, especially at scale

My Docker compose file for Traefik

secrets:
  cf-token:
    file: ./cf-token
services:
  traefik:
    image: traefik:latest # or traefik:v3.3 to pin a version
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true # helps to increase security
    secrets:
      - cf-token # the secret at the top of this file
    env_file:
      - .env # store other secrets e.g., dashboard password
    networks:
       proxy:
    ports:
      - 80:80
      - 443:443
     # - 10000:10000 # optional
     # - 33073:33073 # optional
    environment:
      - TRAEFIK_DASHBOARD_CREDENTIALS=${TRAEFIK_DASHBOARD_CREDENTIALS}
      - CF_API_EMAIL=youremail # Your Cloudflare email
      # - CF_DNS_API_TOKEN=YOUR-TOKEN
      - CF_DNS_API_TOKEN_FILE=/run/secrets/cf-token # see https://doc.traefik.io/traefik/https/acme/#providers
      # token file is the proper way to do it
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/debian/docker/traefik/config/traefik.yaml:/traefik.yaml:ro
      - /home/debian/docker/traefik/config/acme.json:/acme.json
      - /home/debian/docker/traefik/config/config.yaml:/config.yaml:ro
      - /home/debian/docker/traefik/logs:/var/log/traefik
    
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.uk`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_DASHBOARD_CREDENTIALS}"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.yourdomain.uk`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=yourdomain.uk"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.yourdomain.uk"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true

When deploying Traefik as your primary reverse proxy with Docker, here are some key points to keep in mind:

  1. Docker Network: Ensure all services you want Traefik to route are in the same Docker network. Typically, you create a network (e.g., traefik-net) (In my case, I used proxy), and attach both Traefik and your services to it.
networks:
  proxy:
    external: true


Usually, it’s a good idea to create the network beforehand. Therefore, Traefik can use the network during the deployment. To create the network in Docker, you can run –

sanju@pihole-vm-VLAN-70:~/docker$ docker network create exmaple-network
814a6c93758c55a6af67ee2b57a0a288af72ac9ec5729d57b959975224447ac8
sanju@pihole-vm-VLAN-70:~/docker$ 

After creating the network, you can verify using the docker command-

sanju@pihole-vm-VLAN-70:~/docker$ docker network ls 
NETWORK ID     NAME              DRIVER    SCOPE
7d0c0098a487   bridge            bridge    local
4d331a9a9f70   exmaple-network   bridge    local
813e29d19142   host              host      local
cd84d0dbaeff   none              null      local

Docker Labels Use labels in your docker-compose.yml files to define routing rules for Traefik. This allows it to discover and configure services dynamically.

Exposing Ports Traefik needs to listen on ports 80 (HTTP) and 443 (HTTPS) to handle incoming requests. If using the Traefik dashboard, you also need to expose it properly.

Certificates (Optional) If you want HTTPS, set up Let’s Encrypt or bring your certificates.

In my Traefik setup, I prioritised using SSL certificates from Let’s Encrypt. To achieve this, I created and mounted a file acme.json in the configuration directory, where Traefik securely stores my domain’s Let’s Encrypt SSL certificates.

Additionally, I use a .env file in the root of my project directory to store sensitive credentials, including the Traefik dashboard login details. For Cloudflare integration, I keep my API token in a cf-token file. Both of these values are referenced as environment variables in my docker-compose.yml file, ensuring a secure and organised configuration.

sanju@pihole-vm-VLAN-70:~/docker$ tree traefik/
traefik/
├── cf-token
├── config
│   ├── acme.json
│   ├── config.yaml
│   └── traefik.yaml
├── docker-compose.yaml
└── logs
    ├── access.log
    └── traefik.log

Using acme.json for Let’s Encrypt ensures your certificates are safely stored, and keeps credentials in .env and cf-token adds an extra layer of security.

A few best practices for your setup:

  1. Set Proper Permissions
    • acme.json Should be read/write only for Traefik:
chmod 0600 acme.json
  • This prevents unauthorised access to your certificates.

Docker Secrets (Optional)

  • If you’re running Docker Swarm, consider using Docker secrets instead of .env for sensitive credentials.

Cloudflare API Token Scope

  • Ensure the Cloudflare API token has only the required permissions (e.g., DNS edit for ACME challenge).

The traefik.yaml The file is the static configuration file for Traefik. It defines the core settings that Traefik loads when it starts up. This file is essential because Traefik has two types of configurations:

  1. Static Configuration (Defined in traefik.yaml or CLI args)
    • Loaded at startup and cannot be changed dynamically.
    • Includes settings like entry points, providers, and API/dashboard configuration.
  2. Dynamic Configuration (Defined via Docker labels, files, or Kubernetes)
    • Managed dynamically while Traefik is running.
    • Includes routers, middlewares, and services for routing traffic.

My traefik.yaml file

api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
    http:
      # middlewares: # uncomment if using CrowdSec 
        #- crowdsec-bouncer@file
      redirections:
        entrypoint:
          to: https
          scheme: https
  https:
    address: ":443"
    http:
      # middlewares: # uncomment if using CrowdSec 
        #- crowdsec-bouncer@file
  # tcp:
   # address: ":10000"
  # apis:
   # address: ":33073"
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yaml # example provided gives A+ rating https://www.ssllabs.com/ssltest/
certificatesResolvers:
  cloudflare:
    acme:
      # caServer: https://acme-v02.api.letsencrypt.org/directory # production (default)
      # caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging (testing)
      email: youremail # Cloudflare email (or other provider)
      storage: acme.json
      dnsChallenge:
        provider: cloudflare # change as required
        # disablePropagationCheck: true # Some people using Cloudflare note this can solve DNS propagation issues.
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

log:
  level: "INFO"
  filePath: "/var/log/traefik/traefik.log"
accessLog:
  filePath: "/var/log/traefik/access.log"

Key Sections in traefik.yaml

  • Entry Points: Define which ports Traefik listens on (e.g., HTTP/HTTPS).
  • Providers: Tell Traefik where to get service configurations (Docker, Kubernetes, etc.).
  • API: Enables the Traefik dashboard.
  • CertificatesResolvers: Configures Let’s Encrypt for automatic HTTPS.

This file is usually mounted in a Docker setup like this:

volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/debian/docker/traefik/config/traefik.yaml:/traefik.yaml:ro
      - /home/debian/docker/traefik/config/acme.json:/acme.json
      - /home/debian/docker/traefik/config/config.yaml:/config.yaml:ro
      - /home/debian/docker/traefik/logs:/var/log/traefik

To obtain an SSL certificate with Traefik, you must own a domain from a registrar or provider. I chose Cloudflare for my domain setup, but many other options are available.

Domain Ownership Verification for Let’s Encrypt

Before issuing an SSL certificate, Let’s Encrypt requires proof that you own the domain. There are three ways to achieve this:

  1. DNS Challenge
    • Creates a special DNS TXT record in your domain settings.
    • Works even when your server is behind a firewall or NAT.
    • Ideal for wildcard certificates (*.example.com).
  2. TLS Challenge
    • Requires Traefik to serve a temporary TLS certificate.
    • Requires direct HTTPS access to your server on port 443.
  3. HTTP Challenge
    • Places a special file on your web server (.well-known/acme-challenge/).
    • Requires port 80 to be open.

Why I Chose DNS Challenge

Since I am using Proxmox for virtualisation, I preferred not to expose any additional ports on my firewall. The DNS challenge was the best choice because:

  • It works without opening ports 80 or 443.
  • It allows issuing wildcard SSL certificates (*.mydomain.com).
  • It integrates well with Cloudflare via API, automating the process.

This approach ensures a secure and automated SSL certificate setup while protecting my network.

Conclusion

After deploying my Traefik proxy, everything worked as expected. I’m excited to experiment more with Traefik in future projects, but for now, I can confidently say it’s a fantastic tool that’s well worth learning.

Back to top arrow