网站提示 ERR_TOO_MANY_REDIRECTS、重定向次数过多,先别重装 VPS,也别把所有 HTTPS 开关都关掉。先看每次响应的 Location:是 HTTP 和 HTTPS 来回跳,还是 www 与裸域名互相跳,或者登录页一直跳回自己?这三种情况的修复位置不同。
本文面向使用 Nginx、Cloudflare 或 WordPress 的站长。命令中的 example.com 要换成你的域名;配置示例用于说明修改位置,不要覆盖现有证书、网站根目录或应用配置。本文提供诊断步骤,没有把示例输出当作真实站点实测。
在电脑或 VPS 上运行下面两条命令。第一条只看首次响应,第二条使用 GET 跟随跳转,最多 10 次,不下载页面正文到终端:
curl -sS -D - -o /dev/null https://example.com/
curl -sS -L --max-redirs 10 -D - -o /dev/null https://example.com/
重点看状态行与 Location。到达上限时 curl 会报错,这正是需要保留的证据,不要通过提高上限“修复”。用 GET 是因为部分应用对 HEAD 的处理不同。
| 跳转表现 | 优先检查 | 常见处理方向 |
|---|---|---|
| HTTP → HTTPS → HTTP | CDN 回源协议、源站跳转 | 统一 HTTPS,核对 SSL 模式 |
| example.com → www → example.com | CDN、Nginx、应用主域名 | 所有层使用同一个规范域名 |
| HTTPS 同一 URL 不断返回 301/302 | 应用是否识别外部 HTTPS | 检查代理头与可信代理设置 |
| 登录页 → 后台 → 登录页 | Cookie、会话、登录插件 | 单独检查身份验证链路 |
| 只有旧浏览器会循环 | 缓存的跳转与站点数据 | 修好服务器规则后再清理 |
Server: cloudflare 只说明响应经过 Cloudflare,不能单凭这一行认定跳转由它生成。源站返回的跳转也可能经 CDN 转发。保存出现问题的完整路径、发生时间和每一跳,再与源站访问日志对照。
这是接入 CDN 后突然打不开网站的一种典型原因。浏览器用 HTTPS 访问 Cloudflare,但 Flexible 模式下 Cloudflare 使用 HTTP 回源;源站要求 HTTPS,返回跳转,Cloudflare 下一次仍以 HTTP 回源,于是循环。
Cloudflare 官方排障文档明确说明了这个组合。排查时到域名的 SSL/TLS 设置核对当前加密模式,同时检查源站 80 端口是否强制跳转。
如果网站需要登录或提交数据,先配置源站有效证书、443 监听和正确域名,再使用 Full (strict) 完成两段加密与证书验证。不要在源站尚未具备 HTTPS 时直接切换;否则可能从重定向循环变成握手或证书错误。已经出现这类错误时,按 Cloudflare 525 / 526 排查指南继续定位。
Full (strict) 下源站若又把 HTTPS 重定向回 HTTP,同样会与边缘强制 HTTPS 规则冲突。检查两边规则的方向,比反复切换 SSL 模式更有用。Cloudflare Tunnel 的本地服务连接另有配置,不能照搬普通橙云回源的判断。
先查看实际加载的配置,而不是只修改某个看起来像站点配置的文件:
sudo nginx -t
sudo nginx -T 2>&1 | less
在输出中检查对应 server_name、return 301、return 302、rewrite 和 proxy_set_header。nginx -T 可能包含内部地址或凭据,不要直接把完整输出贴进公开工单。
如果 CDN 把 www 跳到裸域名,而 Nginx 把裸域名跳到 www,两条规则各自都能通过语法检查,组合起来却永远到不了页面。先决定最终地址,例如 https://example.com,再让 CDN、Nginx 和应用使用它。临时修复时一次只调整一个位置,保留原配置供回滚。
对“外部 HTTPS 在这台 Nginx 终止,后端仅在本机 HTTP 监听”的结构,可在现有 HTTPS server 的代理 location 中核对下面这些字段:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
这只是 location 片段,假定后端确实监听 3000,且外层已有正确 TLS 配置。Nginx 官方文档说明 proxy_set_header 用于设置传给后端的请求头。应用仍需配置可信代理,才会按它判断外部协议。
如果 HTTPS 在更外层的负载均衡器终止,这台 Nginx 接收到的是 HTTP,$scheme 就是 http,照抄会把外部 HTTPS 信息覆盖掉。此时要在可信入口覆盖客户端提供的头,并按实际代理链传递协议;不要无条件信任公网请求中的 X-Forwarded-Proto。后端也应限制为只接受预期代理的连接。
修改后先执行 sudo nginx -t,成功后再执行 sudo systemctl reload nginx。语法正确不等于跳转逻辑正确,还要重新跑跳转链。
搬家或换域名后,WordPress 的公开站点地址、程序地址和 HTTPS 判断可能没有一起更新。先备份数据库与 wp-config.php,有 WP-CLI 时在站点目录以站点运行用户读取配置:
wp option get home
wp option get siteurl
核对协议、域名和路径。普通单站点部署通常应与预期地址一致,但 WordPress 安装在子目录时,两个路径可以合理不同,不能为了消除差异直接改成一样。还要检查 wp-config.php 是否定义了 WP_HOME、WP_SITEURL;这些常量可能覆盖后台选项。多站点则需要按网络配置单独排查。
WordPress 官方 HTTPS 文档指出,反向代理终止 HTTPS 后,WordPress 必须正确识别原始 HTTPS 状态,否则强制后台 HTTPS 可能形成循环。应按你的代理拓扑修复识别,并在加载 WordPress 设置前生效。不要在任何人都能直连的后端盲目信任转发头。
如果只有登录页面循环,先用无痕窗口复现,再检查 Cookie 的域名、Secure 属性、站点地址和会话存储。不要一上来关闭所有插件;优先检查最近启用的 SSL、缓存、重定向和登录插件,一次停用一个并记录结果。迁移后出现的问题,也可对照 WordPress 搬家与回滚清单。
知道源站 IP、且允许从当前机器访问时,可以保留域名和 TLS SNI,直接测试源站。下面使用文档保留地址,必须替换成真实源站地址:
curl --resolve example.com:443:203.0.113.10 -sS -D - -o /dev/null https://example.com/
不要先加 -L,先看源站第一跳,避免跳到其他主机后混淆结果。也不要用 -k 的成功证明证书正常。Cloudflare Origin CA 证书默认不被普通 curl 信任,直接测试可能报证书错误;这与浏览器经 Cloudflare 访问是不同的信任路径,应使用正确 CA 验证或从授权位置检查。
源站第一跳正常、经 CDN 才循环,优先检查边缘跳转规则和回源模式;源站也不断跳,检查 Nginx 与应用。若源站只允许 Cloudflare 访问,直连失败本身不能证明服务故障,不必为了测试放开所有公网来源。
- HTTP、HTTPS、www、裸域名四种入口都能到达预期地址,没有循环。
- 最终页面返回预期状态;需要登录的页面允许跳登录页,但登录后能正常返回。
- 首页、后台、回调路径和一个深层页面都测试过,路径与查询参数未被错误丢弃。
- 新无痕窗口正常后,再清理受影响浏览器的站点数据;服务器或 CDN 缓存按需精确清理。
- 每一层的规范域名和协议一致,保留修改前配置,确认没有把修复变成证书错误。
“清 Cookie”可以验证是否只是旧会话问题,却修不好服务器上的循环规则。先抓两次重复出现的 Location,确定冲突层,再改一项并重新测试,通常比同时切换多个 HTTPS 开关更容易找到原因。
