
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),跳过了 VarnishVarnish 监听在 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)。

评论(0)