How to Fix a Redirect Loop
You get a redirect loop when the server (or CDN) keeps sending the browser back and forth, e.g. A → B → A, or www → non-www → www. The browser gives up and shows ERR_TOO_MANY_REDIRECTS. Here's how to trace the loop, find the conflicting rule, and fix it on Nginx, Apache, and Cloudflare.
Key takeaways
- Trace the loop first: Use our HTTPS checker or browser DevTools (Network tab) to see the exact redirect chain.
- Common causes: Conflicting www vs non-www rules, HTTP→HTTPS in the wrong place (e.g. in the HTTPS block), or both CDN and origin redirecting.
- Use separate server blocks (Nginx) or clear rule order (Apache) so only one redirect applies per request.
- If you use Cloudflare (or another CDN), avoid redirecting at the origin in a way that conflicts with the CDN, otherwise you get a loop.
What is a redirect loop?
The server (or CDN) keeps sending the browser to another URL, which then sends it back, e.g. https://example.com → https://www.example.com → https://example.com → … After a few hops the browser stops and shows ERR_TOO_MANY_REDIRECTS (Chrome) or similar. Fix: find which two (or more) rules are fighting and keep only one path, e.g. always end on https://www.example.com or always on https://example.com.
How to trace the redirect loop
Before touching config, see the exact chain. Two ways:
- HTTPS checker: Enter your domain on our checker. If there’s a loop, the report will show the chain (repeated URLs). That tells you which hosts or paths are bouncing (e.g. www vs non-www, or HTTP vs HTTPS).
- Browser DevTools: Open DevTools (F12) → Network tab, enable “Preserve log,” then load the URL. You’ll see each redirect (301/302) and the next URL. Follow the chain until you see it repeat.
Once you’ve got the chain (e.g. www → non-www → www), fix the rule that shouldn’t be there, or make sure only one side does the redirect.
Common causes of redirect loops
- www vs non-www: One rule sends www → non-www, another sends non-www → www. Keep a single canonical choice and redirect the other to it in one place only.
- HTTP → HTTPS in the wrong block: If the HTTPS server block (port 443) also issues a redirect to HTTPS, every HTTPS request gets redirected again → loop. Put the “redirect HTTP to HTTPS” rule only in the port 80 block.
- CDN + origin both redirecting: Cloudflare (or another CDN) redirects HTTP to HTTPS, and your origin also redirects HTTP to HTTPS. The CDN may send the request to the origin over HTTP; the origin then redirects to HTTPS; the CDN might send again to origin over HTTP → loop. Fix: either turn off “Always Use HTTPS” at the CDN and do the redirect only at the origin, or turn off the HTTP→HTTPS redirect at the origin and let the CDN handle it (Cloudflare recommends the latter).
- Nginx
if+ rewrite: Usingifwithrewritewhen both www and non-www are inserver_namecan cause repeated evaluation and a loop. Prefer separate server blocks instead.
Fixing a redirect loop in Nginx
Use separate server blocks for each “role”: one for HTTP (port 80) that redirects to HTTPS, one for the non-canonical host (e.g. www) that redirects to the canonical host, and one for the canonical HTTPS site that serves content. Avoid redirecting inside the block that serves content.
Example: canonical site is https://example.com. Then:
# 1) HTTP → HTTPS (port 80 only)
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# 2) www HTTPS → non-www HTTPS (canonical)
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
return 301 https://example.com$request_uri;
}
# 3) Canonical HTTPS – serve site here (no redirect)
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
root /var/www/html;
# ...
}Do not put a redirect to HTTPS inside the HTTPS server blocks. Do not use a single server block with if ($host = ...) and rewrite for both www and non-www, that often causes loops. After editing, run sudo nginx -t then sudo systemctl reload nginx.
Fixing a redirect loop in Apache (.htaccess)
Rule order matters. If you have both “force HTTPS” and “force www” (or “force non-www”), they can conflict. Decide on one final URL (e.g. https://example.com) and do a single redirect to it. For example, first force HTTPS, then in a separate rule force the canonical host, but ensure the second rule doesn’t match the first rule’s target, or you get a loop.
Example: canonical is https://example.com. Force HTTPS first, then send www to non-www:
RewriteEngine On
# 1) HTTP → HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# 2) www → non-www (only when already HTTPS to avoid double redirect)
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [L,R=301]If your server is behind a proxy, %{HTTPS} may always be off; in that case use RewriteCond %{HTTP:X-Forwarded-Proto} !https for the HTTPS check. Keep rule order clear so you never redirect the canonical URL back to the non-canonical one.
Fixing a redirect loop with Cloudflare
If you use Cloudflare and get a loop, usually both Cloudflare and your origin are redirecting. Cloudflare’s docs recommend: do not do HTTP→HTTPS redirect at the origin when “Always Use HTTPS” is on at Cloudflare, otherwise the request can bounce (Cloudflare sends to origin on HTTP, origin redirects to HTTPS, repeat). Either:
- Turn on Always Use HTTPS in Cloudflare (SSL/TLS → Edge Certificates) and remove the HTTP→HTTPS redirect from your origin, or
- Turn off Always Use HTTPS at Cloudflare and do the redirect only at your origin.
For www vs non-www, use a single Redirect Rule in Cloudflare that sends (e.g.) https://www.example.com/* to https://example.com/$1 with 301. Don’t also redirect non-www to www at the origin if Cloudflare is sending www to non-www, or you can get a loop.
How to verify the fix
After you change config, clear cache or use a private window, then try both http:// and https:// and both www and non-www. You should land on the same canonical URL with no loop. Run your domain through our HTTPS checker again, the chain should be short and end on the expected URL, with no repeated entries.
Stuck? We’re happy to point you in the right direction or suggest next steps.
Contact us