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 那一行代入请求路径,循环就清楚了:
- 浏览器请求
https://example.com/,第 (1) 段是 HTTPS。 - Flexible 模式下,Cloudflare 用 HTTP 去请求源站
http://example.com/。 - 源站的 Nginx 或应用配置了“HTTP 一律 301 到 HTTPS”,于是回一个
Location: https://example.com/。 - 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 在静默模式下仍输出错误信息):
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 缓存头怎么配。
第二步:绕过 Cloudflare 直接问源站
用 --resolve 把域名指到源站 IP,就能看到源站在 HTTP 和 HTTPS 两种情况下各自怎么回应。把 203.0.113.10 换成你的源站地址:
# 模拟 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 错误码速查。
如果 --resolve 不确定该填哪个 IP,或怀疑本地解析被改过,先按 DNS 污染和 DNS 劫持的判断方法 确认解析结果。
第三步:五个常见成因逐项检查
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):
wp option get siteurl
wp option get home
两者都应该是 https:// 开头,并且与你实际使用的主机名(带不带 www)一致。最省事的修法仍然是切到 Full (strict),让 WordPress 真正收到 HTTPS 请求。如果暂时做不到,可以在 wp-config.php 里 require_once ABSPATH . 'wp-settings.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 信任,专门用于边缘到源站这一段。步骤如下:
- 控制台进入 SSL/TLS → Origin Server,点 Create Certificate。
- 选择由 Cloudflare 生成私钥,密钥类型 RSA 或 ECC 均可;主机名填
example.com和*.example.com;有效期按需选择(最长可达 15 年,具体选项以控制台为准)。 - 生成后页面会显示证书和私钥。私钥只显示这一次,立即保存到源站:
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
- 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;。
sudo nginx -t && sudo systemctl reload nginx,然后回控制台把模式改成 Full (strict)。- 再跑一遍第一步的 curl:请求
https://地址应直接 200;请求http://地址应只有一次 301 到 HTTPS,然后 200。 - 要从本机验证源站证书,从 Cloudflare 官方文档下载 Origin CA 根证书(RSA 或 ECC,与第 2 步的密钥类型对应),用它代替系统信任库:
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 限速与回源保护怎么配。
修完之后的检查表
- 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 状态页 每 15 分钟同步一次 Cloudflare 官方状态页,可以顺手看看当时有没有区域性事件;想比较各家公共 CDN 在国内的连接表现,可以看 CDN 速度榜 和 国内怎么选公共 CDN。更完整的本地网络排查顺序在 开发者网络自检清单(2026 版)。需要基于 Cloudflare 网络做边缘加速的团队,可以看 cdnping Edge 的介绍;中国大陆境内加速需要 ICP 备案,并经由持证服务商。