Caddy 配置 versions h2 后报 malformed HTTP response
Caddy反代DoH出现malformed HTTP response时,核对TLS ALPN与versions枚举。修正h2为受支持的2,保留证书验证,区分旧版请求错误与新版加载拒绝。
DoH 服务直连可以返回 DNS 结果,经 Caddy 反代却得到 502,日志出现 HTTP/1.x transport connection broken: malformed HTTP response,后面跟着二进制转义字节。如果传输配置写了 versions h2,先核对这个值:TLS 握手的 ALPN 标识 h2,不是 Caddy versions 指令接受的 HTTP/2 枚举。
在 Caddy 2.10.0 的这类配置中,错误值可能没有在加载阶段被拒绝,随后出现协议解析错误。Caddy 2.11.7 已会在配置预备阶段拒绝 h2,报 unsupported HTTP version;不能把旧版本的请求阶段现象说成所有现行版本都一样。
两段连接的 HTTP 版本分别检查
浏览器或 DNS 客户端到 Caddy 使用 HTTP/2,并不决定 Caddy 到上游的协议。直连上游时看见 ALPN h2,能帮助判断服务支持 TLS 上的 HTTP/2,但不能证明反向代理使用了正确设置。
检查实际加载的 reverse_proxy、upstream 地址和 transport http。面板生成配置、导入文件和容器挂载需要看同一运行实例,不能只改终端里另一份 Caddyfile。
错误里的二进制内容也不能直接推出“后端并发流数量为零”。先根据配置和实际响应辨别协议,确认不是连接了另一端口、明文服务或中间错误页面。日志里的完整请求头可能含身份信息,保留必要字段即可。
TLS HTTP/2 的枚举写 2
对于已经确认使用 TLS 的上游,修正的是传输版本值。以下是要合入既有反向代理的参数片段:
transport http {
tls
versions 2
}
保留实际 upstream、路由、鉴权、必要请求头、证书信任池和服务器名称设置,不用这一小段覆盖整个代理块。tls 已由 HTTPS upstream 或其他必要 TLS 参数启用时,按原配置组织,不必机械重复添加。
Caddy 当前接受 1.1、2、h2c 和 3。普通上游默认支持 1.1 2;如果业务没有特定的版本配置需求,保留受支持的默认组合也可以。不要看到 ALPN 输出就把它逐字复制进 versions。
h2c 表示到上游的明文 HTTP/2,不是 TLS h2 的另一个拼法。把 TLS 上游改成明文,或者跳过证书验证,都不是枚举拼错的修复。
协议修正后仍要保留证书校验
原配置若有 tls_insecure_skip_verify,它会关闭证书验证,却不会修正 HTTP 版本。私有 CA 应通过现有信任池配置解决,连接地址与证书名称不同则核对 tls_server_name。
协议枚举正常后出现未知 CA、名称不匹配或授权错误,属于新的具体分支。根据新日志处理,不能因原来的 502 消失,就把忽略证书或删除访问控制留下来。
用真实 DoH 请求验收
保存原配置后,用与部署相同的 Caddy 版本和模块,在合适的测试环境校验实际配置。通常可使用:
caddy validate --config /path/to/active/Caddyfile --adapter caddyfile
路径是占位值,校验会加载并预备模块,需具备相同的资源条件。通过后按已有管理方式重载,不为此次操作把管理 API 开放到公网。
重载后从原 DNS 客户端请求实际 DoH 路径,确认 DNS 响应内容和状态符合预期,再核对同一请求的代理及上游日志。首页返回 200、TLS 握手成功或配置校验通过,都不能代替 DoH 功能验证。
多上游环境逐个核对协议和响应。若新配置不能加载,或业务结果异常,恢复本次保存的配置并按同一流程加载,继续检查具体协议与信任条件,不用增加重试来掩盖配置值错误。


