Aditya Sharma

WordPress Too Many Redirects: Trace the Loop With curl First

On this page, 7 sections

“Too many redirects” on WordPress means two things on the path to your site are each redirecting the request to the other’s version, and they never agree. The browser follows the chain until it gives up and shows ERR_TOO_MANY_REDIRECTS. Typical pairs are HTTP against HTTPS, www against no www, or a trailing slash against none.

Do not start by deleting cookies or plugins. Run one command that prints the whole chain, then read it. The chain tells you which two layers are fighting.

Step 1: Print the redirect chain

From a terminal, follow the redirects, throw the page body away, print every response’s headers, and cap the hops so the command stops. This sends GET requests, because some servers redirect HEAD requests differently:

curl -sL -o /dev/null -D - --max-redirs 10 https://example.com/ | grep -iE "^(HTTP|location|server|cf-ray)"

Replace the address with the one that fails. The output is a list of status lines and location headers. You are looking for a repeat: the same two addresses, one after the other.

Read the pattern:

  • http://example.com/ sends you to https://example.com/, and that sends you back to http://example.com/. This is a protocol loop.
  • https://example.com/ sends you to https://www.example.com/, and that sends you back. This is a host loop.
  • The server or cf-ray lines can hint at which layer answered. A cf-ray header means the response passed through Cloudflare. It does not prove Cloudflare wrote the redirect, because Cloudflare adds its own headers to responses that your origin generated. To separate the two, compare with a request that goes straight to the origin address.

I have not run this against a looping site for this article. The command is ordinary curl usage. The part that matters is that it shows each hop’s location, and the headers tell you who sent it.

Why the loop happens: WordPress and its neighbours both redirect

WordPress has its own redirect logic. redirect_canonical() in wp-includes/canonical.php builds the address WordPress thinks is the correct one and sends a 301 when the request differs. It has a www against no www comparison, and it begins by using is_ssl() to decide whether the requested address is HTTP or HTTPS. I read the file on 11 October 2026.

That makes is_ssl() the key function. In wp-includes/load.php it returns true in two cases: the server variable HTTPS is on or 1, or the server port is 443. I found no other check in the function. In particular, it does not look at the X-Forwarded-Proto header that a proxy or CDN adds.

So when SSL ends at a proxy and the proxy talks plain HTTP to your server, WordPress sees every request as HTTP. If your site address is set to https://, WordPress redirects to HTTPS, the proxy forwards the next request over HTTP again, and the loop starts.

The causes, in the order I would check them

1. Cloudflare’s encryption mode

Cloudflare’s own page on this error says redirect loops after adding a domain come from three areas: the SSL/TLS encryption mode, the settings on the Edge Certificates page, and redirect rules. The page was marked last updated on 1 September 2026 when I read it.

Two of its cases matter for WordPress:

  • Flexible mode. Cloudflare connects to your origin over plain HTTP. If your origin or a WordPress setting redirects all HTTP requests to HTTPS, you get a loop. Cloudflare’s fix is to remove the HTTPS redirect from the origin, or change the mode to Full or higher, which needs a certificate on the origin.
  • Full or Full (strict) mode. Cloudflare connects over HTTPS. If your origin redirects HTTPS to HTTP, you get a loop. The fix is to remove that redirect.

The same page covers “Always Use HTTPS” and HTTP Strict Transport Security with the same shape: a loop appears when the origin redirects the opposite way, or when the encryption mode is Off.

Check the mode in the Cloudflare dashboard under SSL/TLS before you touch WordPress.

2. WordPress cannot tell the request was HTTPS

If the site sits behind a proxy or load balancer that ends SSL, make WordPress recognise it. WordPress’s HTTPS guide says that behind a reverse proxy that provides SSL, with the site itself running without SSL, the force-HTTPS options send requests into an infinite loop. Its suggested fix is a block in wp-config.php that reads the forwarded protocol header:

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
    && false !== strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) ) {
    $_SERVER['HTTPS'] = 'on';
}

Put this above the line that says “That’s all, stop editing” and save. The guide’s version uses strpos( ... ) !== false, because the header can hold a comma separated list such as http,https. Only do this if you trust the proxy that sets the header, because a visitor can send a fake header to a server that is reachable directly.

3. The two WordPress addresses disagree

WordPress stores a WordPress Address and a Site Address under Settings, General. If one is http:// and the other is https://, or one has www and the other does not, redirect_canonical() will keep trying to reach the other form.

If you cannot log in, read them with WP-CLI:

wp option get siteurl
wp option get home

Make them match, including the scheme and the www. If the site also defines WP_HOME or WP_SITEURL in wp-config.php, check those too. I did not verify in this session which of the two sources WordPress prefers, so make all of them agree.

4. A redirect in the web server config or .htaccess

A rule added by you, a host, or an SSL plugin can force HTTPS or force www. Two rules that disagree, or one rule and a CDN setting that disagree, make a loop. Open .htaccess and look for rewrite rules that mention HTTPS or a host name. Comment out the extra ones one at a time and run the curl command again after each change.

5. A plugin that redirects

SSL, redirection and security plugins can add their own redirects. If the chain shows the same hop on every try and the config is clean, rename the wp-content/plugins folder to turn all plugins off at once.

If the loop stops, rename it back and then disable plugins one at a time. This is a diagnostic step, not a fix. Do it on a staging copy if you can.

6. Cached redirects

A 301 is allowed to be cached by browsers and CDNs. After you fix the cause, the old redirect can still be served. Test in a private window or with curl, which does not cache, and purge the CDN. My guide to 301 errors in WordPress is the sibling article on single redirects.

Which layer sent the redirect

The curl output answers it. Run the command and look at the headers on the hop that redirects. Then run it again straight against the origin, if your host gives you its address. If the loop disappears when you bypass the CDN, the CDN’s settings or rules are involved. If it stays, look at the origin config and WordPress.

Choosing a CDN for WordPress explains what each layer in that stack is responsible for.

Questions people ask

Can I fix it from the browser alone?

Clearing cookies helps only when the loop comes from a login cookie. If the same address fails in a private window, the loop is in the server or CDN, and the browser is not the cause.

What is the redirect limit?

Browsers stop after a fixed number of hops and show the error. I did not verify the exact number for each browser, so I do not quote one. The curl command above uses a limit of 10 so it stops by itself.

Why did it start after I enabled SSL?

Turning on HTTPS adds a second redirect layer. If your site address, your proxy, your CDN and your web server do not agree on one final address, you get a loop. Cloudflare’s page lists the common mismatches.

Do this today

Run curl -sL -o /dev/null -D - --max-redirs 10 on the address that fails, paste the output somewhere, and mark the two addresses that repeat. Then fix the layer that sends the second one.

Resources

Tell me where I am wrong

Your email is not published and I do not add it to any list. Corrections with a source are the ones I act on fastest.