Traefik Redirect Loop - Double Traefik Proxy

Problem Summary

I'm experiencing redirect loops and 404 errors when trying to access my Excalidraw service through Traefik. The service works internally https://excalidraw.local.mydomain.com but fails when accessed via the public domain https://excalidraw.mydomain.com.

Architecture

  • Main Traefik: External-facing reverse proxy (handles public traffic & source of true) at 10.66.0.99
  • Local Traefik: Internal services proxy (runs on TrueNAS server) at 10.66.0.100
  • Excalidraw: Docker container running on TrueNAS at 10.66.0.100

Doing this away so i don't need to expose port on TrueNAS for Apps

Expected Behavior

  • User visits https://excalidraw.mydomain.com
  • Main Traefik routes request to TrueNAS Traefik https://excalidraw.local.mydomain.com
  • TrueNAS Traefik get's Excalidraw APP
  • Excalidraw interface loads correctly

Actual Behavior

  • Main Traefik: Shows redirect loop (HTTP 301 responses)
  • TrueNAS Traefik: Returns 404 errors for some requests
  • Service is unreachable from external domain

Error Logs

Main Traefik (showing redirect loop):

10.66.0.99 - - [16/Sep/2025:10:46:49 +0000] "GET / HTTP/2.0" 301 17 "-" "-" 426 "excalidraw@file" "http://excalidraw.local.mydomain.com:80" 7ms 10.66.0.99 - - [16/Sep/2025:10:46:49 +0000] "GET / HTTP/2.0" 301 17 "-" "-" 427 "excalidraw@file" "http://excalidraw.local.mydomain.com:80" 8ms [repeated multiple times...]

TrueNAS Traefik (showing 404s):

10.66.0.100 - - [16/Sep/2025:10:38:32 +0000] "GET / HTTP/2.0" 404 19 "-" "-" 77 "-" "-" 0ms 10.20.0.100 - - [16/Sep/2025:10:38:32 +0000] "GET /favicon.ico HTTP/2.0" 404 19 "-" "-" 78 "-" "-" 0ms

Configuration Files

Main Traefik Configuration

docker-compose.yaml:

secrets:
	cf-token:
		file: ./cf-token
services:
	traefik:
		image: traefik:latest
		container_name: traefik
		restart: unless-stopped
		security_opt:
		- no-new-privileges:true
		secrets:
			- cf-token
		env_file:
			- .env
		networks:
			- proxy
		ports:
			- 80:80
			- 81:81
			- 443:443
			- 444:444
		environment:
			- TRAEFIK_DASHBOARD_CREDENTIALS=${TRAEFIK_DASHBOARD_CREDENTIALS}
			- CF_DNS_API_TOKEN_FILE=/run/secrets/cf-token
		volumes:
			- /etc/localtime:/etc/localtime:ro
			- /var/run/docker.sock:/var/run/docker.sock:ro
			- /home/ubuntu/docker/traefik/traefik.yaml:/traefik.yaml:ro
			- /home/ubuntu/docker/traefik/acme.json:/acme.json
			- /home/ubuntu/docker/traefik/config.yaml:/config.yaml:ro
			- /home/ubuntu/docker/traefik/logs:/var/log/traefik
		labels:
			- "traefik.enable=true"
			- "traefik.http.routers.traefik.entrypoints=http"
			- "traefik.http.routers.traefik.rule=Host(`traefik.mydomain.com`)"
			- "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(`traefikmydomain.com`)"
			- "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=mydomain.com"
			- "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.mydomain.com"
			- "traefik.http.routers.traefik-secure.service=api@internal"

networks:
	proxy:
		external: true

traefik.yaml:

api:
	dashboard: true
	debug: true
entryPoints:
	http:
		address: ":80"
		http:
			redirections:
				entrypoint:
					to: https
					scheme: https
	https:
		address: ":443"
	http-external:
		address: ":81"
		http:
			redirections:
				entrypoint:
					to: https-external
					scheme: https
	https-external:
		address: ":444"
serversTransport:
	insecureSkipVerify: true
providers:
	docker:
		endpoint: "unix:///var/run/docker.sock"
		exposedByDefault: false
	file:
		filename: /config.yaml

certificatesResolvers:
	cloudflare:
		acme:
			caServer: acme-staging-v02.api.letsencrypt.org/directory 
			email: ...
			storage: acme.json
			dnsChallenge:
				provider: cloudflare 
				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"

config.yaml:

http:
  middlewares:
    default-security-headers:
      headers:
        customBrowserXSSValue: 0
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: false
        referrerPolicy: strict-origin-when-cross-origin
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 3153600
        contentSecurityPolicy: default-src 'self'; script-src 'self' 'unsafe-inline';
          style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src
          'self' data:; connect-src 'self' wss:;
        customRequestHeaders:
          X-Forwarded-Proto: https
    https-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true
  routers:
    excalidraw:
      entryPoints:
        - https
      rule: Host(`excalidraw.mydomain.com`)
      middlewares:
        - default-security-headers
        - https-redirectscheme
      tls: {}
      service: excalidraw
  services:
    excalidraw:
      loadBalancer:
        servers:
          - url: https://excalidraw.local.mydomain.com
        passHostHeader: true

TrueNAS Traefik Configuration

docker-compose.yaml:

secrets:
  cf-token:
    file: ./cf-token
services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    secrets:
      - cf-token
    env_file:
      - .env
    networks:
      - proxy
    ports:
      - 80:80
      - 81:81
      - 443:443
      - 444:444
    environment:
      - TRAEFIK_DASHBOARD_CREDENTIALS=${TRAEFIK_DASHBOARD_CREDENTIALS}
      - CF_DNS_API_TOKEN_FILE=/run/secrets/cf-token
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/temp/apps/docker/traefik/traefik.yaml:/traefik.yaml:ro
      - /mnt/temp/apps/docker/traefik/acme.json:/acme.json
      - /mnt/temp/apps/docker/traefik/config.yaml:/config.yaml:ro
      - /mnt/temp/apps/docker/traefik/logs:/var/log/traefik
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.entrypoints=http
      - traefik.http.routers.traefik.rule=Host(`traefik.local.mydomain.com`)
      - 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.local.mydomain.com`)
      - 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=mydomain.com
      - traefik.http.routers.traefik-secure.tls.domains[0].sans=*.local.mydomain.com
      - traefik.http.routers.traefik-secure.service=api@internal
networks:
  proxy:
    external: true

traefik.yaml:

api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: :80
    http:
      middlewares:
        - crowdsec-bouncer@file
      redirections:
        entrypoint:
          to: https
          scheme: https
  https:
    address: :443
    http:
      middlewares:
        - crowdsec-bouncer@file
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false
  file:
    filename: /config.yaml
certificatesResolvers:
  cloudflare:
    acme:
      caServer: https://acme-staging-v02.api.letsencrypt.org/directory
      email: ...
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        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

config.yaml:

http:
  middlewares:
    default-security-headers:
      headers:
        customBrowserXSSValue: 0
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: false
        referrerPolicy: strict-origin-when-cross-origin
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 3153600
        contentSecurityPolicy: default-src 'self'
        customRequestHeaders:
          X-Forwarded-Proto: https
    https-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true
    crowdsec-bouncer:
      forwardauth:
        address: http://bouncer-traefik:8080/api/v1/forwardAuth
        trustForwardHeader: true

Excalidraw (Runing on TrueNAS)

docker-compose.yaml:

services:
  excalidraw:
    image: excalidraw/excalidraw:latest
    container_name: excalidraw
    restart: on-failure
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.excalidraw.entrypoints=http
      - traefik.http.routers.excalidraw.rule=Host(`excalidraw.local.mydomain.com`)
      - traefik.http.middlewares.excalidraw-https-redirect.redirectscheme.scheme=https
      - traefik.http.routers.excalidraw.middlewares=excalidraw-https-redirect
      - traefik.http.routers.excalidraw-secure.entrypoints=https
      - traefik.http.routers.excalidraw-secure.rule=Host(`excalidraw.local.mydomain.com`)
      - traefik.http.routers.excalidraw-secure.tls=true
      - traefik.http.routers.excalidraw-secure.service=excalidraw
      - traefik.http.services.excalidraw.loadbalancer.server.port=80
      - traefik.docker.network=proxy

networks:
  proxy:
    external: true

Questions

  1. Should I remove the https-redirectscheme middleware since I already have automatic redirect in entryPoints?
  2. What should the service URL be - How should Main Traefik point to TrueNAS Traefik
  3. Do I need to configure the Excalidraw route on both Traefik instances or just one?
  4. Is there a network connectivity issue between the two Traefik instances?

Environment

  • Traefik Version: Latest
  • Docker Setup: Both Traefik instances running in Docker
  • Network: Internal network
  • SSL: Let's Encrypt via Cloudflare DNS challenge

Any help troubleshooting this setup would be greatly appreciated!

Let’s clean this up.

  1. Remove https-redirect middlewares
  2. Remove tls: {} which plain will disable LetsEncrypt
  3. Assign the certResolver directly to secure entrypoints
  4. Remove X-Forwarded-Proto which is added automatically
  5. Use external domain for Host() on second proxy, as you tell the first proxy to forward it (or adapt service on first to use the local domain)
  6. Enable access log in JSON format
  7. Why bouncer on internal Traefik?