· Jeff · 技术文章 · 6 分钟阅读
改了静态站内容,线上却不更新?nginx 缓存排障实录
静态站改完内容部署后线上还是旧页面,排查半天发现根因是宝塔 nginx 的全局代理缓存。一篇讲透判断方法和治本方案。
改了静态站内容,线上却不更新?nginx 缓存排障实录
静态站(Docker + Nginx 部署)改完内容、重新构建部署后,线上访问还是旧页面。带
?v=随机数能拿到新内容,不带参数就是旧的——典型的缓存层作祟。本文记录完整排查过程和治本方案。
一、现象
我维护的一个静态博客站(Astro 构建,Nginx 容器托管),在某次加了一个新栏目后:
- 重新构建 Docker 镜像并重启容器 ✅
- 容器内直接
cat生成的 HTML,新内容明明在 ✅ - 但浏览器 / curl 访问线上域名,看到的还是旧页面 ❌
最诡异的是:curl "https://站点/页面/?v=12345"(带随机参数)能拿到新内容,不带参数就是旧的。
二、第一反应:是不是 CDN 缓存?
我的站点前面套了 Cloudflare,第一反应是 CDN 边缘缓存。
结果检查响应头:
cf-cache-status: DYNAMIC # Cloudflare 说自己没缓存
last-modified: Mon, 17 Aug 2026 17:15:50 GMT # 旧时间cf-cache-status: DYNAMIC 意味着 Cloudflare 认为这个响应不该被缓存。那 last-modified 为什么是旧的?
三、关键判断:对比「源站直连」和「外部访问」的 Last-Modified
这是整个排查里最有用的一步——对比同一资源在「源站直连」和「外部访问」下的响应头差异。
# 1. 直连源站(跳过所有前置层)
curl -sI http://127.0.0.1:3001/collections/
# Last-Modified: Mon, 17 Aug 2026 17:53:30 GMT ← 新内容的时间
# 2. 走完整链路(域名访问)
curl -sI https://你的域名/collections/
# Last-Modified: Mon, 17 Aug 2026 17:15:50 GMT ← 旧内容的时间同一个页面,源站返回新时间,外部访问返回旧时间——说明问题不在源站,而在源站和外部之间的某一层缓存。
既然 Cloudflare 显示 DYNAMIC(没缓存),那嫌疑就落到源站前面的反向代理上。
四、根因:宝塔 nginx 的「全局代理缓存」对全站生效
我用的服务器面板(宝塔)在 nginx 全局配置里有一个 proxy.conf,里面有这样一行:
# 全局代理缓存配置(http 级)
proxy_cache_path /www/server/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:20m inactive=1d max_size=5g;
proxy_cache cache_one;关键在最后一行:proxy_cache cache_one; 写在 http 级(全局),对所有站点生效。
而我的站点自己的配置里虽然没写 proxy_cache cache_one;,但它继承了全局配置——所有经 nginx 反代的响应都会被缓存(inactive=1d,最长缓存 1 天)。
所以流程是:
浏览器 → Cloudflare(DYNAMIC 不缓存) → 宝塔 nginx(proxy_cache 缓存了旧 HTML) → Docker 容器(其实已是新内容)之前我还以为 proxy_cache_valid 200 1h;(站点配置里的一行)是缓存源,但真正起作用的其实是全局那行 proxy_cache cache_one;。
五、治本方案:绕过缓存 + 清空旧缓存
1. 给站点加绕过指令
在站点的 nginx 配置 location / 里加上:
location / {
proxy_pass http://127.0.0.1:3001;
...
proxy_no_cache 1; # 不写入缓存
proxy_cache_bypass 1; # 绕过已有缓存,直接回源
}proxy_no_cache 1;:告诉 nginx 这个响应不要写进缓存proxy_cache_bypass 1;:即使缓存里有,也直接回源站拿新的
2. 清空已有缓存
rm -rf /www/server/nginx/proxy_cache_dir/*3. 重载 nginx
nginx -s reload # 或 systemctl reload nginx六、验证
改完再访问,Last-Modified 变成新内容的时间,新栏目正常显示:
last-modified: Mon, 17 Aug 2026 17:53:30 GMT ← 已是新时间之后每次改内容,部署完刷新就能看到,不用再等缓存过期。
七、经验总结
- 带
?v=随机数能拿到新内容 = 有缓存层。不同 URL 会绕过缓存,所以能拿到新的;但这不是根治,只是绕过。 - 判断缓存在哪层:对比「源站直连」和「外部访问」的响应头(尤其
Last-Modified/Age)。不一致 = 中间有缓存。 cf-cache-status: DYNAMIC不代表没有缓存——它只说明 Cloudflare 没缓存,源站前面的反向代理可能缓存了。- 面板类服务器(宝塔等)的全局 nginx 配置要留个心眼:
proxy.conf里的proxy_cache cache_one;是 http 级,对所有站点生效,很容易成为隐藏的缓存源。 - 治本一定要用
proxy_no_cache+proxy_cache_bypass,而不是只清一次缓存(清完还会再缓存旧的)。
相关阅读
- 如果你也遇到「改了 Docker 容器内容但线上不更新」,先按上面的三步排查:容器内看内容 → 对比 Last-Modified → 找缓存层。
☕ 如果这篇文章对你有帮助
欢迎请 Jeff 喝杯咖啡,支持我持续分享更多软件技巧~
打赏功能即将上线,先点个赞也是支持 ❤️