摘要:在解决国内局域网设备(玩客云 Armbian)跨境直连海外 VPS 晚高峰丢包 40% 的过程中,开启 Cloudflare CDN 代理(小黄云)本该是最直观的加速与抗丢包手段。然而,紧随其后的却是主站与个人博客双双陷入
ERR_TOO_MANY_REDIRECTS(301 死循环)、探针回源报Error 525、甚至遭遇 Cloudflare Enterprise 专属付费拦截的一系列连环踩坑。本文记录了从盲目排查到抓包溯源,最终揭开 Nginx Proxy Manager 底层机制并 100% 免费破局的完整实录。
一、 背景与起因:跨洋之痛与“随手开启的小黄云”
在我的家庭网络环境中,有一台刷了 Armbian 的玩客云小主机,负责日常爬虫采集与数据推送。为了监控各端节点的存活与网络健康状况,我在一台海外 VPS 上搭建了 Komari Monitor 监控服务以及个人 WordPress 博客,并通过玩客云上的客户端(komari-agent)持续向服务端上报心跳指标。
但跨国网络环境向来充满变数:每逢晚高峰(20:00 – 23:00),国内骨干网出口拥堵,玩客云直连海外 VPS 的链路丢包率飙升至 35% ~ 50%。监控面板上的玩客云频繁在“在线”与“离线”之间反复横跳,日志里充斥着心跳连接超时和 WebSocket 异常断开。
此时,最顺理成章的优化方案摆在眼前——Cloudflare CDN(小黄云)。
凭借 Cloudflare 优质的 Anycast 全球边缘网络,流量从国内经优化路由进入 Cloudflare 边缘节点,再通过其跨洋内网骨干回源到 VPS,不仅能够将丢包率压到接近 0%,还能为博客和面板提供免费的 Web 安全防护与静态资源加速。
我在 Cloudflare DNS 控制台找到 komari 和 blog 的 A 记录,顺手将代理状态从灰色切换为醒目的橙色:【已代理(小黄云 ☁️)】。
点击保存的那一刻,我以为性能优化已经大功告成。然而,现实却给我上了一堂深刻的运维排障课。
二、 灵异事件:小黄云开启后的“连环崩塌”
刚开启小黄云不到一分钟,刷新浏览器测试,预想中的丝滑并没有到来,反而迎来了连环翻车现场:
现象 1:主站与博客双双陷入“死循环重定向”
在浏览器中打开 https://komari.example.com 或 https://blog.example.com,页面并没有正常展示,而是转圈数秒后直接弹出 Chrome 经典的报错:
ERR_TOO_MANY_REDIRECTS
该网页无法正常运作,komari.example.com将您重定向的次数过多。
【 死循环重定向 (301 Loop) 产生链路 】
访客浏览器 Cloudflare CDN 源站 VPS (NPM)
│ │ │
(1) │ 访问 https://komari │ │
├────────────────────────────>│ │
│ │ (2) 回源转发 (HTTP) │
│ ├───────────────────────────────>│
│ │ │
│ │ (3) 触发 Force SSL, 强制返回 301 │
│ │<───────────────────────────────┤
│ │ (Location: https://komari) │
│ (4) 将 301 抛回给浏览器 │ │
│<────────────────────────────┤ │
│ │ │
(5) │ 遵循 301, 再次请求 https │ │
├────────────────────────────>│ (重复步骤 2~4,进入无休止死循环!)
现象 2:探针单独走新域名,迎来大红叉 Error 525
为了不影响主站访问,我尝试另辟蹊径:在 DNS 中新建一个单独给探针使用的子域名 probe.example.com 并开启小黄云。结果更糟糕,访问该域名直接触发了 Cloudflare 拦截页:
Error 525: SSL handshake failed
Cloudflare is unable to establish an SSL connection to the origin server.
三、 屡试屡败的“常规解法”
面对这两个问题,我开启了第一轮排查,但几乎把网上能搜到的经验踩了个遍:
1. 经验主义失效:“SSL 模式从灵活切换到完全严格”?
网上 90% 关于“Cloudflare 重定向死循环”的文章都给出了标准答案:
“去 Cloudflare 后台将 SSL/TLS 加密模式从 Flexible 改为 Full 或 Full (Strict)。”
但我点开 Cloudflare 后台一看,域名的加密模式原本就一直设置在【完全(严格)/ Full (Strict)】!
按常理,Full (Strict) 下 Cloudflare 会使用 HTTPS (443) 并校验源站证书后回源,根本不应该存在因明文 HTTP 握手而引起的重定向。这个结论一度让我怀疑是 Cloudflare 节点的缓存延迟。
2. 规则救场?遭遇 Enterprise 权限暴击
既然 probe 域名回源报 525 握手失败,原因显然是源站 OpenResty 只有 komari.example.com 的证书,SNI 对不上导致握手终止。
🔒 Cloudflare 规则弹窗拦截:
“仅 Enterprise 套餐提供。升级计划来启用此功能。”
(注:Cloudflare 仅向月费数千美元的 Enterprise 客户开放 Origin Rules 中的重写主机标头功能)
四、 拨云见日:用抓包揭开真相
不再盲猜,直接使用终端命令行对真实链路进行“剥洋葱”式的逐层探测。
1. 抓取 301 响应头,确认重定向发起者
通过 curl -Iv 对重定向循环进行捕获:
curl -Iv https://komari.example.com/
终端打印出的响应头暴露了关键细节:
HTTP/2 301
date: Sun, 18 Oct 2026 13:58:10 GMT
content-type: text/html
location: https://komari.example.com/
server: cloudflare
...
[HTML 页面内容]
301 Moved Permanently
openresty
注意这几个字段:
- HTML 响应体中的
openresty标识:重定向页面根本不是 Cloudflare 边缘规则生成的,而是 VPS 上的源站 OpenResty 吐出来的! - VPS 上的反向代理容器正是基于 OpenResty 开发的 Nginx Proxy Manager (NPM)。
2. 深入 NPM 机制:罪魁祸首竟是【Force SSL】!
我们进一步测试绕过 Cloudflare,直连 VPS 的 443 和 80 端口:
-
直连 443 端口(带 Let’s Encrypt 证书):
curl -s --resolve "komari.example.com:443:1.2.3.4" "https://komari.example.com"👉 返回 200 OK,页面完整加载!
-
直连 80 端口:
curl -I "http://1.2.3.4/" -H "Host: komari.example.com"👉 返回 301 Moved Permanently,内容与 Cloudflare 代理时完全一致!
真相终于大白:
在 Nginx Proxy Manager 控制台(http://vps-ip:81)中,我们在配置 komari 站点时随手勾选了 【Force SSL】(强制使用 SSL)。
在 NPM 底层,Force SSL 的本质是无脑植入了一段判断逻辑:
# Nginx Proxy Manager Force SSL 逻辑
if ($scheme = "http") {
return 301 https://$host$request_uri;
}
当开启 Cloudflare 小黄云后,回源请求经过 CDN 时,即使浏览器端是 HTTPS,如果回源握手或反代未正确透传 $scheme,NPM 便会认定当前连接“不够安全”,忠实地抛出 301 -> https://komari.example.com。
浏览器收到后,再次带着 HTTPS 发起请求给 Cloudflare,Cloudflare 再次把请求递给 NPM,NPM 再次丢出 301……双方在门口互相推诿,形成了一个永无止境的死循环!
WordPress 博客(blog.example.com)的原理同理:WordPress 核心代码自带规范 URL 重定向,当收到不含 HTTPS=on 标识的代理请求时,WordPress 自身会强制做 301 重定向,与 NPM 和 CDN 叠加上演“死循环三重奏”。
五、 终极解决方案:三步破局(0 成本、0 报错)
弄清底层原理后,修复只需一分钟,且无需修改复杂的代码。核心设计哲学是 “外紧内松”:
外层由 Cloudflare 权威 Edge 证书阻挡所有不安全流量并提供 CDN 保护,内层源站 NPM 卸下防备,专注于纯粹的反代转发。
步骤 1:关闭 NPM 的【Force SSL】(破除 301 死循环)
- 登录 VPS 上的 Nginx Proxy Manager 后台(
http://vps-ip:81)。 - 在 Proxy Hosts 列表找到
komari.example.com和blog.example.com,点击右侧的 Edit (编辑)。 - 切换到 【SSL】 选项卡。
- 取消勾选【Force SSL】(关闭强制跳转开关)。
- 点击 Save。
原理:取消后,NPM 不再针对进站请求强刷 301。无论 Cloudflare 回源以何种形式到达,NPM 都直接将请求交给后端容器,死循环瞬间瓦解!
步骤 2:多域名复用(解决探针 525 握手失败与企业版限制)
不需要购买 Enterprise 套餐重写标头,直接让源站 NPM 原生支持 probe 域名:
- 在刚刚的 NPM 编辑弹窗中,切换到 【Details】 选项卡。
- 在 Domain Names 文本框中,键入
probe.example.com并按下 Enter 回车键。 - 确保框内同时存在:
komari.example.comprobe.example.com
- 勾选 Websockets Support(监控探针与网页终端心跳通信必须)。
- 点击 Save。
原理:NPM 自动将
probe与komari指向同一个后端。此时 Cloudflare 带probe.example.com回源时,NPM 能正确响应,525 握手错误彻底消除。
步骤 3:WordPress 适配 Cloudflare 代理标头(防止博客偶发重定向)
针对个人博客,在 VPS 的 WordPress 根目录下编辑 wp-config.php,在 /* That's all, stop editing! Happy publishing. */ 一行上方加入以下代码:
// 信任 Cloudflare 反向代理的 HTTPS 标头,防止 301 循环
if (isset($_SERVER['HTTP_CF_VISITOR']) && strpos($_SERVER['HTTP_CF_VISITOR'], 'https') !== false) {
$_SERVER['HTTPS'] = 'on';
}
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
保存后,WordPress 无论在何种 CDN 架构下都能精准感知当前的加密通道,彻底告别重定向混乱。
额外神技:Cloudflare Worker 免费白嫖多路反代
如果在某些特殊场景下无法修改源站配置,我们还可以利用 Cloudflare 每天免费 10 万次调用的 Cloudflare Workers 来免费平替 Enterprise 的标头重写功能:
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 探针专属加速路由:重写 Host 并转发
if (url.hostname.includes('probe')) {
url.hostname = 'komari.example.com';
const newReq = new Request(url, request);
newReq.headers.set('Host', 'komari.example.com');
return fetch(newReq);
}
// 默认路由
return fetch(request);
}
};
在 Worker 绑定自定义域后,等同于获得了企业版的 Host Header Rewrite 能力,全程 0 费用。
六、 成果验证
配置生效后,在玩客云小主机上将探针服务地址切换为 probe.example.com:
sed -i 's|komari.example.com|probe.example.com|g' /etc/systemd/system/komari-agent.service
systemctl daemon-reload && systemctl restart komari-agent
再在终端进行全链路检验:
- 访问测试:
curl -I https://komari.example.com直接返回HTTP/2 200 OK,博客与监控后台秒开。 - 探针状态:玩客云上
systemctl status komari-agent显示 WebSocket 握手成功,心跳平稳。 - 丢包对比:晚高峰期间通过 Cloudflare 边缘路由,持续 ping 测 1000 个数据包,丢包率从直连的 40% 骤降至 0%,延迟方差显著收窄,探针再也没有闪断过。
七、 总结与避坑心得
这次排障经历虽然曲折,但提炼出了几条极为实用的运维铁律:
- 别被表面现象带偏,善用抓包定位责任人:遇到 301 重定向循环时,第一步不是去盲改 CDN 设置,而是运行
curl -Iv查看响应头里的Server和 HTML 内容。到底是谁抛出的 301,一目了然。 - CDN 体系下的“双层 SSL 悖论”:在“CDN 边缘 + 源站反代”双层架构中,源站切忌开启强硬的
Force SSL或强制跳转规则。外部 CDN 负责接管用户侧的 HTTPS 握手与证书升级,源站反代只需无条件透传。 - 遇到付费墙,多想想轻量级替代:Cloudflare 的高级规则虽好,但往往有商业化限制。善用其免费提供的 Workers、Page Rules 以及源站反代本身的多域名别名机制,绝大多数需求都能零成本优雅解决。