---
title: "Cloudflare 重定向次数过多怎么办：SSL 模式选错导致的循环与修复"
description: "Cloudflare 重定向次数过多多半是 SSL 模式与源站跳转冲突。讲清 Flexible、Full、Full (strict) 的区别，附 curl 排查步骤和 Origin CA 证书的 Nginx 配置。"
url: https://cdnping.org/blog/cloudflare-too-many-redirects-ssl-mode
language: zh-CN
published: 2026-10-24
category: "边缘与 CDN"
tags: ["Cloudflare","HTTPS","SSL/TLS","Nginx","排障"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# Cloudflare 重定向次数过多怎么办：SSL 模式选错导致的循环与修复

站点刚接入 Cloudflare，浏览器就报“重定向次数过多”（ERR_TOO_MANY_REDIRECTS），最常见的原因是 SSL/TLS 加密模式设成了 Flexible，而源站自己又在把 HTTP 跳到 HTTPS。临时的修法是把模式改成 Full；长期应该给源站装上证书，改用 Full (strict)。如果改了模式还在循环，就用下面的 curl 命令看清 Location 链，看是哪一跳在兜圈子。

## Flexible、Full、Full (strict) 到底差在哪？

Cloudflare 代理（橙色云朵）开启后，一次访问分成两段连接：浏览器到 Cloudflare 边缘，边缘到你的源站。SSL 模式只管第二段怎么走。

```
浏览器 ──(1)──> Cloudflare 边缘 ──(2)──> 源站
```

| 模式 | 第 (2) 段协议 | 是否校验源站证书 | 适用情况 |
|---|---|---|---|
| Off | HTTP | 不涉及 | 不建议使用 |
| Flexible | 始终 HTTP（80 端口） | 不涉及 | 源站完全没有 HTTPS 时的过渡 |
| Full | 跟随访客协议，访客走 HTTPS 时用 HTTPS（443） | 不校验，自签名或过期证书也能通 | 源站有证书但还不合规时的过渡 |
| Full (strict) | 同 Full | 校验：证书须由公共 CA 或 Cloudflare Origin CA 签发、未过期、域名匹配 | 推荐的长期配置 |

较新接入的域名可能默认是“自动”模式，Cloudflare 会探测源站能力后替你选。具体选项名称以控制台 SSL/TLS → Overview 页面为准。

## 为什么 Flexible 会造成无限重定向？

把上表的 Flexible 那一行代入请求路径，循环就清楚了：

1. 浏览器请求 `https://example.com/`，第 (1) 段是 HTTPS。
2. Flexible 模式下，Cloudflare 用 HTTP 去请求源站 `http://example.com/`。
3. 源站的 Nginx 或应用配置了“HTTP 一律 301 到 HTTPS”，于是回一个 `Location: https://example.com/`。
4. Cloudflare 把这个 301 原样交给浏览器，浏览器再请求 `https://example.com/`，回到第 1 步。

源站看到的永远是 HTTP，所以它会一直跳；浏览器看到的永远是 HTTPS，所以它会一直跟。Chrome 和 Firefox 默认在跟了 20 次左右后放弃，报出这个错误。

同样的结构还会以别的形式出现：源站把 HTTPS 跳回 HTTP，而 Cloudflare 又开着 Always Use HTTPS；或者重定向规则让 `www` 跳到裸域，源站又让裸域跳回 `www`。共同点是两个环节对“正确的地址”意见不一致。

## 第一步：用 curl 看清 Location 链

浏览器会缓存 301，排查时先别用它，直接用 curl。下面的命令跟随跳转，只打印每一跳的状态码和关键头（`-S` 让 curl 在静默模式下仍输出错误信息）：

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

一段典型的 Flexible 循环输出长这样（示例）：

```
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
```

怎么读：

- **Location 指向自己**：请求 `https://example.com/` 却被要求跳到 `https://example.com/`，基本可以断定是协议不一致，优先查 SSL 模式。
- **两个地址来回切换**（`www` 和裸域，或 `http` 和 `https`）：是两条规则互相打架，下面第三节逐个查。
- **跳转出自谁**：经过 Cloudflare 的响应 `server` 头都显示 `cloudflare`，不能靠它区分。如果同时带着源站才有的头（如 `x-powered-by`、应用自定义头），说明 301 是源站发的；只有 Cloudflare 的头而没有源站痕迹，多半是 Always Use HTTPS、Redirect Rules 或 Page Rules 发的。
- **`cf-cache-status: HIT`**：301 被边缘缓存了，改完配置要去 Caching → Configuration 清缓存，否则看起来“没生效”。缓存规则可以参考 [Cache-Control 缓存头怎么配](/blog/cache-control-headers-guide-cdn)。

## 第二步：绕过 Cloudflare 直接问源站

用 `--resolve` 把域名指到源站 IP，就能看到源站在 HTTP 和 HTTPS 两种情况下各自怎么回应。把 `203.0.113.10` 换成你的源站地址：

```bash
# 模拟 Flexible：Cloudflare 用 HTTP 回源
curl -sI --resolve example.com:80:203.0.113.10 http://example.com/

# 模拟 Full：Cloudflare 用 HTTPS 回源（-k 忽略证书，只看跳转）
curl -skI --resolve example.com:443:203.0.113.10 https://example.com/

# 检查源站证书能否通过 Full (strict) 的校验（去掉 -k）
curl -sI --resolve example.com:443:203.0.113.10 https://example.com/
```

判断方法：

| 第一条结果 | 第二条结果 | 结论 |
|---|---|---|
| 301 到 https | 200 | 源站有 HTTPS，改成 Full 或 Full (strict) 即可 |
| 301 到 https | 连接失败 | 源站 443 没监听，先装证书，或临时关掉源站的强制跳转 |
| 200 | 301 到 http | 源站把 HTTPS 往回跳，配合 Always Use HTTPS 会循环，去掉源站这条规则 |
| 200 | 200 | 源站没问题，去查 Cloudflare 侧的规则 |

第三条命令如果报证书错误，说明源站证书不是公共 CA 签发的，或已过期、域名不匹配，这时开 Full (strict) 会得到 526 错误，需要先换证书。例外是 Cloudflare Origin CA 证书：它不被 curl 默认信任，第三条命令同样会报错，要用 `--cacert` 指定 Cloudflare 官方文档提供的 Origin CA 根证书再测（见后文）。Cloudflare 边缘返回的其他 5xx，例如 502、524，可以对照 [大模型 API 错误码速查](/blog/ai-api-error-codes-400-to-529-cheatsheet)。

如果 `--resolve` 不确定该填哪个 IP，或怀疑本地解析被改过，先按 [DNS 污染和 DNS 劫持的判断方法](/blog/dns-pollution-vs-hijacking-detect) 确认解析结果。

## 第三步：五个常见成因逐项检查

### 1. SSL 模式是 Flexible，源站又强制 HTTPS

最常见。控制台 SSL/TLS → Overview 改成 Full，清缓存，再跑一遍第一步的 curl。源站有有效证书就直接用 Full (strict)。

### 2. Always Use HTTPS 和源站的反向跳转冲突

SSL/TLS → Edge Certificates 里的 Always Use HTTPS 会在边缘把 HTTP 请求 301 到 HTTPS。如果源站有一条“HTTPS 跳 HTTP”的旧规则（常见于早年为了省证书写的配置），两边会来回推。删掉源站那条规则。

### 3. 源站自己的 301 判断依据不对

Nginx 里常见的写法是在 80 端口的 server 块里 `return 301 https://$host$request_uri;`。这在 Full 模式下没问题，因为 HTTPS 访客对应的回源请求走 443。但如果源站前面还有一层反向代理，按 `$scheme` 判断协议就会出错。经过 Cloudflare 的请求会带 `X-Forwarded-Proto` 和 `CF-Visitor: {"scheme":"https"}`，应用层应读这两个头来判断访客协议，或者干脆让 Cloudflare 负责跳转，源站不再跳。

### 4. WordPress 的 siteurl 和 home

WordPress 会把请求跳到数据库里登记的地址。Flexible 模式下它收到的是 HTTP 请求，`is_ssl()` 返回 false，于是不断把用户送回 HTTPS。先查当前值（需要服务器上装有 WP-CLI）：

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

两者都应该是 `https://` 开头，并且与你实际使用的主机名（带不带 `www`）一致。最省事的修法仍然是切到 Full (strict)，让 WordPress 真正收到 HTTPS 请求。如果暂时做不到，可以在 `wp-config.php` 里 `require_once ABSPATH . 'wp-settings.php';` 之前加上：

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

这只是过渡办法，源站依旧是明文回源。

### 5. www 与非 www 规则互相指向

例如 Cloudflare 的 Redirect Rules 把 `www.example.com` 跳到 `example.com`，而 Nginx 的 `server_name` 配置或 CMS 的站点地址又把裸域跳回 `www`。curl 输出里两个主机名交替出现就是这种情况。只保留一处负责规范主机名，建议放在 Cloudflare 规则里，源站只管返回内容。

## 为什么长期应该用 Full (strict)？

Flexible 只加密了浏览器到边缘这一段，边缘到源站仍是明文，访客的表单、Cookie 在这一段可以被沿途网络看到，而浏览器地址栏显示的是锁。Full 加密了第二段，但不校验证书，中间人用任意自签名证书都能冒充源站。Full (strict) 两段都加密，并确认对端确实是你的服务器。

另一个实际好处是排障简单：协议在两段上一致，源站看到的 scheme 就是访客的 scheme，前面第 3、4 条那类问题基本不会再出现。

## 怎么签发 Cloudflare Origin CA 证书并在 Nginx 配置？

Origin CA 证书免费，只被 Cloudflare 信任，专门用于边缘到源站这一段。步骤如下：

1. 控制台进入 SSL/TLS → Origin Server，点 Create Certificate。
2. 选择由 Cloudflare 生成私钥，密钥类型 RSA 或 ECC 均可；主机名填 `example.com` 和 `*.example.com`；有效期按需选择（最长可达 15 年，具体选项以控制台为准）。
3. 生成后页面会显示证书和私钥。私钥只显示这一次，立即保存到源站：

```bash
sudo mkdir -p /etc/ssl/cloudflare
sudo nano /etc/ssl/cloudflare/example.com.pem   # 粘贴证书
sudo nano /etc/ssl/cloudflare/example.com.key   # 粘贴私钥
sudo chmod 600 /etc/ssl/cloudflare/example.com.key
```

4. Nginx 配置：

```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;
    }
}
```

较旧版本的 Nginx 不支持单独的 `http2 on;`，改成 `listen 443 ssl http2;`。

5. `sudo nginx -t && sudo systemctl reload nginx`，然后回控制台把模式改成 Full (strict)。
6. 再跑一遍第一步的 curl：请求 `https://` 地址应直接 200；请求 `http://` 地址应只有一次 301 到 HTTPS，然后 200。
7. 要从本机验证源站证书，从 Cloudflare 官方文档下载 Origin CA 根证书（RSA 或 ECC，与第 2 步的密钥类型对应），用它代替系统信任库：

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

两点注意：Origin CA 证书不被浏览器信任，一旦把 DNS 记录切到灰色云朵（仅 DNS），访客会直接看到证书错误；如果还想限制只有 Cloudflare 能连源站，可以在此基础上开启 Authenticated Origin Pulls，或在防火墙只放行 Cloudflare 公布的 IP 段。回源保护的其他做法见 [用 Cloudflare 加速 AI 应用：缓存、API 限速与回源保护怎么配](/blog/cloudflare-edge-for-ai-apps)。

## 修完之后的检查表

- [ ] SSL/TLS 模式为 Full (strict)
- [ ] `curl -sIL https://example.com/` 没有跳转或最多一跳，最终 200
- [ ] `curl -sIL http://www.example.com/` 跳到规范地址后 200，没有来回
- [ ] 直连源站 443 校验证书通过（公共 CA 证书直接去掉 `-k`；Origin CA 证书用 `--cacert` 指定根证书）
- [ ] 改配置后清过 Cloudflare 缓存，浏览器用无痕窗口复测
- [ ] 源站只有一处负责 HTTPS 跳转，只有一处负责主机名规范化

如果配置都对，访问仍然时好时坏，问题可能不在你这边。cdnping 的 [API 状态页](/status) 每 15 分钟同步一次 Cloudflare 官方状态页，可以顺手看看当时有没有区域性事件；想比较各家公共 CDN 在国内的连接表现，可以看 [CDN 速度榜](/benchmark/cdn) 和 [国内怎么选公共 CDN](/learn/choose-public-cdn-china)。更完整的本地网络排查顺序在 [开发者网络自检清单（2026 版）](/blog/developer-network-self-check-2026)。需要基于 Cloudflare 网络做边缘加速的团队，可以看 [cdnping Edge](/edge) 的介绍；中国大陆境内加速需要 ICP 备案，并经由持证服务商。
