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
    
  2. 你的评论設定沒有接受語法,所以有些字被過濾掉。

    • 对不起,评论里只接受少量语法。另外,为了过滤一些比较明显的spam,还自己设定了一些条件,可能会误挡某些正常评论。

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

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

时间过去太久,评论已关闭。
如果您有话要说,请到讨论区留言并给出此文章链接。
谢谢您的理解 :-)