这篇文章最初记录了给 LNMP 编译 ngx_pagespeed 的过程。该项目现在已经归档,旧版下载地址、PSOL 二进制和重新编译 Nginx 的步骤不再适合作为安装指南。保留过时代码会给读者带来供应链和运维风险,因此本文改为现代性能优化路线。
为什么不再推荐 ngx_pagespeed
Apache 的 incubator-pagespeed-ngx 仓库已归档。归档项目不会按现代 Nginx、OpenSSL、编译器和浏览器行为持续修复。
为一个停止维护的模块自行编译 Nginx,会增加:
- 安全更新时的重新构建与回归成本。
- 动态模块 ABI 与发行版包不兼容的风险。
- 来源、校验和与旧二进制依赖的供应链风险。
- 页面被自动重写后难以定位的缓存和展示问题。
仍在使用的老站应先盘点哪些 PageSpeed filter 真正生效,再逐项迁移,不要直接卸载后凭感觉观察。
从测量开始
至少建立三层指标:
- 真实用户: LCP、INP、CLS、错误率、关键业务转化。
- 实验室: Lighthouse、WebPageTest 或可重复的浏览器性能脚本。
- 服务器: TTFB、上游响应、缓存命中率、带宽、CPU、内存和慢查询。
测试移动网络、缓存冷启动和登录态。单次本机 Lighthouse 分数不能代表真实用户体验。
让应用和 CDN 做正确的事
静态资源指纹与长期缓存
只有文件名包含内容哈希时,才适合一年 immutable 缓存:
location ~* \.(?:css|js|woff2|png|jpg|jpeg|webp|avif)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri =404;
}
如果 app.js 每次发布仍使用相同文件名,不能配置 immutable。HTML 则通常需要更短缓存或协商缓存,避免发布后长时间引用旧资源。
压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types
text/plain
text/css
application/json
application/javascript
application/xml
image/svg+xml;
Brotli 需要 Nginx 构建或平台模块支持。CDN 已压缩时要避免重复工作,并检查 Vary: Accept-Encoding、缓存键和实际响应头。
图片
- 在上传或构建阶段生成符合展示尺寸的派生图。
- 按浏览器和业务能力提供 WebP/AVIF,但保留可用回退。
- 为图片输出宽高,减少布局偏移。
- 首屏关键图片不要盲目懒加载,其余图片使用原生 lazy loading。
- 不把 4000 像素原图缩在 300 像素容器里。
协议与连接
优先使用发行版或托管平台维护的 Nginx、TLS 和 HTTP/2;HTTP/3 应在 CDN/入口层有监控地启用。不要为了一个性能模块长期锁死整个服务器软件版本。
WordPress/LNMP 常见瓶颈
- 页面缓存与对象缓存是否适合登录态和个性化内容。
- PHP-FPM 进程数、慢日志和 OPcache 是否基于真实内存调整。
- 数据库慢查询、autoload 选项和无索引 meta 查询。
- 第三方脚本、字体和广告是否阻塞主线程。
- 主题/插件是否在每个页面加载不需要的 CSS、JS 和查询。
- Cron、队列和图片生成是否挤占前台请求资源。
优化顺序通常是删除不必要工作、建立缓存、缩小资源,再考虑更复杂的自动重写。
迁移检查
- 保存当前 Nginx 配置、模块列表和代表性页面瀑布图。
- 列出启用的 PageSpeed filter 及它们生成的缓存 URL。
- 在暂存环境分别关闭 filter,找出依赖它的图片、CSS、JS 与缓存规则。
- 把压缩、图片派生、资源指纹和 HTML 优化迁移到构建/CDN。
- 清理缓存并验证旧 PageSpeed URL 的重定向或失效策略。
- 小流量发布,比较真实用户指标和错误日志。
- 确认回滚后再移除模块和旧缓存目录。
性能优化的目标是让系统更快也更容易维护。依赖一个归档的“自动优化黑盒”,通常与这两个目标都相反。