---
title: "Cloudflare Too Many Redirects: Fix the SSL Mode Redirect Loop"
description: "Cloudflare's too many redirects error usually means an SSL mode clash with your origin. Compare Flexible, Full and Full (strict), debug with curl, fix it."
url: https://cdnping.org/en/blog/cloudflare-too-many-redirects-ssl-mode
language: en
published: 2026-10-24
category: "Edge & CDN"
tags: ["Cloudflare","HTTPS","SSL/TLS","Nginx","Troubleshooting"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# Cloudflare Too Many Redirects: Fix the SSL Mode Redirect Loop

If your site just went behind Cloudflare and the browser shows "too many redirects" (ERR_TOO_MANY_REDIRECTS), the most common cause is an SSL/TLS encryption mode set to Flexible while your origin is also redirecting HTTP to HTTPS. The quick fix is to switch the mode to Full. The long-term fix is to install a certificate on the origin and use Full (strict). If the loop continues after you change the mode, use the curl commands below to read the Location chain and find which hop is going in circles.

## What's the difference between Flexible, Full, and Full (strict)?

With the Cloudflare proxy on (the orange cloud), each visit is split into two connections: browser to Cloudflare edge, and edge to your origin. The SSL mode only controls how the second leg works.

```
Browser ──(1)──> Cloudflare edge ──(2)──> Origin
```

| Mode | Protocol on leg (2) | Validates origin certificate? | When to use |
|---|---|---|---|
| Off | HTTP | N/A | Not recommended |
| Flexible | Always HTTP (port 80) | N/A | Stopgap when the origin has no HTTPS at all |
| Full | Follows the visitor's protocol; HTTPS (443) when the visitor uses HTTPS | No; self-signed or expired certificates still work | Stopgap when the origin has a certificate that isn't valid yet |
| Full (strict) | Same as Full | Yes: certificate must be issued by a public CA or Cloudflare Origin CA, unexpired, and match the hostname | Recommended long-term setup |

Newer domains may default to an "Automatic" mode, where Cloudflare probes what your origin supports and picks for you. Check the SSL/TLS → Overview page in the dashboard for the exact option names.

## Why does Flexible cause an infinite redirect?

Plug the Flexible row from the table into the request path and the loop becomes clear:

1. The browser requests `https://example.com/`, so leg (1) is HTTPS.
2. In Flexible mode, Cloudflare requests `http://example.com/` from the origin over HTTP.
3. The origin's Nginx or application is configured to "301 all HTTP to HTTPS", so it responds with `Location: https://example.com/`.
4. Cloudflare passes that 301 to the browser unchanged, the browser requests `https://example.com/` again, and we are back at step 1.

The origin only ever sees HTTP, so it keeps redirecting. The browser only ever sees HTTPS, so it keeps following. Chrome and Firefox give up after about 20 redirects and show this error.

The same structure shows up in other forms: the origin redirects HTTPS back to HTTP while Cloudflare has Always Use HTTPS on, or a redirect rule sends `www` to the apex domain while the origin sends the apex back to `www`. In every case, two components disagree about what the correct address is.

## Step 1: Read the Location chain with curl

Browsers cache 301s, so don't debug with one. Use curl instead. The command below follows redirects and prints only the status code and key headers for each hop (`-S` makes curl still show errors in silent mode):

```bash
curl -sSIL --max-redirs 8 https://example.com/ \
  | grep -iE '^(HTTP/|location:|server:|cf-cache-status:|x-powered-by:)'
```

A typical Flexible loop looks like this (example):

```
HTTP/2 301
server: cloudflare
location: https://example.com/
x-powered-by: PHP/8.x
HTTP/2 301
server: cloudflare
location: https://example.com/
...
curl: (47) Maximum (8) redirects followed
```

How to read it:

- **Location points to itself**: you requested `https://example.com/` and were told to go to `https://example.com/`. This almost certainly means a protocol mismatch, so check the SSL mode first.
- **Two addresses alternating** (`www` and apex, or `http` and `https`): two rules are fighting each other. Section 3 below walks through them one by one.
- **Who issued the redirect**: every response that passes through Cloudflare shows `server: cloudflare`, so that header can't tell you. If the response also carries headers only your origin would add (such as `x-powered-by` or custom application headers), the 301 came from the origin. If you see only Cloudflare headers and no trace of the origin, it was most likely Always Use HTTPS, Redirect Rules, or Page Rules.
- **`cf-cache-status: HIT`**: the 301 was cached at the edge. After you fix the configuration, purge the cache under Caching → Configuration, or it will look like the change didn't take effect. For caching rules, see [How to set Cache-Control headers for a CDN](/en/blog/cache-control-headers-guide-cdn).

## Step 2: Bypass Cloudflare and ask the origin directly

Use `--resolve` to point the hostname at your origin IP and see how the origin responds over HTTP and HTTPS separately. Replace `203.0.113.10` with your origin address:

```bash
# Simulate Flexible: Cloudflare connects to the origin over HTTP
curl -sI --resolve example.com:80:203.0.113.10 http://example.com/

# Simulate Full: Cloudflare connects to the origin over HTTPS (-k ignores the certificate; we only want the redirect behavior)
curl -skI --resolve example.com:443:203.0.113.10 https://example.com/

# Check whether the origin certificate would pass Full (strict) validation (no -k)
curl -sI --resolve example.com:443:203.0.113.10 https://example.com/
```

How to interpret the results:

| First result | Second result | Conclusion |
|---|---|---|
| 301 to https | 200 | The origin has HTTPS. Switch to Full or Full (strict) |
| 301 to https | Connection fails | Nothing is listening on port 443. Install a certificate first, or temporarily disable the origin's forced redirect |
| 200 | 301 to http | The origin redirects HTTPS back to HTTP, which loops when combined with Always Use HTTPS. Remove that origin rule |
| 200 | 200 | The origin is fine. Look at the Cloudflare-side rules |

If the third command reports a certificate error, the origin certificate wasn't issued by a public CA, has expired, or doesn't match the hostname. Turning on Full (strict) would then give you a 526 error, so replace the certificate first. The exception is a Cloudflare Origin CA certificate: curl doesn't trust it by default, so the third command fails for it too. Retest with `--cacert` pointing at the Origin CA root certificate from Cloudflare's official documentation (see below). For other 5xx errors returned by the Cloudflare edge, such as 502 and 524, see the [LLM API error code cheat sheet](/en/blog/ai-api-error-codes-400-to-529-cheatsheet).

If you're not sure which IP to use for `--resolve`, or you suspect local DNS has been tampered with, first confirm the resolution result using [How to tell DNS pollution from DNS hijacking](/en/blog/dns-pollution-vs-hijacking-detect).

## Step 3: Check the five common causes

### 1. SSL mode is Flexible and the origin forces HTTPS

This is the most common one. In the dashboard, change SSL/TLS → Overview to Full, purge the cache, and rerun the curl from Step 1. If the origin has a valid certificate, go straight to Full (strict).

### 2. Always Use HTTPS conflicts with a reverse redirect on the origin

Always Use HTTPS under SSL/TLS → Edge Certificates 301s HTTP requests to HTTPS at the edge. If the origin has an old "HTTPS to HTTP" rule (common in configs written years ago to avoid buying a certificate), the two sides push the request back and forth. Delete that origin rule.

### 3. The origin's own 301 logic checks the wrong thing

A common Nginx pattern is `return 301 https://$host$request_uri;` in the port 80 server block. That's fine in Full mode, because origin requests for HTTPS visitors arrive on 443. But if there's another reverse proxy in front of the origin, deciding the protocol from `$scheme` will go wrong. Requests through Cloudflare carry `X-Forwarded-Proto` and `CF-Visitor: {"scheme":"https"}`. The application layer should read one of these headers to determine the visitor's protocol, or you can let Cloudflare handle the redirect and stop redirecting on the origin entirely.

### 4. WordPress siteurl and home

WordPress redirects requests to the address stored in its database. In Flexible mode it receives HTTP requests, `is_ssl()` returns false, and it keeps sending users back to HTTPS. Check the current values first (requires WP-CLI on the server):

```bash
wp option get siteurl
wp option get home
```

Both should start with `https://` and match the hostname you actually use (with or without `www`). The simplest fix is still to switch to Full (strict) so WordPress actually receives HTTPS requests. If you can't do that yet, add this to `wp-config.php` before the line `require_once ABSPATH . 'wp-settings.php';`:

```php
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}
```

This is only a stopgap. The origin leg is still plaintext.

### 5. www and non-www rules point at each other

For example, a Cloudflare Redirect Rule sends `www.example.com` to `example.com`, while the Nginx `server_name` config or the CMS site address sends the apex back to `www`. If both hostnames alternate in your curl output, this is what's happening. Keep one place responsible for canonicalizing the hostname, preferably a Cloudflare rule, and let the origin just serve content.

## Why should you use Full (strict) long term?

Flexible only encrypts the browser-to-edge leg. The edge-to-origin leg stays plaintext, so form data and cookies can be read by networks along the path, while the browser's address bar still shows a padlock. Full encrypts the second leg but doesn't validate the certificate, so a man in the middle can impersonate your origin with any self-signed certificate. Full (strict) encrypts both legs and confirms the other end really is your server.

There's also a practical debugging benefit: the protocol is the same on both legs, so the scheme the origin sees is the visitor's scheme, and problems like causes 3 and 4 above largely disappear.

## How do you issue a Cloudflare Origin CA certificate and configure Nginx?

Origin CA certificates are free and trusted only by Cloudflare, designed for the edge-to-origin leg. Steps:

1. In the dashboard, go to SSL/TLS → Origin Server and click Create Certificate.
2. Let Cloudflare generate the private key; RSA or ECC both work. Enter `example.com` and `*.example.com` as hostnames, and choose a validity period (up to 15 years; check the dashboard for the exact options).
3. After generation, the page shows the certificate and private key. The private key is shown only once, so save it to the origin immediately:

```bash
sudo mkdir -p /etc/ssl/cloudflare
sudo nano /etc/ssl/cloudflare/example.com.pem   # paste the certificate
sudo nano /etc/ssl/cloudflare/example.com.key   # paste the private key
sudo chmod 600 /etc/ssl/cloudflare/example.com.key
```

4. Nginx configuration:

```nginx
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name example.com www.example.com;

    ssl_certificate     /etc/ssl/cloudflare/example.com.pem;
    ssl_certificate_key /etc/ssl/cloudflare/example.com.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}
```

Older Nginx versions don't support a standalone `http2 on;`. Use `listen 443 ssl http2;` instead.

5. Run `sudo nginx -t && sudo systemctl reload nginx`, then go back to the dashboard and set the mode to Full (strict).
6. Rerun the curl from Step 1: the `https://` URL should return 200 directly, and the `http://` URL should give exactly one 301 to HTTPS and then 200.
7. To verify the origin certificate from your own machine, download the Origin CA root certificate from Cloudflare's official documentation (RSA or ECC, matching the key type from step 2) and use it in place of the system trust store:

```bash
curl -sI --cacert origin_ca_rsa_root.pem \
  --resolve example.com:443:203.0.113.10 https://example.com/
```

Two caveats. Origin CA certificates aren't trusted by browsers, so if you switch a DNS record to the gray cloud (DNS only), visitors will see certificate errors right away. And if you also want to restrict origin access to Cloudflare only, you can enable Authenticated Origin Pulls on top of this, or allow only Cloudflare's published IP ranges in your firewall. For other ways to protect the origin, see [Using Cloudflare for AI apps: caching, API rate limiting, and origin protection](/en/blog/cloudflare-edge-for-ai-apps).

## Checklist after the fix

- [ ] SSL/TLS mode is Full (strict)
- [ ] `curl -sIL https://example.com/` shows no redirect or at most one, ending in 200
- [ ] `curl -sIL http://www.example.com/` redirects to the canonical address, then 200, with no back-and-forth
- [ ] Direct connection to origin port 443 passes certificate validation (for public CA certificates just drop `-k`; for Origin CA certificates use `--cacert` with the root certificate)
- [ ] Cloudflare cache purged after the change, and retested in an incognito window
- [ ] Exactly one place on the origin handles the HTTPS redirect, and exactly one handles hostname canonicalization

If the configuration is all correct and access is still intermittent, the problem may not be on your side. The cdnping [API status page](/en/status) syncs with Cloudflare's official status page every 15 minutes, so you can check whether there was a regional incident at the time. To compare how public CDNs perform from mainland China, see the [CDN speed ranking](/en/benchmark/cdn) and [How to choose a public CDN for China](/en/learn/choose-public-cdn-china). A fuller order of operations for local network troubleshooting is in the [Developer network self-check list (2026 edition)](/en/blog/developer-network-self-check-2026). Teams that want edge acceleration built on Cloudflare's network can read about [cdnping Edge](/en/edge). Note that acceleration inside mainland China requires an ICP filing (China's mandatory website registration) and must go through a licensed provider.
