Cloudflare CDN下Nginx源站缓存失效及与Apache的差异咨询
嗨,咱们来聊聊为啥你的Nginx源站在Cloudflare上缓存一直是DYNAMIC,而Apache却正常——这俩服务器在缓存相关的配置和行为上有不少关键差异,我给你拆解一下:
1. 默认响应头的差异
Apache的默认配置(尤其是开启了mod_expires或mod_headers模块时)往往会自动给静态资源返回允许缓存的Cache-Control或Expires头,比如public, max-age=86400,这让Cloudflare很容易识别出可缓存的内容。
而Nginx默认就“保守”多了:它通常会给动态内容返回Cache-Control: no-cache, no-store, must-revalidate,甚至加上Pragma: no-cache这类强禁止缓存的头。哪怕你在Cloudflare设了“缓存所有内容”的页面规则,只要源站返回了no-store这类头,Cloudflare会优先遵守源站的设置,直接标记为DYNAMIC。
快速排查:用curl -I https://你的Nginx源站域名/某个资源,对比Apache源站的响应头,重点看Cache-Control、Pragma、Expires这几个字段。
2. 动态内容的缓存头配置逻辑
Apache的mod_cache、mod_fcgid等模块默认会对动态内容(比如PHP)的缓存处理更灵活,甚至很多主机面板(比如cPanel)会自动给动态内容添加合适的缓存头。
但Nginx不一样——它默认不会主动给动态内容设置缓存头。如果你的Nginx配置里没有明确添加add_header Cache-Control "public, max-age=3600";这类规则,动态内容就会一直带着“不可缓存”的标记,Cloudflare自然不会缓存它。
3. Cookie处理的差异
这是很容易被忽略的点:Nginx默认可能会给所有响应(包括静态资源)带上Cookie(比如PHPSESSID),而Cloudflare默认会跳过带Cookie的请求的缓存(因为Cookie意味着内容可能是个性化的)。
反观Apache,很多默认配置会给静态资源自动去掉Cookie,或者你的Apache配置里已经做了相关设置。如果Nginx的静态资源响应头里带着Cookie,Cloudflare会直接判定为动态内容,不会缓存。
解决方法:在Nginx的静态资源location块里添加:
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { proxy_hide_header Set-Cookie; fastcgi_hide_header Set-Cookie; add_header Cache-Control "public, max-age=86400" always; }
4. 缓存规则的优先级细节
Cloudflare的页面规则优先级通常高于源站响应头,但有两个例外:如果源站返回Cache-Control: private或者no-store,Cloudflare会严格遵守源站的设置,页面规则的“缓存所有内容”会失效。
你的Apache源站大概率没有返回这些强禁止的头,所以页面规则能正常生效;但Nginx默认返回的就是这类头,导致页面规则起不了作用。
快速修复:在Nginx的全局或location配置里强制设置允许缓存的头:
server { # ...其他配置 add_header Cache-Control "public, max-age=3600" always; # 如果是PHP动态内容,还可以加上这些 fastcgi_cache_bypass $http_pragma; fastcgi_no_cache $http_pragma; }
5. Vary头的差异
Apache默认可能不会返回Vary: *这类头,但Nginx在某些配置下(比如开启了某些动态模块)会返回Vary: *。这个头会告诉Cloudflare“每个请求的内容都可能不同”,直接导致无法缓存。
排查:检查Nginx响应头里有没有Vary: *,如果有,在配置里去掉或者改成具体的字段(比如Vary: Accept-Encoding)。
- 用
curl -I分别请求Apache和Nginx源站的同一个资源,对比响应头的差异,重点看Cache-Control、Set-Cookie、Vary字段。 - 在Nginx配置里添加强制缓存头,重启Nginx后测试Cloudflare的缓存状态。
- 确认Cloudflare的页面规则确实匹配了Nginx源站的域名(有没有规则顺序错误、匹配路径不对的情况)。
内容的提问来源于stack exchange,提问作者Almighty




