PHP-FPM 是一个简单可靠的 FastCGI 进程管理器(FastCGI Process Manager),从 PHP 5.3.3 开始就成为了 PHP 的内置管理器。Apache 官方网站也提供了配置 Apache httpd 2.4.x 使用 mod_proxy_fcgi 和 PHP-FPM 运行 php 程序的基本方法和设置运行方式的简单介绍。然而,在实际操作过程中发现这个东西还挺麻烦的,因此汇总记录下查找的资料以备查阅。
为了省事,我们以官方文档为模板进行操作。基本的安装和配置已经在“更改 LAMP 执行方式为 PHP-FPM”一文中有记录。这里仅记录设置代理方式的问题。
使用 PHP-FPM 就意味着不用 Apache 内置的 mod_php,也就是要在 Apache 之外处理 php 程序的解释运行问题。虽然看起来是多引入了一个额外的程序 PHP-FPM,既占 CPU 又占内存,但实际上这样一来,因为 Apache 可以专心处理除 php 之外的静态网页及元素,反而 httpd 进程本身占用的 CPU 和内存可以显著降低,从而从整体上降低资源消耗。
快捷目录:
1. PHP-FPM 监听方式
官方文档提到的 PHP-FPM 监听方式(接收 Apache 转过去的处理 PHP 的请求的方式)有 2 个。这是在 PHP-FPM 的 pool 配置文件中设置的监听方式,例如:
```plaintext
listen = 127.0.0.1:9000
listen = /var/run/php-fpm/php-fpm.sock
```
2. Apache 发送 PHP 处理请求的方式
原来的 mod_php 采用 SetHandler 的方式处理 php 文件并不需要特别的设置,因为在安装 PHP 的时候会自动在 Apache 的配置文件目录写入一个 php.conf 的配置文件,里面有告诉 Apache 处理 php 需要的操作:
以下是重构后的内容:
Apache 的 mod_php 和 PHP-FPM 配置方式有很多种,其中一种简单的、全局的处理方式是通过 SetHandler 指令实现的。这种方式在收到每个请求之后才处理,适用于全局设置。然而,对于 PHP-FPM 来说,这种方式需要到 Apache 2.4.9 版本中才能使用。
在 Apache 2.4.10 版本中,关于 mod_php 和 PHP-FPM 的配置和冲突规避的逻辑判断已经默认设置好。目前 Apache 转发代理的方式有三种:ProxyPass、ProxyPassMatch 和带 [P] 参数的 mod_rewrite。这三种方式组合起来共有 6 种不同的配置方法。为了简化配置过程,官网提供了一个复杂度和灵活性都居中的解决方案作为例子(ProxyPassMatch)。
下面分别针对 SetHandler、ProxyPassMatch、ProxyPass 和 mod_rewrite 这四种处理方式进行举例说明。
3.1 SETHANDLER
SetHandler 是一种适应性最强的处理方式,部署一次之后,所有的虚拟主机
首先,我们需要在 `/etc/php-fpm.d/www.conf` 文件中设置监听方式。在这个例子中,我们将使用 IP:Port 监听方式,即:
```
listen = 127.0.0.1:9000
```
接下来,我们需要在 `vhost.conf` 文件中设置一个全局的代理。在所有 `
```
<FilesMatch \.php$> SetHandler "proxy:fcgi://127.0.0.1:9000"</FilesMatch>
```
或者,您可以将此设置直接放在 `php.conf` 文件中。
完成上述设置后,您的 PHP-FPM 就配置好了。这就是为什么水景一页非常喜欢这个简单的配置方法。
如果您希望采用 UDS(Unix Domain Socket)方式监听,例如:
```
listen = /var/run/php-fpm/php-fpm.sock
```
您可以按照以下步骤进行配置:
1. 在 `Proxy` 标签中声明一个参数(不关心具体是哪个),否则代理无法提前注册。示例代码如下:
```
<Proxy "unix:/var/run/php-fpm/php-fpm.sock|fcgi://php-fpm"> # we must declare a parameter in here (doesn't matter which) or it won't register the proxy ahead of time ProxySet disablereuse=off</Proxy># Redirect to the proxy<FilesMatch \.php$> SetHandler proxy:fcgi://php-fpm</FilesMatch>
```
2. 测试配置。但是,水景一页发现在 Apache 启动时出现错误,提示 `ProxySet URL must be absolute!`,而如果是 `unix:///var/run/php-fpm/php-fpm.sock|fcgi://php-fpm`,就没有问题。此外,网页出现白板,页面源文件显示 php 没有运行而是直接显示源代码。对于 Apache 2.4.10,您可以尝试使用上述配置方法。
重构内容:
## 3.2 PROXYPASSMATCH
在前面的文章中,我们已经介绍了如何将 mod_php 切换到 PHP-FPM。关键点在于:
1. 在每个 `
2. 即使使用相同的 pool,也需要在设置的时候修改 pool 后面的 webroot 路径;
3. 有些特殊的网站网页地址 url 与系统文件路径 dir 之间匹配的问题,简单的一条 ProxyPassMatch 可能还不够,比如那个设置 phpMyAdmin 的例子(见上文)。
假设采用 IP:Port 监听方式,同 3.1。然后,在每个 `
```apache
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/path/to/webroot/$1
```
特别注意的是,红色字体部分需要与每个 `
ProxyPassMatch 只满足特定正则模式的内容才会匹配并执行此规则。这里的模式是:
```regex
^/(.*\.php(/.*)?)$
```
从网站(虚拟主机 `
括号里的内容可以用 `$1` 来表示,以方便后面引用它。通过 mod_proxy_fcgi 来转发的代理,使用 fastCGI 协议,转到 PHP-FPM 监听的端口。改变 IP 地址和/或端口号就可以要转到的不同的 pool。用这个可以实现服务器分流、均衡等。
在 Nginx 配置文件中,我们可以使用以下方法将 PHP 请求代理到 FastCGI 服务器:
1. 首先,确保你的虚拟主机配置正确,并且 DocumentRoot 路径与 FastCGI 服务器的路径匹配。例如:
```nginx
server {
listen 80;
server_name example.com;
root /path/to/your/documentroot/;
index index.php index.html index.htm;
location ~ \.php$ {
fastcgi_pass fcgi://127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
```
2. 如果你的服务器没有设置 `DirectoryIndex`,你需要手动设置它。例如:
```nginx
location ~ \.php$ {
fastcgi_pass fcgi://127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
```
3. 如果你的服务器支持 UDS(Unix Domain Sockets),你可以使用 `ProxyPass` 和 `ProxyPassMatch`。例如:
```nginx
location ~ \.php$ {
ProxyPass uWSGI://127.0.0.1:9000;
ProxyPassReverse uWSGI://127.0.0.1:9000;
}
```
4. 如果以上方法都不支持持久连接(persistent connections),你可以尝试使用 `mod_rewrite`。但是需要注意的是,这种方法不支持持久连接。例如:
```nginx
location ~ \.php$ {
rewriteEngine On;
RewriteRule ^(.*)$ fastcgi://127.0.0.1:9000/path/to/your/documentroot/$1 [P,L] last;
}
```
水景一页无法使找到的几个示例正常工作,这会导致 PHP 源代码直接展示在网页上,或者在网页的源文件中。既然这样不好,就不再浪费版面了。如果大家有兴趣,可以查看以下几个示例:
1. http://serverfault.com/questions/398834/understanding-apache-2-4-mod-proxy-fcgi-and-rewriterules-in-htaccess
2. http://serverfault.com/questions/450628/apache-2-4-php-fpm-proxypassmatch
3. http://www.gossamer-threads.com/lists/apache/users/409168#409168
经过这么多的尝试和探索,我来给大家一个建议吧,以免大家像我一样走弯路。从性能和便利程度来看,目前还是建议使用 ProxyPassMatch,直到 Apache 2.4.10 版本,然后一次性切换到 SetHandler。这是一个比较好的过渡方案。但是,考虑到 CentOS 上游 RedHat 官方的 backporting 政策,Apache 2.4.10 可能需要等到下一次大的系统升级(例如 CentOS 8)时才会加入。
此外,关于 PHP-FPM 处理方式中的一个安全警告,也值得大家关注。