Home › Web & HTTP

ERR_TOO_MANY_REDIRECTS — how to fix

This page isn't working
example.com redirected you too many times.
ERR_TOO_MANY_REDIRECTS

Quick fix: Trace the loop: curl -sIL https://example.com | grep -i '^location'. Behind Cloudflare, set SSL mode to Full (strict) instead of Flexible. Behind a proxy, make the app trust X-Forwarded-Proto so it knows the request is already HTTPS.

What it means

Browsers give up after ~20 redirects. Some rule sends the request back to a URL that redirects again.

First, clear cookies for the site (a bad cookie can cause login loops) and see the chain:

curl -sIL https://example.com | grep -iE '^(HTTP|location)'

Cause 1: Cloudflare "Flexible" SSL + origin forcing HTTPS

With Flexible, Cloudflare talks to your server over HTTP. Your server redirects to HTTPS, Cloudflare fetches HTTP again… forever.

Fix: install a certificate on the origin (Let's Encrypt or a Cloudflare Origin Certificate) and set SSL/TLS → Full (strict). Load balancers like AWS ALB doing TLS termination cause the same loop.

Cause 2: the app doesn't know it's behind HTTPS

A reverse proxy terminates TLS and forwards plain HTTP. The app sees HTTP and redirects to HTTPS. Pass and trust the forwarded protocol:

nginx:

proxy_set_header X-Forwarded-Proto $scheme;

Then in the app: Django SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https"), Express app.set("trust proxy", 1), Laravel TrustProxies middleware, Rails config.assume_ssl = true.

Cause 3: www and non-www rules fighting

One rule redirects example.com → www.example.com and another (DNS provider, CDN, app setting) does the reverse. Choose one canonical host and remove the other rule.

WordPress: siteurl and home (Settings → General or wp_options) must match your real canonical URL, including https:// and www.

Cause 4: nginx config loops

server {
    listen 443 ssl;
    return 301 https://$host$request_uri;   # redirects HTTPS to itself
}

Only put the redirect in the listen 80 server block.

Cause 5: auth redirect loops

A login page that itself requires login, or a session cookie that never sticks (wrong domain, Secure cookie on HTTP, SameSite issues) makes the app redirect to /login forever. Exclude the login route from the auth check and inspect the Set-Cookie header.

Last updated 2026-10-28.