Caddy 2.11.6 → 2.11.7 升级笔记:16 KiB 请求头上限、1 分钟 idle 超时和它引出的三个回归
两个版本挨得很近:2.11.6 改动了几处会直接影响现网行为的地方,2.11.7 专门修 2.11.6 带出来的回归。已经在 2.11.6 的,建议直接升 2.11.7。
- 发布页:
- 全部版本:
2.11.6 的破坏性变更
请求头默认上限 16 KiB
之前沿用 Go 的 1 MB 默认值。现在请求头超过 16 KiB 直接返回 431 Request Header Fields Too Large。常见触发是巨型 cookie 和超长 token,尤其同一域名下挂了多个应用、cookie 叠加的场景。
{
servers {
max_header_size 65536
}
}
max_header_size 是 server option,按需放大。
含点号的请求头被丢弃
逻辑和 2.11.4 丢下划线头一样:PHP 会把 . 折叠成 _,X.Foo 就能冒充 X_Foo 这类合法头。需要保留的用 expected_dot_headers 显式列出。
{
servers {
expected_dot_headers "X.Custom.Header"
}
}
新增默认 1 分钟 idle 读写超时
读请求 body 或写响应时,如果完全没有进展超过 1 分钟,连接会被中断。注意判断依据是「一点进展都没有」,SSE 这种两次写之间有停顿的不该被算进去。调整方式有两种:server option 的 timeouts 里改 read_body_idle / write_idle,或者在路由上用 timeouts 指令单独覆盖。
{
servers {
timeouts {
read_body_idle 5m
write_idle 5m
}
}
}
通配站点的 client_auth 不再被继承
*.example.com 上配的 mTLS 不再自动套用到有独立 site block 的 public.example.com。要 mTLS 就在该站点上显式再配一遍。
另外两条也记一下:Go 1.26 成为构建 Caddy 及插件的最低版本;配置校验变严,重复的 named_routes、重复的 forward_auth uri、非法的 weighted_round_robin 权重、重复或歧义的 map 输入等现在都直接报错,/load 对非法配置返回 400 并把 warning 放进合法的 JSON body(此前是 200 加两个拼接的 JSON 对象)。
2.11.7 修的三个回归
都和新加的 idle 超时有关:
- HTTP/2 反代 nil pointer panic。 请求 body 的 idle deadline 可能活得比设置它的 handler 还久。HTTP/2 下 handler 已返回、反向代理仍在读 body,就会 nil pointer 解引用崩溃(#8101)。
- HTTP/1.1 下带 body 的流式响应被整 60 秒截断。 典型是用 POST 打开 SSE 的客户端,body 读完之后正好 60 秒连接被切断(#8103)。
- HTTP/2 静默 SSE 被 RST。 两次写之间停顿超过
write_idle(默认 1 分钟)就发 stream error 重置流。只有写入真正卡住才该计时,正常停顿不该算(#8118、#8119)。
还有一个非超时类回归:缺失 cookie 的占位符恢复为空。2.11.6 起,cookie 不在请求里时 respond 头会把 {http.request.cookie.*} 原样输出,纯 HTTP 下的 {http.request.tls.*} 同理(#8019)。
排查顺序
- 先看 431。 访问日志里出现
431,基本就是请求头超了 16 KiB。抓一次原始请求头看总大小,重点查 cookie 和 Authorization,再决定是清 cookie 还是抬max_header_size。 - 再看「整 60 秒」。 响应时长卡在 60 秒附近的截断,尤其请求方法是 POST、响应是
text/event-stream,就是 #8103,升 2.11.7 即可。 - 最后看 panic 栈。 栈里出现 nil pointer dereference,且现场是 HTTP/2 + 反向代理 + 请求体,对应 #8101。
- HTTP/2 上 SSE 周期性断流、日志里是流重置而非超时,对应 #8118/#8119。
顺带:Incremental 头(RFC 10036)
2.11.7 加了对 Incremental 头字段的支持,它是 NGINX 私有 X-Accel-Buffering 的标准替代。上游响应带 Incremental: ?1 时,reverse_proxy 立即转发,效果等同 flush_interval -1,encode 也会流式处理而不是压着缓冲。如果 request_buffers 或 response_buffers 会阻止增量转发,Caddy 按 RFC 要求返回 501 Not Implemented,而不是静默缓冲;新加的 proxy_status_name 选项可附带 Proxy-Status 头说明拒绝原因(#8020)。
2.11.7 的其他改动
- TLS 握手时证书查找约快 2 倍(10 次内存分配,此前 15 次),前提是没注册事件订阅且关闭 debug 日志(#8010)。
- reload 时把监听从 Unix socket 挪走,旧 socket 立即关闭并删除文件;此前客户端要挂起约 2 分钟等 GC(#8061)。
- headers handler 在 JSON 配置里设置多个
Set-Cookie时,改为发送多个独立头字段,不再用逗号拼接(#8080)。 caddy fmt不再删除输入末尾的左花括号(#8047)。encode之后的 SSE 现在立即流式输出,不再缓冲(#7905)。
升级路径很清楚:2.11.5 及更早的,先评估 16 KiB 头和点号头两项是否命中自己的流量,再上 2.11.7;已经在 2.11.6 的,直接升,重点确认 POST+SSE 和 HTTP/2 反代两条链路。