傳統 LAMP 架構中 Apache 通常以 mod_php(Prefork MPM)運行 PHP,存在內存佔用大、無法平滑重啟、版本切換困難等痛點。Nginx + PHP-FPM 雖成主流,但遷移成本高、Rewrite 規則不兼容、團隊技術棧調整大。Apache 2.4+ 原生 mod_proxy_fcgi 模塊提供了最優雅的方案:保留 Apache 架構,享受 PHP-FPM 的進程管理、多版本隔離、平滑重載優勢。
| 模塊 | 特點 | 推薦度 |
|---|---|---|
mod_fcgid | Apache 管理進程,無需 PHP-FPM,但配置複雜、調試困難 | ⭐⭐ |
mod_fastcgi | 老牌模塊,2007 年停更,不推薦生產環境 | ⭐ |
mod_proxy_fcgi | Apache 2.4+ 內置,一行 ProxyPassMatch 搞定,穩定高效 | ⭐⭐⭐⭐⭐ |
CentOS 6 默認 Apache 2.2,但社區已移植 mod_proxy_fcgi 至 EPEL 源。
# 1. 安裝 EPEL 源 yum install epel-release -y # 2. 直接安裝模塊(已編譯好,無需手動編譯 Apache) yum install mod_proxy_fcgi -y # 3. 重啟 Apache 生效 service httpd restart
httpd -M | grep proxy # 輸出應包含: # proxy_module (shared) # proxy_fcgi_module (shared)
假設已編譯安裝多個 PHP 版本,各自運行獨立 PHP-FPM:
127.0.0.1:9056127.0.0.1:9070127.0.0.1:9074127.0.0.1:9081<VirtualHost *:80>
ServerName site-php56.example.com
DocumentRoot "/var/www/html/site_php56"
# 關鍵:禁用全局 php5_module 處理 .php
# 這行通常在 /etc/httpd/conf.d/php.conf 中,需註釋掉
# AddHandler php5-script .php
# 核心指令:將 .php 請求代理到對應 PHP-FPM
ProxyPassMatch "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9056/var/www/html/site_php56/$1"
<Directory "/var/www/html/site_php56">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName site-php74.example.com
DocumentRoot "/var/www/html/site_php74"
ProxyPassMatch "^/(.*\.php(/.*)?)$" "fcgi://127.0.0.1:9074/var/www/html/site_php74/$1"
<Directory "/var/www/html/site_php74">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
ProxyPassMatch:正則匹配 .php 結尾請求(含 PATH_INFO),代理到 fcgi:// 協議$1 保留匹配的相對路徑,確保 SCRIPT_FILENAME 正確傳遞AddHandler php5-script .php 避免衝突現象:訪問 /subdir/(無 index.php)時,ProxyPassMatch 仍嘗試代理,返回 PHP-FPM 404 而非 Apache 403/自動索引。
原因:正則 ^/(.*\.php(/.*)?)$ 應該不匹配無 .php 的 URL,但某些情況下會誤觸發(疑似模塊 Bug)。
解決方案:
# 方案 A:優化正則,僅匹配確實存在的 .php 文件(需 mod_rewrite 配合)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+\.php(/.*)?)$ fcgi://127.0.0.1:9074/var/www/html/site/$1 [P,L]
# 方案 B(推薦):每個目錄放置 index.html 避免空請求落入 PHP-FPM
# 生產環境通常關閉 DirectoryIndex 目錄索引,此方案最穩健
配置 ProxyPassMatch 的目錄下 Options +Indexes 失效。生產環境建議關閉目錄索引,無影響。
; /usr/local/php74/etc/php-fpm.d/www.conf [www] user = www group = www listen = 127.0.0.1:9074 listen.owner = www listen.group = www listen.mode = 0660 pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 pm.max_requests = 1000 ; 慢日誌排查性能瓶頸 slowlog = /var/log/php-fpm/74-slow.log request_slowlog_timeout = 5s ; 安全限制 security.limit_extensions = .php .php7 .phtml php_admin_value[open_basedir] = /var/www/html/site_php74:/tmp:/proc php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
mod_http2,配合 ProxyPassMatch 大幅提升並發SetEnv proxy-sendcl 1 SetEnv proxy-nokeepalive 1 避免連接洩漏php -d opcache.enable_cli=1 -r "opcache_compile_file('...');"php-fpm_exporter 監控進程數、請求耗時、慢查詢/etc/httpd/conf.d/php.conf 中 AddHandler 已註釋ProxyPassMatch 路徑open_basedir 限制站點目錄PATH_INFO 支持(ThinkPHP、Laravel 等框架)mod_php 配置,緊急時切換回來CentOS 6/7 下利用 EPEL 源的 mod_proxy_fcgi,無需升級 Apache 即可實現 PHP-FPM 多版本共存。核心在於虛擬主機級別的 ProxyPassMatch 精準路由,配合 PHP-FPM 池隔離,達成「同一服務器、多版本共存、互不干擾」的生產級架構。此方案遷移成本低、風險可控,是 LAMP 堅守者的最佳進化路徑。