记录了一次在使用 Caddy 反向代理中的正向代理时, 牵扯出 Caddy 指令的演进、版本间的行为差异,甚至一度让我们怀疑官方文档的准确性。
forward_proxy_url
的迷雾与版本之谜#
我们的核心需求是在 Caddy 反向代理中,再通过一个内部的正向代理去连接最终的后端服务。这形成了一个“代理套代理”的经典场景。
目标架构:用户 -> Caddy (反代) -> 内部代理 -> 后端应用
初次尝试:forward_proxy_url
#
根据经验,我们在 Caddyfile 中写下了如下配置:
|
|
然而,在重载 Caddy 配置时,我收到了第一条令人困惑的信息:
{"level":"warn", ... "msg":"The 'forward_proxy_url' field is deprecated. Use 'network_proxy <url>' instead."}
这是一个明确的弃用警告。它告诉我们 forward_proxy_url
已经过时,应该使用新的 network_proxy
指令。
第二次尝试:network_proxy
的挫败#
我们遵从警告的指示,将配置修改为:
|
|
然而,无论采用哪种方案,Caddy 都返回了错误:unrecognized subdirective network_proxy
。
这让我有点疑惑:Caddy 一方面警告我们旧指令已弃用,另一方面又不认识它推荐的新指令。
另外Caddy官方文档中的介绍是forward_proxy_url
, 没有任何提到network_proxy
的内容。
居然是版本“Bug”#
在反复确认我使用的 Caddy(v2.10.0)版本较新且, 并且不需要任何build自定义插件后,问题的焦点最终落在了 Caddy 自身。
最终艰难的找到了问题原因https://github.com/caddyserver/caddy/pull/6978
居然是2.10.0的版本BUG, 2.10.1中已修复…坑啊
解决方案:
最终我重新用2.10.2版本的caddy重新build了我的caddy镜像, 至于弃用警告我直接忽略了,network_proxy
参数并不能正常工作, 继续使用 forward_proxy_url
。
|
|
经过这次,发现即使是稳定版的软件,也可能存在文档、警告和实际行为之间的微小脱节。当遇到类似情况时,应以实际运行结果为准。
Host
头引发的浏览器重定向循环#
在解决了代理指令的问题后,我遇到了第二个难题。通过 curl
在 Caddy 容器内测试代理链路是完全成功的:
curl -x http://internal-proxy:1055 http://backend-service:8188
curl
能完美获取后端应用的页面。然而,通过浏览器访问 https://app.example.com
却陷入了无限重定向的循环。
症状与根源#
分析caddy日志以及研究curl和caddy动作区别发现:
curl
之所以成功,是因为它在请求后端的 Host
头中,使用的是后端的 IP 地址。
而浏览器通过 Caddy 访问时,Host
头被传递为公网域名 (app.example.com
)。许多后端应用在收到一个与自身监听地址不符的 Host
头时,会出于安全或规范化考虑,发起一次重定向。这个重定向往往会与 Caddy 的自动 HTTPS 功能形成冲突,导致循环。
解决方案:伪装 Host
头#
为了让 Caddy 的行为与成功的 curl
命令保持一致,我们使用 header_up
强制修改了发往后端的 Host
头。
|
|
通过这一行简单的配置,我们让后端应用收到了它“期望”的 Host
头,从而停止了不必要的重定向,浏览器访问恢复正常。
总结#
- 理性看待警告:软件的弃用警告虽值得关注,但当新方案无法工作时,应相信当前版本下依然有效的旧方案。
Host
头是魔鬼:在反向代理环境中,Host
头是导致“curl可以,浏览器不行”这类问题的首要疑犯。通过header_up
控制。