
很多站点用 Nginx 做反向代理(reverse proxy,一种把客户端请求转发给后端服务器并代为返回响应的中间层)来缓存静态资源,页面加载速度确实上去了,但内容更新后用户看到的还是旧版本。问题往往出在缓存失效(cache invalidation,主动让已缓存内容过期并重新拉取)这一步:缓存写进去了,却不知道怎么让它按预期失效。这篇指南带你完整跑通 Nginx 反代缓存失效流程,从 purge 模块安装、配置、触发方式到一致性验证,全程给出可以直接复制的命令。
如果你的业务跑在 Hostease 的 [VPS](https://cn.hostease.com/vps/)([虚拟专用服务器](https://cn.hostease.com/vps/),一种通过虚拟化技术划分出独立资源的服务器实例)或[独立服务器](https://cn.hostease.com/dedicated-server/)上,缓存失效做不好,轻则用户看到过期价格、过期公告,重则造成数据不一致。Nginx 官方自带的缓存机制本身不提供主动删除单个缓存项的能力,需要借助第三方模块或额外手段,这也是很多管理员卡住的地方。
一、为什么缓存会失效:先理解缓存的生命周期
Nginx 的 proxy_cache 机制把后端返回的响应按 key 存到磁盘缓存目录,命中时直接返回缓存,不再请求后端。缓存项有自己的生命周期,由几个关键指令控制:proxy_cache_valid 定义不同状态码的缓存时长,proxy_cache_key 决定缓存项的标识,proxy_cache_path 指定缓存目录与内存索引大小。
缓存失效本质上只有两条路:一是等缓存自然过期(time-based expiry,按 proxy_cache_valid 设定的时间自动失效),二是主动删除指定缓存项(即 purge)。自然过期简单但不可控,比如你改了首页文案,却要等缓存时长走完才能生效;主动 purge 则能精确删除某个 key 对应的缓存,让下一次请求立即回源拉取新内容。
理解这一点很关键:purge 不是”清空整个缓存目录”,而是按 key 精准删除。如果误用了清空目录的方式,所有缓存瞬间失效,后端会同时收到大量请求,反而造成雪崩。所以正确的策略是”按需 purge”,只删需要更新的那部分。

缓存失效还和请求方法、响应头有关。Nginx 默认对带 Cookie 或 Authorization 的请求不缓存,对 Set-Cookie 响应也不缓存,这些细节会影响你判断”为什么这个页面没被缓存”或”为什么 purge 后还是旧内容”。建议先读一下我们之前整理的 Nginx 限流配置,理解 Nginx 请求处理链路,再回来配置缓存会更顺。
二、purge 模块安装与基础配置
Nginx 官方发行版不带 purge 模块,需要自己编译或用带该模块的第三方包。最常用的是 ngx_cache_purge 模块,它提供 proxy_cache_purge 指令,可以按 key 删除缓存项。以 Ubuntu 22.04 / 24.04 为例,如果你用源码编译 Nginx,在 configure 时加上模块即可。
./configure --add-module=/path/to/ngx_cache_purge make sudo make install # 编译安装后,用 nginx -V 确认模块已加载
如果你不想自己编译,也可以使用带 ngx_cache_purge 的第三方 Nginx 包,例如 OpenResty 或某些发行版的 nginx-extras。安装完成后,在 nginx.conf 的 http 块里配置缓存路径,并在 server 块里启用缓存。
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m use_temp_path=off;
server {
location / {
proxy_cache mycache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 301 302 10m;
proxy_pass http://backend;
}
}
}
这里 keys_zone 定义了缓存索引的内存区,max_size 限制磁盘缓存总量,inactive 表示缓存项在指定时间内未被访问就删除。proxy_cache_key 决定缓存项的标识,purge 时用的就是它。配置好后 reload 让配置生效。
sudo nginx -t sudo nginx -s reload # 先测试配置语法,再平滑重载,避免中断服务
缓存目录的权限也要注意,Nginx worker 进程需要能读写 /var/cache/nginx。如果权限不对,缓存写不进去,页面会一直回源,你还会误以为缓存没生效。这类问题排查起来很费时间,建议一开始就把目录属主设为运行 Nginx 的用户。
三、purge 的触发方式:手动、脚本与自动
配置好模块后,purge 的触发方式有三种:手动 curl、脚本调用、以及结合业务逻辑自动触发。手动方式适合临时更新,脚本方式适合发布流程,自动方式适合内容管理系统(CMS,如 WordPress)在保存文章时自动清对应缓存。
手动 purge 最简单,直接请求一个带 PURGE 方法的 URL。ngx_cache_purge 模块默认监听 PURGE 请求方法,命中缓存就删除并返回 200,未命中返回 404。注意这个接口不能暴露给公网,否则任何人都能清空你的缓存,必须做访问控制。
curl -X PURGE http://127.0.0.1/purge/example-page # 返回 200 表示缓存已删除,404 表示该 key 不存在
在 nginx.conf 里,purge 接口通常单独配置一个 location,并限制只允许内网或本机访问。下面这个配置把 PURGE 方法限定到 127.0.0.1,同时用 allow/deny 做白名单。
location ~ /purge(?/.*) { allow 127.0.0.1; deny all; proxy_cache_purge mycache "$scheme$request_method$host$purge_uri"; }
脚本触发适合发布流程。比如你更新了某个页面,可以在部署脚本里调用 purge 接口,只清这一个 key,而不是清空整个缓存。下面是一个简单的 bash 示例,发布后自动清理首页和文章页缓存。
#!/bin/bash
for path in / /article/123 /about; do
curl -s -X PURGE "http://127.0.0.1/purge$path" > /dev/null
done
# 发布后按需清理,避免全量清空造成回源压力
自动触发则要结合业务。WordPress 等 CMS 在保存文章时会触发钩子,你可以写一个插件或脚本,在文章更新时调用 purge 接口。这样用户一保存,对应缓存立即失效,无需人工干预。缓存失效和数据库性能是两回事,如果你的站点同时有数据库慢查询问题,可以参考 MySQL 慢查询分析 单独排查,别把缓存问题混在一起。
四、缓存一致性验证:如何确认 purge 真正生效
purge 执行后,怎么确认它真的生效了?最直接的办法是看响应头。Nginx 命中缓存时会在响应里带上 X-Proxy-Cache 头,值为 HIT;回源后重新缓存则为 MISS。通过对比 purge 前后的响应头,就能判断缓存是否被正确删除并重建。
curl -I http://example.com/article/123 # 第一次请求,X-Proxy-Cache: MISS,回源拉取 curl -I http://example.com/article/123 # 第二次请求,X-Proxy-Cache: HIT,命中缓存 curl -X PURGE http://127.0.0.1/purge/article/123 # 执行 purge curl -I http://example.com/article/123 # purge 后再次请求,X-Proxy-Cache: MISS,说明缓存已重建
如果 purge 后响应头仍是 HIT,说明 purge 没生效,常见原因有三个:一是 proxy_cache_key 和 purge 用的 key 不一致,导致删错了缓存项;二是 purge 请求没走对 location,被其他规则拦截;三是缓存目录有多个副本,比如启用了多级缓存或 CDN 层。逐一排查即可。
更严谨的做法是记录缓存 key 的哈希值。Nginx 的缓存文件名就是 key 的 MD5 值,你可以用 md5sum 计算预期 key,再去缓存目录里确认对应文件是否被删除。这样即使响应头被中间层改写,也能从磁盘层面验证。

echo -n "GEThttp://example.com/article/123" | md5sum # 计算缓存 key 的 MD5,去缓存目录核对对应文件 find /var/cache/nginx -name "*.md5" -mmin -1 # 查看最近被写入的缓存文件,确认 purge 后是否重建
一致性验证还要考虑多节点场景。如果你的站点前面还有 CDN(内容分发网络,把内容缓存到离用户更近的边缘节点),Nginx 层的 purge 只清本机缓存,CDN 层的缓存需要单独刷新。很多管理员只清了 Nginx 缓存,用户却仍看到旧内容,就是因为 CDN 层没同步。建议把 Nginx purge 和 CDN 刷新纳入同一条发布流水线,保证各层一致。
缓存一致性还和日志有关。purge 操作本身不会写访问日志,如果你要审计谁在什么时候清了哪些缓存,需要单独记录。可以参考 Linux 系统日志轮转 的做法,为 purge 操作单独建日志并定期轮转,避免日志无限增长。
五、常见坑与最佳实践
第一个坑是 purge 接口暴露公网。前面说过,PURGE 方法必须用 allow/deny 或防火墙限制,否则任何人都能清空你的缓存,造成回源风暴。生产环境建议只允许本机或内网访问,并配合防火墙规则双重保护。
第二个坑是 proxy_cache_key 不一致。purge 用的 key 必须和缓存写入时的 key 完全一致,包括 scheme、host、request_uri 的大小写和顺序。一个常见的错误是缓存时用 $request_uri,purge 时却用了简化路径,导致永远删不到目标缓存。
第三个坑是缓存了不该缓存的内容。带 Cookie 的个性化页面、登录后的用户页面、动态接口,都不适合用 proxy_cache 缓存。如果误缓存了这些,purge 也救不回来,因为每个用户看到的都是同一个缓存副本。建议用 proxy_cache_bypass 和 proxy_no_cache 指令,按请求头或 Cookie 判断是否跳过缓存。
proxy_cache_bypass $cookie_sessionid; proxy_no_cache $cookie_sessionid; # 带 sessionid 的请求不缓存也不命中缓存,避免用户数据串号
第四个坑是缓存雪崩。如果发布时全量清空缓存,所有 key 同时失效,后端会瞬间收到海量请求。正确做法是分批 purge,或利用 inactive 机制让缓存自然淘汰。如果后端是数据库,还要考虑连接池压力,可以参考 Redis 持久化与恢复 的思路,把热点数据放到更快的缓存层,减轻数据库压力。
最佳实践总结起来就几条:purge 接口严格内网化;key 保持一致并记录哈希;按需 purge 而非全量清空;把 Nginx purge 和 CDN 刷新纳入发布流水线;用响应头和磁盘文件双重验证。做到这几点,缓存失效基本不会出大问题。
六、总结
Nginx 反代缓存失效的核心是理解缓存生命周期,用 purge 按 key 精准删除,而不是全量清空。安装 ngx_cache_purge 模块、配置好 proxy_cache_key、用 PURGE 方法触发、再用响应头和磁盘文件验证一致性,这套流程能让你在内容更新后立即让用户看到新版本,同时避免回源风暴。
如果你的站点跑在 Hostease 的 VPS 或独立服务器上,缓存配置和性能优化是提升用户体验的关键一环。建议先从本文的 purge 配置入手,配合限流、日志轮转等实践,逐步把站点性能调优到稳定状态。遇到缓存失效问题,先查 key 是否一致,再查接口是否受限,最后查 CDN 层是否同步,按这个顺序排查通常能快速定位。