Fixing HTTPS Redirect Loops: Pangolin + Dokploy + Traefik

When exposing services through a tunnel like Pangolin, you might hit a frustrating HTTPS redirect loop. Here's how I solved it for FreeScout on Dokploy, and the solution applies to any Laravel/PHP app behind this stack.

The Setup

Internet → Pangolin (TLS termination) → Newt → Traefik → Container

Pangolin terminates TLS and forwards requests with X-Forwarded-Proto: https. Simple enough, right?

The Problem

The app was stuck in an infinite redirect loop. Every request to HTTPS redirected to... HTTPS. Over and over.

After hours of debugging, I discovered the culprit: Traefik overwrites X-Forwarded-Proto.

When Newt connects to Traefik via HTTP (internal Docker network), Traefik sees an HTTP request and sets X-Forwarded-Proto: http — completely ignoring what Pangolin sent.

The app sees X-Forwarded-Proto: http, thinks “this should be HTTPS”, and redirects. Loop.

The Fix

Two changes are needed:

1. Tell Traefik to Trust Internal Networks

Edit /etc/dokploy/traefik/traefik.yml:

entryPoints:
  web:
    address: ':80'
    forwardedHeaders:
      trustedIPs:
        - "10.0.0.0/8"
        - "172.16.0.0/12"
  websecure:
    address: ':443'
    http:
      tls:
        certResolver: letsencrypt
    forwardedHeaders:
      trustedIPs:
        - "10.0.0.0/8"
        - "172.16.0.0/12"

This tells Traefik: “If a request comes from a Docker internal network, trust its X-Forwarded-* headers.”

Restart Traefik:

docker service update --force dokploy-traefik_traefik

2. Tell Laravel to Trust the Proxy

In Dokploy, add this environment variable:

APP_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12

This configures Laravel's TrustProxies middleware to accept forwarded headers from Docker networks.

Why This Works

  1. Pangolin sends X-Forwarded-Proto: https
  2. Newt forwards to Traefik
  3. Traefik sees Newt's IP is trusted → preserves the header
  4. App receives correct X-Forwarded-Proto: https
  5. No redirect. Done.

The Beautiful Part

This is a one-time configuration that works for all services exposed via Pangolin. No per-service hacks needed.

What Didn't Work

Before finding this solution, I tried:

The Traefik forwardedHeaders.trustedIPs setting is the proper, general solution.

Key Takeaway

When debugging proxy header issues, check every hop in your chain. The problem isn't always where you think it is. In this case, Traefik's default behavior of overwriting headers was the silent culprit.