We’re going to explore how to enhance the security of your Traefik server. We’ll discuss Access Control Lists (ACLs), rate limiting, and GeoIP blocking, and also take a look at how to only permit traffic from certain networks like Cloudflare.

1. Access Control Lists (ACLs)

Traefik uses middlewares to allow or deny access based on a set of conditions. Here’s an example of how to allow a specific IP address:

http:
  middlewares:
    trusted-ips:
      ipAllowList:
        sourceRange:
          - '192.168.1.0/24'    # Local network
          - '10.0.0.0/8'        # Private network
          - '203.0.113.0/24'    # Specific trusted range
        ipStrategy:
          depth: 2              # Consider X-Forwarded-For depth
          excludedIPs:
            - '127.0.0.1/32'    # Exclude localhost
  routers:
    secure-router:
      middlewares:
        - trusted-ips

This configuration allows access from specified IP ranges while considering forwarded headers from proxies.

2. Rate Limiting

Protect your services from abuse using Traefik’s rate limiting middleware with configurable burst and sustained rates:

http:
  middlewares:
    api-rate-limit:
      rateLimit:
        average: 100          # Requests per second (sustained)
        burst: 200           # Maximum burst size
        period: 1m           # Time window for rate calculation
        sourceCriterion:
          ipStrategy:
            depth: 1         # Consider proxy depth
            excludedIPs:
              - '127.0.0.1/32'
    
    strict-rate-limit:
      rateLimit:
        average: 10
        burst: 20
        period: 1m
  
  routers:
    api-router:
      middlewares:
        - api-rate-limit
    admin-router:
      middlewares:
        - strict-rate-limit

This provides different rate limits for different services - more permissive for APIs, stricter for admin interfaces.

3. Allow only Cloudflare IPs

Restrict access to only Cloudflare’s edge servers when using Cloudflare as a CDN/proxy:

http:
  middlewares:
    cloudflare-only:
      ipAllowList:
        sourceRange:
          # IPv4 ranges (update regularly from https://www.cloudflare.com/ips/)
          - '103.21.244.0/22'
          - '103.22.200.0/22'
          - '103.31.4.0/22'
          - '104.16.0.0/13'
          - '104.24.0.0/14'
          - '108.162.192.0/18'
          - '131.0.72.0/22'
          - '141.101.64.0/18'
          - '162.158.0.0/15'
          - '172.64.0.0/13'
          - '173.245.48.0/20'
          - '188.114.96.0/20'
          - '190.93.240.0/20'
          - '197.234.240.0/22'
          - '198.41.128.0/17'
          # IPv6 ranges
          - '2400:cb00::/32'
          - '2606:4700::/32'
          - '2803:f800::/32'
          - '2405:b500::/32'
          - '2405:8100::/32'
          - '2a06:98c0::/29'
          - '2c0f:f248::/32'
        ipStrategy:
          depth: 1

Important: Update these IP ranges regularly as Cloudflare may change them. Check https://www.cloudflare.com/ips/ for current ranges.

4. Trusted Proxy Configuration

When your Traefik instance sits behind reverse proxies like Cloudflare, load balancers, or CDNs, these intermediaries mask the real client IP addresses. Instead of seeing the actual visitor’s IP, Traefik only sees the proxy’s IP address. This breaks IP-based security features like rate limiting and access control.

The solution is configuring Traefik to trust specific proxy IPs and extract the real client IP from HTTP headers like X-Forwarded-For. This restoration of true client IPs ensures your security policies work correctly while maintaining the benefits of your proxy infrastructure.

# Static configuration (docker-compose command or traefik.yml)
entryPoints:
  web:
    address: ':80'
    forwardedHeaders:
      trustedIPs:
        - '103.21.244.0/22'
        - '103.22.200.0/22'
        - '103.31.4.0/22'
        - '104.16.0.0/13'
        - '104.24.0.0/14'
        - '108.162.192.0/18'
        - '131.0.72.0/22'
        - '141.101.64.0/18'
        - '162.158.0.0/15'
        - '172.64.0.0/13'
        - '173.245.48.0/20'
        - '188.114.96.0/20'
        - '190.93.240.0/20'
        - '197.234.240.0/22'
        - '198.41.128.0/17'
      insecure: false        # Only trust specified IPs
  
  websecure:
    address: ':443'
    forwardedHeaders:
      trustedIPs:
        # Same Cloudflare IP ranges as above
        - '103.21.244.0/22'
        # ... (same list)
      insecure: false

This enables accurate client IP detection for security policies while maintaining CDN benefits.

5. Security Headers Middleware

Security headers are HTTP response headers that instruct browsers how to behave when handling your site’s content. They provide crucial protection against cross-site scripting (XSS), clickjacking, content type sniffing, and other client-side attacks. Modern web applications should implement these headers as a fundamental security layer.

These headers work by telling the browser to enforce security policies - for example, preventing your site from being embedded in frames (clickjacking protection), forcing HTTPS connections (HSTS), and restricting resource loading (CSP). While they don’t protect your server directly, they create a security boundary in the user’s browser.

http:
  middlewares:
    security-headers:
      headers:
        accessControlAllowMethods:
          - GET
          - OPTIONS
          - PUT
          - POST
          - DELETE
        accessControlMaxAge: 100
        hostsProxyHeaders:
          - X-Forwarded-Host
        referrerPolicy: "strict-origin-when-cross-origin"
        forceSTSHeader: true
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        contentTypeNosniff: true
        browserXssFilter: true
        customFrameOptionsValue: "SAMEORIGIN"
        customRequestHeaders:
          X-Forwarded-Proto: "https"
        customResponseHeaders:
          X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex"
          server: ""
          X-Powered-By: ""
        contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'self';"

6. Authentication Middleware

Authentication adds a verification layer before users can access your services. This is essential for admin panels, APIs, and any sensitive content. Traefik supports multiple authentication methods, from simple basic auth to sophisticated OAuth flows.

Basic authentication provides quick protection with username/password combinations, while forward authentication delegates to external services like OAuth providers. Choose based on your security requirements - basic auth for simple internal tools, OAuth for production applications with user management needs.

http:
  middlewares:
    basic-auth:
      basicAuth:
        users:
          - "admin:$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi"  # admin:password
        realm: "Traefik Dashboard"
        removeHeader: true
    
    oauth-forward:
      forwardAuth:
        address: "http://oauth-proxy:4181"
        authResponseHeaders:
          - "X-Forwarded-User"
          - "X-Auth-User"
        trustForwardHeader: true

7. Circuit Breaker for Resilience

Circuit breakers protect your infrastructure from cascading failures. When a backend service becomes unhealthy or overloaded, the circuit breaker temporarily stops forwarding requests to it, preventing the problem from spreading to other parts of your system.

Think of it like an electrical circuit breaker in your home - when there’s too much load, it trips to prevent damage. In web applications, this means detecting when error rates or network issues exceed thresholds, then failing fast instead of letting requests pile up and timeout. This maintains overall system stability during partial outages.

http:
  middlewares:
    circuit-breaker:
      circuitBreaker:
        expression: "NetworkErrorRatio() > 0.30 || ResponseCodeRatio(500, 600, 0, 600) > 0.25"
        checkPeriod: 10s
        fallbackDuration: 30s
        recoveryDuration: 10s

8. Complete Security Stack Example

Real-world security requires layering multiple protections. No single security measure is sufficient - attackers who bypass one layer should encounter another. This defense-in-depth approach combines IP filtering, rate limiting, authentication, and other measures into comprehensive protection.

The key is creating middleware chains that apply appropriate security levels for different types of services. Public APIs need different protection than admin interfaces, and you can mix and match middlewares to create the right security posture for each endpoint.

http:
  middlewares:
    security-stack:
      chain:
        middlewares:
          - cloudflare-only
          - security-headers
          - api-rate-limit
          - circuit-breaker
    
    admin-security:
      chain:
        middlewares:
          - trusted-ips
          - basic-auth
          - strict-rate-limit
          - security-headers
  
  routers:
    api-secure:
      rule: "Host(`api.example.com`)"
      middlewares:
        - security-stack
      service: api-service
      tls:
        certResolver: letsencrypt
    
    admin-secure:
      rule: "Host(`admin.example.com`)"
      middlewares:
        - admin-security
      service: admin-service
      tls:
        certResolver: letsencrypt

9. Enhanced Logging and Monitoring

Security without visibility is incomplete. Comprehensive logging provides the data needed to detect attacks, investigate incidents, and improve your security posture over time. Structured JSON logs make it easier to analyze patterns and integrate with security tools.

Good logging captures not just successful requests, but failed authentication attempts, blocked IPs, and suspicious patterns. This creates an audit trail that’s essential for both real-time alerting and post-incident analysis. The logs also feed into automated defense systems like Fail2Ban.

# Static configuration
accessLog:
  format: json
  fields:
    defaultMode: keep
    names:
      ClientUsername: drop
    headers:
      defaultMode: keep
      names:
        User-Agent: keep
        Authorization: drop
        Content-Type: keep
        X-Forwarded-For: keep
        X-Real-IP: keep

log:
  level: INFO
  format: json
  
api:
  dashboard: true
  debug: false
  insecure: false

metrics:
  prometheus:
    buckets:
      - 0.1
      - 0.3
      - 1.2
      - 5.0
    addEntryPointsLabels: true
    addServicesLabels: true

Fail2Ban Integration

Fail2Ban automatically blocks IP addresses that show malicious behavior by analyzing log files and creating temporary firewall rules. This provides dynamic protection against brute force attacks, bot scanning, and other automated threats.

The integration works by parsing Traefik’s access logs to identify suspicious patterns - multiple authentication failures, requests for non-existent files, or attempts to access sensitive paths. When thresholds are exceeded, Fail2Ban adds the offending IP to a blocklist.

# /etc/fail2ban/filter.d/traefik-auth.conf
[Definition]
failregex = .*"ClientHost":"<HOST>".*"OriginStatus":401.*
            .*"ClientHost":"<HOST>".*"OriginStatus":403.*
            .*"ClientHost":"<HOST>".*"OriginStatus":404.*"RequestMethod":"POST".*

ignoreregex =

# /etc/fail2ban/filter.d/traefik-botsearch.conf
[Definition]
failregex = .*"ClientHost":"<HOST>".*"RequestPath":"/\.(env|git|svn|htaccess).*"
            .*"ClientHost":"<HOST>".*"RequestPath":".*(admin|wp-admin|phpmyadmin).*"
            .*"ClientHost":"<HOST>".*"RequestPath":".*(sql|php|asp).*"

# /etc/fail2ban/jail.local
[traefik-auth]
enabled = true
filter = traefik-auth
logpath = /var/log/traefik/access.log
maxretry = 5
bantime = 3600
findtime = 600

[traefik-botsearch]
enabled = true
filter = traefik-botsearch
logpath = /var/log/traefik/access.log
maxretry = 3
bantime = 86400
findtime = 600

10. Timeout and Performance Configuration

Proper timeout configuration serves both performance and security purposes. Timeouts prevent resource exhaustion attacks where malicious clients hold connections open indefinitely, while also ensuring responsive user experiences by failing fast when backends are slow.

Connection limits and health checks add another layer of protection. By restricting concurrent connections and actively monitoring backend health, you prevent both accidental overload and deliberate resource exhaustion attempts.

# Static configuration
serversTransport:
  maxIdleConnsPerHost: 42
  forwardingTimeouts:
    dialTimeout: 30s
    responseHeaderTimeout: 60s
    idleConnTimeout: 90s
  insecureSkipVerify: false

# Service-specific timeouts
http:
  services:
    secure-service:
      loadBalancer:
        servers:
          - url: "http://backend:8080"
        healthCheck:
          path: "/health"
          interval: 30s
          timeout: 10s
          scheme: http
        sticky:
          cookie:
            name: "traefik-session"
            secure: true
            httpOnly: true
            sameSite: strict

11. Additional Security Hardening

Docker Security Configuration

Container security is crucial since Traefik often runs with elevated privileges to access the Docker socket. These measures implement the principle of least privilege - Traefik gets only the minimal permissions needed to function, reducing the impact of potential compromises.

Running as non-root, dropping capabilities, and using read-only filesystems all limit what an attacker can do if they manage to exploit the application. The security options work together to create a hardened container environment.

services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
      - seccomp:unconfined
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    user: "1000:1000"  # Non-root user
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme:/etc/traefik/acme:rw
      - ./logs:/var/log/traefik:rw
    tmpfs:
      - /tmp
    environment:
      - TRAEFIK_LOG_LEVEL=INFO
    networks:
      - traefik

File Permission Security

File system permissions are your last line of defense. Even if an attacker gains access to your server, properly configured permissions can prevent them from reading sensitive configuration files or SSL certificates.

Certificate files are particularly sensitive - they contain private keys that, if compromised, allow attackers to impersonate your services. Restrictive permissions ensure only authorized processes can access these critical files.

# Set restrictive permissions
chmod 600 /etc/traefik/acme/acme.json
chmod 640 /etc/traefik/traefik.yml
chown traefik:traefik /etc/traefik/acme/acme.json
chown root:traefik /etc/traefik/traefik.yml

These configurations provide defense-in-depth security for production Traefik deployments, protecting against common attack vectors while maintaining performance and reliability.



Buy Me a Coffee