Apache本身不解析PHP,必须通过mod_proxy_fcgi将.php请求代理给PHP-FPM处理;需同时启用mod_proxy和mod_proxy_fcgi模块,确保PHP-FPM监听地址(Unix socket或TCP端口)与Apache配置严格匹配,并正确设置socket权限、路径映射及用户组对齐。

Apache 本身不解析 PHP,必须通过 mod_proxy_fcgi 把 .php 请求转发给 PHP-FPM 处理。这不是加载一个模块就完事,而是要打通“模块启用 → 后端监听 → 路径映射 → 权限对齐”整条链路。
确认并启用必要模块
Apache 2.4 必须同时启用 mod_proxy 和 mod_proxy_fcgi,缺一不可。否则会报错:Invalid command 'SetHandler' 或 No protocol handler was valid for the URL。
- 检查是否已加载:
apachectl -M | grep -E "(proxy|fcgi)",应看到两行:proxy_module (shared)proxy_fcgi_module (shared) - 未启用时,在
httpd.conf或apache2.conf中取消以下两行注释:LoadModule proxy_module modules/mod_proxy.soLoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so - Debian/Ubuntu 用户可直接运行:
sudo a2enmod proxy proxy_fcgi && sudo systemctl restart apache2
配置 PHP-FPM 监听方式
PHP-FPM 必须正在运行,且监听地址必须与 Apache 配置严格一致。推荐 Unix socket(性能更好、更安全),TCP 端口适合调试。
-
TCP 方式:在 PHP-FPM 的 pool 配置(如
www.conf)中设listen = 127.0.0.1:9000
Apache 中对应写:fcgi://127.0.0.1:9000或proxy:fcgi://127.0.0.1:9000 -
Unix socket 方式(推荐):
listen = /var/run/php/php8.1-fpm.sock
Apache 中写:proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost
注意竖线|和fcgi://localhost是固定写法,不能省略或改动 - 关键点:socket 文件权限必须允许 Apache 进程用户(如
www-data或apache)读写,否则报Connection refused或Permission denied;SELinux/AppArmor 启用时需额外放行
选择代理规则:SetHandler 还是 ProxyPassMatch?
两者都能转发 PHP 请求,但适用场景和写法逻辑不同。
-
SetHandler(简洁,适合统一配置):
适用于整个虚拟主机统一走同一 PHP-FPM 池,要求 Apache ≥ 2.4.9。
示例:<FilesMatch \.php$><br> SetHandler "proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost/"<br></FilesMatch>
Apache 自动补全脚本路径,无需手动拼接 -
ProxyPassMatch(灵活,兼容性好):
支持正则捕获和路径拼接,Apache 2.4.1+ 即可用,更适合多版本 PHP 或复杂路径结构。
示例:ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1
注意:/var/www/html/必须是 PHP 文件在磁盘上的真实绝对路径,否则 PHP-FPM 返回No input file specified
补充关键细节
几个容易忽略但直接影响成败的点:
-
DirectoryIndex必须包含index.php,否则访问/会返回空白页(WSOD):DirectoryIndex index.php index.html - 不需要启用
mod_rewrite——除非你用RewriteRule实现转发;SetHandler和ProxyPassMatch都不依赖它 - 多 PHP 版本共存时,为每个版本单独配置 PHP-FPM 池(不同 socket 或端口),再在对应虚拟主机中用
SetHandler或ProxyPassMatch指向指定池 - 修改配置后务必重启 Apache:
sudo systemctl restart apache2(Debian/Ubuntu)或sudo systemctl restart httpd(RHEL/CentOS)


















