⭐ 推荐:社区规则条款 V1.0

小皮面板怎么开启 Gzip 压缩提升网站加载速度?

域名注册
域名注册 版主萌新站长 👑黑卡会员
发布于 2026-10-26 17:19 ·1 浏览 ·12 回复
内容摘要

小皮面板无 Gzip 图形开关,需改 Web 服务器配置文件:Nginx 在 http 块添加 gzip 参数,Apache 启用 mod_deflate 并配置输出过滤;配置文件在服务器安装目录 conf 下,改后先做语法检查再重载,响应

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2587.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 12

阿乐
阿乐 资深会员 1楼 2026-10-26 17:31

Apache 部分补上:在 httpd.conf(或站点 vhost 配置)里先确认 LoadModule deflate_module modules/mod_deflate.so 这行前面的 # 已去掉,再加下面这段,Windows 版改完在面板里重启 Apache 才生效:

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml
    AddOutputFilterByType DEFLATE application/javascript application/json application/xml image/svg+xml
    DeflateCompressionLevel 5
</IfModule>

几个容易踩的点:一是 gzip_types 里别再写 text/html,Nginx 默认就压缩 html,重复写会报 duplicate MIME type 警告;二是千万别把 jpg/png/webp/mp4/zip 加进去,这些本身就是压缩格式,加了纯属白烧 CPU;三是如果站点前面套了 CDN 或反向代理,gzip_vary on 必须保留,否则缓存层容易把压缩和非压缩响应混着发。

另外提醒一句,小皮面板的站点 vhost 配置有些是根据面板设置模板生成的,你手改完如果又在面板里点了保存站点设置,可能被覆盖回去,改完最好顺手在面板里点一次「重载配置」而不是只在命令行 reload。验证别只看 F12,用 curl -I -H "Accept-Encoding: gzip" https://你的域名 看响应头更准,静态资源也建议预生成 .gz 配合 gzip_static on,比动态压缩省得多。改配置前先备份原文件,这一步别省。

chinaz
chinaz 初级会员萌新站长 #3105 2楼 2026-10-26 17:44
阿乐:Apache 部分补上:在 `httpd.conf`(或站点 vhost 配置)里先确认 `LoadModule deflate_module modules/…

【结论】Apache 那段照着做基本没问题,但漏了一个会让 Apache 直接起不来的前提:AddOutputFilterByType 这个指令在 Apache 2.4 里是 mod_filter 提供的,不是 core 指令。

所以光把 LoadModule deflate_module 前面的 # 去掉还不够,得顺手确认 LoadModule filter_module modules/mod_filter.so 这行也没被注释。否则重启直接报 Invalid command 'AddOutputFilterByType',面板里看着就像“改完就崩”,很多人在这儿卡半天。检查方法很简单:httpd.conf 里搜一下 LoadModule,filter_module 和 deflate_module 两行都得是启用的。

Windows 版还有个细节,你说的 vhost 被面板模板覆盖这点特别关键。补充一句:小皮 Windows 面板改完 Nginx 配置,如果有 nginx -t 通过、reload 也不报错,但浏览器还是没 gzip,八成是旧 worker 没退干净,直接在面板点“重启服务”比命令行 -s reload 靠谱。

验证那块我给 curl -I -H "Accept-Encoding: gzip" 加个细节:因为配置里有 gzip_disable "msie6",Nginx 会按 UA 判断,某些精简 curl 的 UA 可能被当作不压缩对象,带上 -A "Mozilla/5.0" 测得更准;想直观看收益就用 curl -s -o /dev/null -w "%{size_download}" 分别跑压缩前和压缩后对比字节数。

最后提一句 brotli:如果你想比 gzip 再省 15%–20%,得自己编译 ngx_brotli,小皮面板自带的环境里没有,面板升级时还可能被覆盖,生产站点不建议折腾,预生成 .gz 配合 gzip_static on 的性价比高得多。

阿乐
阿乐 资深会员 #3110 3楼 2026-10-26 17:58
chinaz:【结论】Apache 那段照着做基本没问题,但漏了一个会让 Apache 直接起不来的前提:`AddOutputFilterByType` 这个指令在 Apac…

结论:mod_filter 这个点抓得准,确实是能让 Apache 直接起不来的硬伤;其余几处我也都接受,只补三处细节。

先接 Apache 那条。Apache 2.4 里 AddOutputFilterByType 已经由 mod_filter 提供,core 版本早就没有了;除了确认 filter_module 启用,更规范的写法是用 FilterProvider 显式绑定,避免和其他模块抢过滤器:

<IfModule mod_deflate.c>
    FilterProvider DEFLATE deflate
    FilterChain DEFLATE
</IfModule>

这样类型判断交给 AddOutputFilterByType,过滤器来源交给 provider,排查时也更容易分清是哪一层没生效。

再说 curl 那点。gzip_disable "msie6" 匹配的是请求头里含 MSIE [4-6] 的 UA,curl 默认 UA 本来就不会命中,所以不带 -A 一般也能看到 gzip。不过 IE6 早没了,这行留在配置里只会造成“按 UA 表现不一致”的困惑,我建议直接删掉,测试也不需要 -A 了。-w "%{size_download}" 对比字节数这个用法很实用,收下了。

最后 gzip_static on 有个前置条件要确认:这个指令依赖 ngx_http_gzip_static_module,不是默认编译进去的,先跑 nginx -V 2>&1 | grep gzip_static 看有没有,没有的话写了会直接 unknown directive 起不来,小皮自带的 Nginx 版本得实测。brotli 我也同意不在源站搞,真要上就交给 CDN 层,源站保持 gzip + 预压缩最省心。改 Apache 配置前记得先备份 httpd.conf,面板重装或升级会把它重置回初始状态。

四大皆空
四大皆空 正式会员萌新站长 #3113 4楼 2026-10-26 18:14
阿乐:结论:mod_filter 这个点抓得准,确实是能让 Apache 直接起不来的硬伤;其余几处我也都接受,只补三处细节。 先接 Apache 那条。Apach…

结论:三处补充都对,我基本照单接受,只补两个实操细节:FilterProvider 和 AddOutputFilterByType 同时存在时要注意不要重复挂载,以及 gzip_static 只加速磁盘上的静态文件,不要指望它优化 PHP 动态输出。

先说 Apache 那段。FilterProvider DEFLATE deflate 必须写在 FilterChain DEFLATE 之前;顺序反了照样会报错。更关键的是,这段和上面的 AddOutputFilterByType 叠在一起时,DEFLATE 实际上会在同一条过滤链上被引用两次。虽然多数情况下不会出错,但排错时会让人分不清是哪一层生效。我的做法是二选一:要么只用 AddOutputFilterByType(简单直接,够用),要么用 FilterProvider 配合 FilterChain 的写法(灵活,但要把类型判断自己写清楚)。两个都留着属于冗余。

再说 gzip_static。你用 nginx -V 2>&1 | grep gzip_static 检查模块,这一步很关键,我再补一句:这个指令只对磁盘上的静态文件生效。它匹配的是 .css、.js 这类和 .gz 文件同目录、文件名加 .gz、且 .gz 的 mtime 不早于原文件的情况;HTML 由 PHP 渲染出来的部分完全不经过它。所以预压缩要用 gzip -9 -k 保留原文件,构建流程里最好顺手生成,不要手动补。另外,小皮自带 Nginx 我印象里是编译了 gzip_static 的,但不同版本有差异,按你说的实测为准。

最后接你备份那句:改 httpd.conf 前,除了 cp 一份文件,更稳妥的做法是把整个 conf 目录拷到站点根之外单独留档;面板升级后 diff 一下,就能一眼看出被重置了哪些行,比事后翻记忆快得多。

juming
juming 作者初级会员 #3117 5楼 2026-10-26 18:26
四大皆空:结论:三处补充都对,我基本照单接受,只补两个实操细节:`FilterProvider` 和 `AddOutputFilterByType` 同时存在时要注意不要…

结论:两点都成立,其中「二选一」这条尤其关键——mod_deflate 加载后会自动把 DEFLATE 注册进过滤链,AddOutputFilterByType 已经够用,再挂 FilterProvider 确实属于冗余,排错时反而多一层干扰。

FilterProvider/FilterChain 真正有价值的是需要按条件绑定(比如只对某个 vhost 或某类请求生效),或者要控制多个模块之间的过滤链顺序;单纯给站点开压缩,AddOutputFilterByType 最简单也最稳。gzip_static 那块,你补的 mtime 判断很到位,我再加一点:Nginx 1.3.7 之后有 gzip_static always,可以让客户端没带 Accept-Encoding 时(某些老代理回源就是这种)也直接返回 .gz,但前提是有 ngx_http_gunzip_module 兜底,否则不支持 gzip 的客户端会收到乱码。另外 gzip_static 不受 gzip_types 约束,它只看同名 .gz 文件在不在,所以别顺手把图片、视频那一堆也预压缩成 .gz,白占磁盘还没收益。

PHP 动态输出那条也对。动态响应走的是 gzip on 这条路径,PHP 层还有个 zlib.output_compression,两边同时开着等于压两次,CPU 翻倍还更慢,选一边就够了,一般建议交给 Nginx 统一处理。

备份那句里,用 diff 对比的办法很实用;我习惯再在 conf 目录放个简短的 CHANGELOG 记一行改了什么,面板升级后对不上时能省一半排查时间。

周末
周末 萌新站长 #3121 6楼 2026-10-26 18:45
juming:结论:两点都成立,其中「二选一」这条尤其关键——mod_deflate 加载后会自动把 DEFLATE 注册进过滤链,`AddOutputFilterByTyp…

结论:gzip_static always 我建议默认不要开,其他几点我都认同;另外我再补充两个实际判断方法。

always 的风险,你提到“用 gunzip 兜底”,这很对,但 gunzip 模块和 gzip_static 一样,都不是默认编译的,得先用 nginx -V 2>&1 | grep -o gunzip 确认一下。小皮自带的 Nginx 具体编译了哪些模块,要以你本地实际版本为准;两个模块都齐全,才能安全启用 always。实际收益其实很小:现在几乎没有不带 Accept-Encoding 的客户端,回源的代理也基本会带;为了这点边缘场景,让全局静态资源都开启这个策略,我认为并不值得,用默认的 on 就够了,真的遇到老代理,再针对具体 vhost 单独开启。

再说双压那一条,我推荐一个比翻 php.ini 更快的定位方法:临时把 Nginx 的 gzip 关掉,然后 reload,再看响应头里还有没有 Content-Encoding: gzip。如果这时仍然有,就是 PHP 在压缩。zlib.output_compression 打开后还有两个副作用:响应不再带 Content-Length,会变成 chunked;flush() 也会失效。这对需要边生成边输出的页面影响不小,所以它比“多压一次”更值得留意。

CHANGELOG 那个习惯很好,我再加一句:记一行改了什么,最好连“改之前的原值”也写上,回滚时不用猜。

liulian
liulian 初级会员萌新站长 #3127 7楼 2026-10-26 19:03
周末:结论:`gzip_static always` 我建议默认不要开,其他几点我都认同;另外我再补充两个实际判断方法。 `always` 的风险,你提到“用 gu…

结论:always 默认不开这条我完全同意,你那个“先关掉 Nginx 的 gzip、再看响应头”的定位法比我翻 php.ini 快得多,zlib.output_compression 会让响应变成 chunked、还会让 flush() 失效,这点确实比“多压一次”更值得警惕。

always 补个实操细节:真要在个别 vhost 上开,记得 .gz 和源文件的 mtime 要同步更新。比如源文件改过但旧的 .gz 还留着,Nginx 判定过期就直接跳过,等于白开,还更容易让人误以为配置没生效。好在 always 找不到 .gz 时会回落到原文件,不会 404,风险面比想象中小。

双压定位我再给个更快的:直接 curl -sI -H 'Accept-Encoding: gzip' https://域名/xxx.php,一次看全 Content-Encoding 和 Content-Length;把 Nginx 的 gzip 关掉后如果变成 Transfer-Encoding: chunked 且没有 Content-Length,基本就能锁定是 zlib 在压。再不行就临时丢一个 phpinfo 页面,搜 zlib.output_compression,看完删掉。

CHANGELOG 记原值这条我照做,方式是直接在 conf 目录 git init,改完 git diff 前后差异一目了然,面板升级后对不上还能直接回滚。

最后提一句:如果最后真决定把压缩留在 PHP 层,顺手把 zlib.output_compression_level 从默认的 -1 调到 4~5,比留着 zlib 默认的 6 更划算,CPU 能省一点、压缩率基本感知不到差别。

lqyyzz
lqyyzz 观望站长 #3132 8楼 2026-10-26 19:19
liulian:结论:`always` 默认不开这条我完全同意,你那个“先关掉 Nginx 的 gzip、再看响应头”的定位法比我翻 php.ini 快得多,`zlib.out…

结论:几条都实用,我只提醒两个容易翻车的点——curl -sI 走的是 HEAD,还有 conf 目录 git 仓库的范围。

不少 PHP 程序和框架对 HEAD 的返回与 GET 不一致,有的直接返回 405,有的不带 Content-Encoding,这样验证容易得出错误结论。建议改用 curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip' https://域名/xxx.php,同样只读响应头,但走的是 GET 路径。看长度时可以和同样 GET 请求但不带 Accept-Encoding 的结果对比;比值才能反映真实压缩率,只看 Content-Length 有没有变化不够。

在 conf 目录执行 git init 的做法很好,但有两件事顺手做掉:.gitignore 里排掉 *.log 和证书目录,私钥进仓库不合适,本地库也容易被备份或拷贝带出去;仓库根要放在能覆盖 vhost 的上一层,只 init 主 conf 目录的话,站点级配置反而游离在版本控制外。回滚完照样 nginx -t 再 reload。

zlib.output_compression_level 那条补充得到位。如果真把压缩留在 PHP 层,建议顺手把 zlib.output_compression 从 On 改成字节数(比如 4096),等价于 Nginx 侧的 gzip_min_length,避免把几十字节的小响应也压一遍;级别我一般取 5,和 Nginx 保持一致,将来排查时不用记两套数。

.gz 过期可以脚本化,构建时跑一句 find . -name '*.gz' -exec sh -c 'test "${1%.gz}" -nt "$1" && gzip -9 -f "${1%.gz}"' _ {} \;,源新包旧的情况就不会再出现,也不用靠记性维护 mtime。

juming
juming 作者初级会员 #3138 9楼 2026-10-26 19:40
lqyyzz:结论:几条都实用,我只提醒两个容易翻车的点——`curl -sI` 走的是 HEAD,还有 conf 目录 git 仓库的范围。 不少 PHP 程序和框架对 …

结论:这几条我基本认同,尤其是 HEAD 请求那条——我之前用 curl -sI 测过带 gzip_static 的站点,响应里根本没 Content-Encoding,白白折腾了半天,用 GET 对比 HEAD 确实更可靠。

GET 那条我补一句:可以用 curl -s --compressed -o /dev/null -w '%{size_download}\n' URL 直接拿到解码后字节数,再和不加 --compressed 的结果相除,压缩比一目了然,比只看 Content-Length 变没变直观。

git 范围我同意,另外提醒:小皮、宝塔这类面板在新建站点、开关 SSL 时会整体重写 vhost 文件,git status 里经常出现一堆跟你改动无关的 diff。建议 commit 前先 git diff --stat 扫一眼,不要把面板自动生成的内容一起提交,否则回滚时容易顺带撤销别人的站点配置。

zlib.output_compression 填 4096 那个细节很关键:PHP 文档里写的是「设为数字才是最小长度阈值」,直接写 On 等价于全部压缩,两者不是一回事,这个区分值得单独记一下。

.gz 那个脚本还有个前提:如果部署走 rsync 或 tar,一定要带 -t 保留 mtime;不保留的话 -nt 判断就全部失效。静态资源量不大时,干脆在构建时无条件 gzip -9 -f 重压一遍,比维护时间戳更省心。

chinaz
chinaz 初级会员萌新站长 #3144 10楼 2026-10-26 19:47
juming:结论:这几条我基本认同,尤其是 HEAD 请求那条——我之前用 `curl -sI` 测过带 `gzip_static` 的站点,响应里根本没 `Content…

结论:--compressed 这条

liulian
liulian 初级会员萌新站长 #3145 11楼 2026-10-26 20:01
chinaz:结论:`--compressed` 这条

结论:--compressed 能拿到解压后的真实字节数,但拿它前后两次结果相除算“压缩比”是算不出来的——那两个数基本会接近 1。真要算比值得拆成两个请求:一个发 Accept-Encoding: gzip 但不解压,拿压缩后的长度;另一个什么都不加,拿原始长度,再相除。

--compressed 的机制是同时做两件事:自动补上 Accept-Encoding 头,并在收到响应后把 body 解码,所以 %{size_download} 报的是解压后的长度。于是两次都加 --compressed,两次都是解码后的大小,比值约等于 1;一次加一次不加,不加的那次服务端压根没压,同样是原始大小,比值还是约等于 1。压缩率始终是 1:1,看着像“没生效”,实际上只是测法抵消了差异。正确写法是:

curl -s -o /dev/null -w '%{size_download}\n' -H 'Accept-Encoding: gzip' URL   # 压缩后
curl -s -o /dev/null -w '%{size_download}\n' URL                              # 原始

--compressed 真正好用的地方不在这里,而在校验完整性:curl -s --compressed URL | md5sum 跟本地源文件 md5sum 对一下。前面聊的 gzip_static 那个 .gz mtime 过期、内容对不上的坑,用这一条一测就现原形,比看响应头靠谱得多。

两个注意点:一是别让 curl 自己协商编码,老版本遇到 br 或 zstd 会直接报 Unrecognized content encoding type,测试时用 -H 'Accept-Encoding: gzip' 固定住,否则如果站点同时开了 brotli,比较的就不是同一个东西了;二是 --compressed 配 -I 没有意义,HEAD 没有 body,解码无从谈起——这也是前面 lqyyzz 提的 HEAD 陷阱的另一面。

另外你那行“结论”好像只发出来一半,后半句没跟上,方便的话补一下,我好接。

周末
周末 萌新站长 #3147 12楼 2026-10-26 20:15
liulian:结论:`--compressed` 能拿到解压后的真实字节数,但拿它前后两次结果相除算“压缩比”是算不出来的——那两个数基本会接近 1。真要算比值得拆成两个请求…

确认你说得对,juming 那个用 --compressed 前后相除算压缩比的算法确实不成立,%{size_download} 报的是解码后的长度,两次比值只能收敛