
先说效果
改成 nginx 静态直出后,缓存命中的请求完全不会进入 PHP-FPM,一个 worker 都不占。对和别的站共用同一个 PHP-FPM 池的机器(比如宝塔上一台机器放好几个站),这是最直接的提速手段。
代价是:多了一段 nginx 配置要维护,而且它有两个不讲道理的坑(见下文)。
一、先搞清楚 WP Super Cache 的两种模式
WP Super Cache 缓存的「内容」是一样的,区别只在谁来把缓存吐给浏览器:
| 模式 | 命中缓存时发生什么 |
|---|---|
| PHP 模式(默认) | 请求进 PHP → advanced-cache.php 判断命中 → 直接输出缓存文件。省掉了数据库和模板渲染,但仍然占用一个 PHP-FPM worker |
| mod_rewrite 模式 | nginx 发现缓存文件存在 → 直接 rewrite 到那个静态文件返回,完全不进 PHP |
所以「缓存已经开了」不等于「已经最优」——默认的 PHP 模式,每个缓存命中都在吃 worker。
二、第一步:确认 WPSC 已启用,并切到 mod_rewrite
看 wp-content/wp-cache-config.php,关键几行:
$cache_enabled = true;
$super_cache_enabled = true;
$wp_cache_mod_rewrite = 1; // 1 = 允许 mod_rewrite 静态直出
$cache_max_time = 3600; // 缓存过期时间(秒)
$wp_cache_clear_on_post_edit = 1; // 编辑/发布文章时自动清缓存
$wp_cache_mod_rewrite = 1 也可以在后台「设置 → WP Super Cache → 高级」里勾选。改完记得确认缓存目录可写,缓存文件长这样:
wp-content/cache/supercache/<你的域名>/<URI>/index-https.html
- https 站点是
index-https.html,http 站点是index.html,后缀别写错; <URI>是去掉首尾斜杠的路径,首页的缓存文件直接放在域名目录下。
三、第二步:让 nginx 直接返回缓存文件
在站点的 nginx 配置里加一段(宝塔可以放在 vhost/nginx/extension/<域名>/ 下的独立文件里):
set $wpsc_uri $request_uri;
# 以下任一条件成立就跳过静态缓存,回落到 PHP(与插件自身规则保持一致)
if ($request_method = POST) { set $wpsc_uri "NOCACHE"; }
if ($query_string != "") { set $wpsc_uri "NOCACHE"; }
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*\.php|/feed/|index.php|sitemap(_index)?.xml|/wp-json/") { set $wpsc_uri "NOCACHE"; }
# 登录用户、评论过的人、有密码的页面一律不缓存
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $wpsc_uri "NOCACHE"; }
if (-f $document_root/wp-content/cache/supercache/$http_host/$wpsc_uri/index-https.html) {
rewrite ^(.*)$ /wp-content/cache/supercache/$http_host/$wpsc_uri/index-https.html break;
}
# 如果你的站还有 http 访问(没有强制 https),把这个 http 分支也加上
if (-f $document_root/wp-content/cache/supercache/$http_host/$wpsc_uri/index.html) {
rewrite ^(.*)$ /wp-content/cache/supercache/$http_host/$wpsc_uri/index.html break;
}
如果你有会员中心、表单页这类必须实时的页面,再加一条按路径排除:
if ($request_uri ~* "^/(sign|uc|edit)(/|$|\?)") { set $wpsc_uri "NOCACHE"; }
上面这三个路径是我自己的会员中心 / 用户页 / 草稿编辑页,换成你自己不能缓存的路径。
注意
$wpsc_uri用的是$request_uri(含路径),带尾斜杠的 URI 会被拼成<路径>//index-https.html,实际能命中的是不带尾斜杠的目录形式——所以请求/about/时可能回落 PHP。这不是配置错误,WordPress 本身也会把/about/301 到/about。
四、两个必须知道的坑
坑 1:rewrite ... break 会终止整个 server 级 rewrite 脚本
nginx 会把 vhost 主文件以及它 include 的所有 server 级指令编译成同一个 rewrite 脚本。break 的语义是终止这个脚本剩余部分——不是"只跳出当前 if"。
后果:如果你的缓存直出规则排在反爬/拦截规则前面,只要命中了缓存,后面的规则(例如「某些 UA 返回 403」)会被整体跳过。
我实际的教训:把文件命名为 02-wpsc-static.conf 时,对已生成缓存的 URI(比如首页),AhrefsBot / SemrushBot 全部 200(没被拦);调整 include 排序、让静态直出规则排在最后,才恢复 403。
做法:把这个配置文件放在 extension 目录里排序最后的位置,include 顺序不要动。
坑 2:改了这个文件必须回归自检
改完跑两条命令,确认拦截和直出都还正常:
# 期望 403(反爬规则仍生效)
curl -sk -o /dev/null -w '%{http_code}\n' -A 'AhrefsBot/7.0'
--resolve www.mokiii.com:443:127.0.0.1 https://www.mokiii.com/
# 期望 200(正常访客仍能拿到页面)
curl -sk -o /dev/null -w '%{http_code}\n'
--resolve www.mokiii.com:443:127.0.0.1 https://www.mokiii.com/
五、怎么确认你真的命中了静态文件
两个判据,一起用最准:
# 1) 看响应头:PHP 模式会下发 cache-control: max-age=3, must-revalidate
# 命中静态文件时不会出现这个头,而是带 last-modified / etag
curl -skD - -o /dev/null https://www.mokiii.com/ | grep -iE 'HTTP/|cache-control|last-modified|etag'
# 2) 比字节:响应体应与缓存文件逐字节一致
curl -sk https://www.mokiii.com/ -o /tmp/live.html
md5sum /tmp/live.html wp-content/cache/supercache/www.mokiii.com/index-https.html
注意第 2 条的陷阱:有些 CDN(比如阿里云的边缘安全加速)会在边缘注入脚本(例如 RUM 监控),此时 md5 会不一致,但差异只在那一行注入代码。发现不一致时先看差异内容,别急着判定缓存没生效。
六、回滚
- 删掉那段 nginx 配置(或整个 extension 文件),
nginx -t && nginx -s reload; - 把
wp-cache-config.php里的$wp_cache_mod_rewrite改回0。
回滚后缓存仍然有效,只是退回 PHP 模式——不会因为回滚就变得"没缓存",这点可以放心。
一句话总结:WP Super Cache 默认只是"省数据库和模板",切到 mod_rewrite 再配 nginx 直出才是"连 PHP 都省"。但那段 rewrite ... break 的排序是硬要求,改完必须回归自测。

评论 (0)