根本原因是请求未被正确分流至varnish:nginx未将流量代理给varnish(如proxy_pass指向后端而非varnish)、自身缓存未关闭、静态文件被本地响应、或varnish因cookie等头默认bypass;需确保nginx纯代理+透传头+禁用缓存,varnish定制vcl_recv处理cookie并显式hash。

Varnish 和 Nginx 在同一台机器上共用 80 端口时,缓存行为会互相干扰——根本原因不是“谁先启动”,而是请求路径没被正确分流,导致 Nginx 直接回源或绕过 Varnish 缓存。
为什么 Nginx 反代 Varnish 后仍出现 X-Cache: MISS 或缓存失效
常见现象是:浏览器看到 X-Cache: MISS、Age: 0、Via: 1.1 nginx(而非 varnish),说明请求根本没进 Varnish。这不是 Varnish 配置问题,而是 Nginx 没把该请求转发给它。
典型错误配置:
- Nginx 的
proxy_pass指向后端应用(如http://127.0.0.1:8080),跳过了 Varnish - Varnish 监听在
127.0.0.1:6081,但 Nginx 的proxy_pass写成http://localhost:6081(某些系统下解析慢或失败) - 没禁用 Nginx 自身的缓存(
proxy_cache),和 Varnish 形成双重缓存逻辑冲突 - 客户端直接访问 Nginx 的 80 端口,而 Nginx 对静态资源(
.js、.css)做了try_files本地响应,根本没发请求出去
让 Nginx 正确代理到 Varnish 的关键配置项
核心原则:Nginx 做纯七层反向代理(不缓存、不重写、不拦截),把所有需缓存的流量无损转给 Varnish。
必须确认以下几点:
-
proxy_pass必须明确指向 Varnish 监听地址,推荐用http://127.0.0.1:6081(避免 DNS 解析开销) - 关闭 Nginx 自身缓存:
proxy_cache off;,且确保没有全局proxy_cache_path生效 - 透传原始 Host 和协议:
proxy_set_header Host $host;、proxy_set_header X-Forwarded-Proto $scheme; - 禁用 Nginx 对静态文件的本地服务逻辑(删掉或注释掉
location ~ \.(js|css|png|jpg)$ { try_files ... }这类块) - 若需支持 HTTPS,Nginx 终止 SSL 后,用
proxy_set_header X-Forwarded-Proto https;告知 Varnish,否则 Varnish 可能因判断非 HTTP 而跳过缓存
Varnish 的 vcl_recv 中必须处理 Nginx 透传的头信息
Varnish 默认只缓存 GET 和 HEAD 请求,且对带 Cookie 或 Authorization 的请求默认 bypass。但 Nginx 透传过来的请求如果含这些头,Varnish 会直接 pass,造成全量 MISS。
在 /etc/varnish/default.vcl 的 vcl_recv 中至少加这几行:
sub vcl_recv {
if (req.method == "PURGE") {
return (purge);
}
if (req.url ~ "\.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$" || req.url ~ "^/api/") {
unset req.http.cookie;
set req.http.X-Ignore-Cookie = "true";
}
if (req.http.X-Ignore-Cookie == "true") {
unset req.http.cookie;
}
}
注意:unset req.http.cookie 必须在 return (hash) 前执行;否则 Varnish 仍按带 Cookie 的逻辑区分缓存键。
调试缓存是否真正生效的三步验证法
别只看浏览器响应头——那可能是 Nginx 回的。要确认真实路径:
- 用
curl -I http://your-domain.com/test.html,检查响应头中是否有X-Varnish:和X-Cache: HIT(不是X-Cache: HIT from nginx) - 登录 Varnish 服务器,运行
varnishadm backend.list确认后端健康;再执行varnishadm ban.list看是否有误清除规则残留 - 临时在 Nginx 的
location /块里加add_header X-Proxy-By "nginx->varnish";,再 curl 验证该 header 是否出现——若没出现,说明请求根本没走这个 location
最易被忽略的一点:Varnish 的缓存键(hash_data)默认包含 req.http.host 和 req.url,但如果你在 Nginx 层做了 rewrite 或 proxy_redirect,而没同步更新 Varnish 的 vcl_hash,会导致相同内容被存多份、命中率骤降。此时必须自定义 vcl_hash 并显式 hash_data(req.url)。











