Varnish仅根路径请求返回400错误,寻求技术排查方案
问题:Varnish仅根路径返回400错误,其余路径正常
部署的Varnish缓存服务器仅在访问站点根路径/(https://example.com/)时返回400 Bad Request错误,其余路径如example.com/en均可正常处理。
Varnish日志输出
* << Request >> 164200 - Begin req 164199 rxreq - Timestamp Start: 1676987476.561832 0.000000 0.000000 - Timestamp Req: 1676987476.561832 0.000000 0.000000 - ReqStart 127.0.0.1 36702 a0 - ReqMethod GET - ReqURL / - ReqProtocol HTTP/1.0 - ReqHeader X-Real-IP: 10.254.27.52 - ReqHeader X-Forwarded-For: 10.254.27.52 - ReqHeader X-Forwarded-Proto: https - ReqHeader X-Forwarded-Port: 443 - ReqHeader Connection: close - ReqUnset X-Forwarded-For: 10.254.27.52 - ReqHeader X-Forwarded-For: 10.254.27.52, 127.0.0.1 - VCL_call RECV - ReqHeader Surrogate-Capability: Varnish=ESI/1.0 - ReqHeader Host: - ReqURL / - VCL_return hash - VCL_call HASH - VCL_return lookup - Hit 3 2414.934756 120.000000 0.000000 - VCL_call HIT - VCL_return deliver - RespProtocol HTTP/1.1 - RespStatus 400 - RespReason Bad Request - RespHeader Date: Tue, 21 Feb 2023 13:31:31 GMT - RespHeader Server: Apache - RespHeader Content-Length: 226 - RespHeader Content-Type: text/html; charset=iso-8859-1 - RespHeader x-url: / - RespHeader x-host: - RespHeader X-Varnish: 164200 3 - RespHeader Age: 1185 - RespHeader Via: 1.1 varnish (Varnish/6.0) - VCL_call DELIVER - RespUnset x-url: / - RespUnset x-host: - RespUnset Via: 1.1 varnish (Varnish/6.0) - RespUnset X-Varnish: 164200 3 - VCL_return deliver - Timestamp Process: 1676987476.561898 0.000066 0.000066 - RespHeader Connection: close - Timestamp Resp: 1676987476.561937 0.000105 0.000040 - ReqAcct 142 0 142 177 226 403 - End
TCP Dump捕获结果

varnishd服务配置
[Unit] Description=Varnish Cache, a high-performance HTTP accelerator After=network-online.target [Service] Type=forking KillMode=process # Maximum number of open files (for ulimit -n) LimitNOFILE=131072 # Locked shared memory - should suffice to lock the shared memory log # (varnishd -l argument) # Default log size is 80MB vsl + 1M vsm + header -> 82MB # unit is bytes LimitMEMLOCK=85983232 # Enable this to avoid "fork failed" on reload. TasksMax=infinity # Maximum size of the corefile. LimitCORE=infinity ExecStart=/usr/sbin/varnishd -a :6081 -f /etc/varnish/default.vcl -s malloc,2g -p http_max_hdr=1024 -p http_resp_hdr_len=65536 ExecReload=/usr/sbin/varnishreload [Install] WantedBy=multi-user.target
问题原因分析
- 空Host头触发后端400:从日志可见请求的
Host头为空(ReqHeader Host:),后端Apache接收到无Host头的根路径请求时返回400错误。 - 错误响应被缓存:Varnish将这个400错误响应缓存,后续访问根路径时直接命中缓存返回错误,因此请求无需转发到后端Apache(与TCP Dump结果一致)。
解决办法
1. 立即清除根路径缓存条目
用varnishadm删除缓存的错误响应:
varnishadm ban req.url == "/"
2. 修改VCL配置避免重复问题
编辑/etc/varnish/default.vcl,在sub vcl_recv中添加以下逻辑二选一:
方案A:直接拦截空Host头请求
sub vcl_recv { // 拦截无Host头的请求,直接返回400 if (req.http.Host == "") { return (synth(400, "Bad Request: Missing Host header")); } // 保留原有VCL逻辑... }
方案B:允许空Host头但不缓存根路径
sub vcl_recv { // 空Host头的根路径请求直接透传到后端,不缓存 if (req.url == "/" && req.http.Host == "") { return (pass); } // 保留原有VCL逻辑... }
3. 重载Varnish配置
使修改后的配置生效:
systemctl reload varnish
内容的提问来源于stack exchange,提问作者Eng7
相关产品推荐
相关产品推荐

