Apache + PHP-FPM 与 Mod_deflate

VPS 操作系统升级到 CentOS 7,有了 Apache 2.4 便迫不及待的尝试了一下 MPM event + PHP-FPM 组合。使用 Google PageSpeed 测试性能的时候却发现提示没开启网页 gzip 压缩。这个问题的解决很意外,记录在这里与大家分享。

之前服务器 Apache 运行在 prefork 模式,一直采用 mod_deflate 提供网页压缩传输功能。切换 Apache MPM 模式的时候除了有限的几个需要调整的参数外其它的都没有变化。所以 deflate 怎么就突然不工作了呢?

第一时间想到的就是,因为 PHP-FPM 是 Apache 之外的,可能与 deflate 协调不好。就试了试不需要通过 PHP-FPM 解释的 html 网页,果然是开启了 gzip 的。然后在网上拼命 Google 相关问题。别说,还真有人提到这个问题,只不过他是在 Apache 2.2 上,其它组件一样但这里是 Zend Opcache 而不是 APC。症状一样:

UPDATE: The problems seems to be with anything that is processed by PHP, if I copy the html output to a .html file and then fetch it, it will be compressed, if I rename the same file to .php and fetch it the output won’t be compressed.

我一度为了能使用网页压缩而开启了 PHP 内置的 Zlib 压缩,在 /etc/php.ini 中修改 Zlib 压缩参数为,

zlib.output_compression on

但是WordPress 中的 WP Super Cache 一个劲儿的提示说开了 Zlib 不太好之类的 blah blah。

于是继续找解决办法,结果却是无意中解决了。这是在调整 Apache 的参数配置文件,那一大堆 conf 文件的时候解决的。方法倒是很简单,简单到至今我都不太确定是不是真的是这个情况:将 deflate 配置放到 <Location /> 而不是 <Directory /> 里面。( )

因为 Apache 2.4 里将本来放在 httpd.conf 里的配置分割开来放到了 conf.modules.d 文件夹下面的多个 conf 文件里。受到启发,我也把 vhost.conf 里的全局配置提出来放到了新的 00-common.conf 里面。我的具体部署是,在 Apache 的 conf.d 文件夹下新增了两个配置文件, 00-common.conf 放置全局 vhost 配置,比如 deflate 设置等;01-bad.conf 放置屏蔽一些 spider 和 乱七八糟广告 bot 的配置。

为了对所有的虚拟主机(同一服务器 Apache 上配置的多个网站)同时适用,就把 mod_deflate 的配置改成下面的样子(其中一些具体的指令规则已经是很久很久前从网上搜集的了,没记录具体的出处):

# Enclose configurations of mod_deflate 
# by <Location /> </Location> 
# instead of <Directory /> </Directory> 
# to make them effective to PHP-FPM.
<Location />
    # mod_gzip
    <ifModule mod_gzip.c>
        mod_gzip_on Yes
        mod_gzip_dechunk Yes
        mod_gzip_item_include file \.(html?|txt|css|js|php|pl|css\?.*|js\?.*)$
        mod_gzip_item_include handler ^cgi-script$
        mod_gzip_item_include mime ^text/.*
        mod_gzip_item_include mime ^application/x-javascript.*
        mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
    </ifModule>
 
    # mod_deflate
    <IfModule deflate_module>
        <IfModule filter_module>
            AddOutputFilterByType DEFLATE text/plain
            AddOutputFilterByType DEFLATE text/css
            AddOutputFilterByType DEFLATE text/css\?(.*)
            AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml application/xml-dtd
            AddOutputFilterByType DEFLATE image/svg+xml
            AddOutputFilterByType DEFLATE application/rss+xml
            AddOutputFilterByType DEFLATE application/atom_xml
            AddOutputFilterByType DEFLATE application/x-javascript
            AddOutputFilterByType DEFLATE application/x-httpd-php
            AddOutputFilterByType DEFLATE application/x-httpd-fastphp
            AddOutputFilterByType DEFLATE application/x-httpd-eruby
            AddOutputFilterByType DEFLATE text/html text/htm
            AddOutputFilterByType DEFLATE font/otf font/opentype application/font-otf application/x-font-otf
            AddOutputFilterByType DEFLATE font/ttf font/truetype application/font-ttf application/x-font-ttf
        </IfModule>
 
        SetOutputFilter DEFLATE
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
        SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar|7z)$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.avi$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.mov$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.mp3$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.mp4$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.rm$ no-gzip dont-vary 
        SetEnvIfNoCase Request_URI \.(?:docx?|pptx?|pptm|xlsx?)$ no-gzip dont-vary 
    </IfModule> 
</Location>

跟之前的最大区别就是代码上下两端的 <Location /> </Location>。Enclose configurations of mod_deflate by <Location /> </Location> instead of <Directory /> </Directory> to make it effective to PHP-FPM in case of php files are not compressed before sending to client but html files and others are compressed..

不过,到底是不是因为这个才使得在 Apache + PHP-FPM 的情况下能对 PHP 文件执行 deflate 压缩,只在虚拟机里试了试,没在服务器上验证。主要是累得不想折腾了。如果有朋友有这方面的经历,请一定留言告知一声。©

本文发表于水景一页。永久链接:<http://cnzhx.net/blog/apache-php-fpm-and-mod_deflate/>。转载请保留此信息及相应链接。

3 条关于 “Apache + PHP-FPM 与 Mod_deflate” 的评论

  1.   DeflateCompressionLevel 9
      SetOutputFilter DEFLATE
      BrowserMatch ^Mozilla/4 gzip-only-text/html
      BrowserMatch ^Mozilla/4\.0[678] no-gzip
      BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
      BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
      SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip
      Header append Vary User-Agent env=!dont-vary 
    # 博主补充,因作者评论时部分字符被过滤
    # 博主根据评论内容而搜索参考了:http://stackoverflow.com/questions/18018624/apache-gzip-compression-not-compressing-js-css-in-other-directories
    # 水景一页 2014-12-20 21:47
    
    # Cache Control Settings for one hour cache
    Header set Cache-Control "max-age=2592000, public"
    Header set Cache-Control "max-age=2592000, public, must-revalidate"
    Header set Cache-Control "max-age=2592000, must-revalidate"
    HostnameLookups Off
    
    • 对不起,评论里只接受少量语法。另外,为了过滤一些比较明显的spam,还自己设定了一些条件,可能会误挡某些正常评论。

      你提供的代码是为了补充 deflate 设置的吗?好像在哪里看到过测试,说压缩级别设置高了虽然可以压缩得更多,但是相比较更多的CPU消耗是不划算的。所以这里没设置。

      BrowerMatch 是干什么的?另外,Cache Control 是与 mod_deflate 无关的,所以没有在这里写出来。

雁过留声,人过留名

电子邮件地址不会被公开。 必填项已用*标注

特别提示:与当前文章主题无关的讨论相关但需要较多讨论求助信息请发布到水景一页讨论区的相应版块,谢谢您的理解与合作!请参考本站互助指南