Hermes Dashboard 反代访问异常排障复盘
有些运维问题最麻烦的地方,不是它完全不会报错,而是每一层看起来都对,偏偏合在一起就不工作。
这次我们做 Hermes Dashboard 的域名访问时,遇到的就是这样一个问题。
一开始大家都以为,这无非就是“把服务挂到域名下面”而已:
域名 → 反向代理 → 本机服务
听上去像一条很普通的链路,但真正开始之后,事情比想象中绕得多。目标也很明确:服务留在内网,外部只走统一入口,不把管理端口直接暴露出去。
一开始:服务其实是好的
Hermes Dashboard 本身并没有问题。
我们先确认了它的监听状态,某个本地端口确实起来了,服务也能正常响应请求。
后来为了安全起见,我们把它从对外监听收回到本机:
| |
这样做的好处是:
- 本地管理端口不再直接暴露公网
- 只能由本机反向代理访问
- Dashboard 更符合生产环境的安全要求
真正适合生产的方式,应该是让它只在本机监听,然后由统一的反向代理层做代理。
第二层:反向代理看起来也没错
某个面板管理下的站点配置如下:
/path/to/site.conf/path/to/proxy.conf
核心反代逻辑是:
| |
也就是说,外部请求应该经过:
| |
从本机回源测试看,这条链路是通的。
为了把入口理顺,我们还补了这些东西:
80 -> 301 https443 -> 反代到本地服务- 一度加过 basic auth
- 后来又把 basic auth 去掉
- 再后来又重新加回去做登录保护
- 最后又再次关掉,确认问题不在认证层
一路排下来,你会发现:OpenResty 本身并不是坏的,反代也不是坏的。
真正让人迷惑的,是“浏览器报重定向次数太多”
最先暴露问题的,不是服务端日志,而是浏览器。
页面不是报 404,也不是 500,而是直接提示:
重定向次数太多
这类现象通常不是后端完全不可用,而是某一层在不断改写请求路径或协议,导致请求在不同端之间来回循环。我们很快意识到,问题已经不是“某个组件能不能跑”,而是“整条访问链路的语义是否一致”。
根因:Cloudflare 代理模式与源站 HTTPS 重定向冲突
1. 域名流量并不是直接打到源站
我们检查 DNS 后发现,example.yourdomain.com 解析出来的是 Cloudflare 的边缘节点地址,而不是源站机器 IP。
这意味着实际链路是:
| |
而不是直接访问服务器。
2. 源站本身会把 HTTP 重定向到 HTTPS
在站点反代配置里,我们配置了:
80 -> 301 https443 -> 反代到本地服务
这是一种很常见、也很合理的生产策略:所有明文 HTTP 请求统一升级到 HTTPS。
3. Cloudflare Flexible 模式会让语义发生冲突
如果 Cloudflare 使用的是 Flexible 模式,那么它的行为是:
- 用户访问 Cloudflare:HTTPS
- Cloudflare 到源站:HTTP
这时候就出现了一个非常关键的问题:
源站视角
源站看到的是 HTTP 请求,于是按照配置把它重定向到 HTTPS。
Cloudflare 视角
Cloudflare 仍然坚持用 HTTP 回源。
于是双方开始互相“纠正”:
- 浏览器访问
https://example.yourdomain.com - 请求进入 Cloudflare
- Cloudflare 以 HTTP 回源到源站
- 源站把 HTTP 重定向到 HTTPS
- Cloudflare 再按自己的策略回源
- 浏览器最终陷入 重定向循环
这就是“重定向次数太多”的根本原因。
为什么关闭代理模式后问题就好了
当我们把代理模式关闭,也就是改成 DNS only 后,域名访问立刻恢复正常。
这说明:
- Hermes Dashboard 是正常的
- 反向代理是正常的
- basic auth 不是根因
- 真正的问题在代理层与源站 HTTPS 策略的冲突
也就是说,问题不是“服务没起来”,而是“外层代理和源站对协议语义理解不一致”。
为什么推荐 Full (strict)
如果未来需要重新打开代理模式,正确的方式不是 Flexible,而是:
- Full
- 更推荐 Full (strict)
Full (strict) 的含义
它表示:
- 浏览器到 Cloudflare:HTTPS
- Cloudflare 到源站:HTTPS
- Cloudflare 会验证源站证书是否有效
为什么它适合这个场景
因为我们的源站本来就希望:
- HTTP 自动升级到 HTTPS
- 正式入口走 HTTPS
如果 Cloudflare 回源也使用 HTTPS,那么双方语义一致,重定向循环就不会再发生。
换句话说:
- Flexible:Cloudflare 用 HTTP 回源,容易和源站的 HTTP→HTTPS 冲突
- Full (strict):Cloudflare 也用 HTTPS 回源,和源站策略一致
所以在这种架构中,Full (strict) 是更合理的生产选择。
最后留下的做法
这次排障结束后,我们把比较稳妥的做法保留了下来:
1. 服务只监听本机
| |
2. 统一入口放在反向代理层
80 -> 443443 -> 127.0.0.1:PORT
3. 认证按场景决定是否保留
- 如果要保留认证,可以作为额外安全层
- 如果正在排障,最好先去掉认证,避免干扰判断
4. 代理模式要么关闭,要么用 Full (strict)
- 排障阶段:优先 DNS only
- 生产阶段:如果要用代理,建议 Full (strict)
经验总结
这次问题最重要的经验,不是某一行配置,而是对整条链路的理解。
1. 单点没问题,不代表整体没问题
服务能起来、证书能过、入口也能通,并不意味着整体链路一定正常。
代理层、回源层、重定向策略叠加起来,才是最终用户看到的行为。
2. 代理层并不总是透明的
一旦开启代理模式,它不只是一个“转发器”,还会参与:
- SSL 终止
- 回源协议
- 重定向行为
- 缓存与规则处理
3. Flexible 和强制 HTTPS 的源站容易冲突
只要源站坚持 HTTP -> HTTPS,用 HTTP 回源就很容易出现重定向循环。
4. Full (strict) 才是更一致的做法
它保证了外层代理和源站在协议上是统一的,不会互相打架。
结论
这次 Hermes Dashboard 访问异常的根因,不是反代配置写错,也不是 Dashboard 服务本身异常,而是:
代理模式与源站的 HTTP→HTTPS 重定向策略发生了语义冲突,最终导致浏览器进入重定向循环。
当代理模式关闭后,问题立刻消失,说明源站链路本身没有问题。
如果未来要恢复代理,应该使用 Full (strict),让回源语义与源站策略保持一致。