Ubuntu20.04 Apache多PHP版本多站点用户权限隔离配置问题
问题根因
配置不生效的核心原因共3点:
- 安装php7.4时系统默认会启用
libapache2-mod-php7.4模块,PHP直接作为Apache内置子进程运行,完全没有走预期的FCGI流程 - 仅安装
libapache2-mpm-itk包不会自动启用MPM-ITK,Ubuntu 20.04默认启用mpm_event模块,与MPM-ITK冲突,<IfModule itk.c>块内的AssignUserID规则根本没有被加载 - mod_php模式本身不支持多PHP版本共存,同一时间Apache只能加载一个版本的PHP模块,无法满足多站点使用不同PHP版本的需求
正确配置方案(适配Ubuntu 20.04,同时满足多PHP版本+站点权限隔离)
1. 清理冲突配置
先卸载冲突组件,禁用无效模块:
# 卸载所有版本的mod_php,避免与FCGI模式冲突 sudo apt remove -y libapache2-mod-php* # 禁用默认的MPM模块 sudo a2dismod mpm_event mpm_prefork mpm_worker # 禁用残留的PHP模块 sudo a2dismod php7.4 php8.0 php8.1 php8.2 2>/dev/null
2. 启用必要的Apache模块
# 启用MPM-ITK实现静态文件访问的权限隔离 sudo a2enmod mpm_itk # 启用FCGI相关模块用于对接PHP-FPM sudo a2enmod actions fcgid alias proxy_fcgi setenvif # 重启Apache加载模块 sudo systemctl restart apache2
3. 安装多版本PHP-FPM
所有PHP版本必须安装fpm包,禁止安装mod_php包。如果需要使用Ubuntu默认源以外的PHP版本,先添加PPA源:
sudo apt install -y software-properties-common sudo add-apt-repository -y ppa:ondrej/php sudo apt update
按需安装对应版本的PHP-FPM及扩展,示例为PHP7.4、PHP8.1两个版本:
# 安装PHP7.4组件 sudo apt install -y php7.4-fpm php7.4-cli php7.4-mbstring php7.4-mysql php7.4-curl # 安装PHP8.1组件 sudo apt install -y php8.1-fpm php8.1-cli php8.1-mbstring php8.1-mysql php8.1-curl
4. 为每个站点配置独立PHP-FPM池
这是权限隔离的核心:每个站点对应一个独立的FPM运行池,以站点专属用户身份运行PHP进程,完全不共用进程资源。
以u-site1站点使用PHP7.4为例:
# 复制默认FPM池模板生成站点专属配置 sudo cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/u-site1.conf # 编辑专属池配置 sudo vi /etc/php/7.4/fpm/pool.d/u-site1.conf
修改以下配置项,其余参数保持默认即可:
; 池名称改为对应站点标识 [u-site1] ; 监听路径设为专属sock文件,禁止多个站点共用 listen = /run/php/php7.4-u-site1.sock ; PHP进程运行身份设为站点专属用户/用户组 user = u-site1 group = u-site1 ; sock文件权限配置,保证Apache可正常访问 listen.owner = www-data listen.group = www-data listen.mode = 0660
保存后重启对应版本的PHP-FPM服务:
sudo systemctl restart php7.4-fpm
- 其他站点、其他PHP版本的FPM池按相同逻辑配置即可,确保每个站点对应独立的池、独立的sock文件、独立的运行用户。
5. 配置Apache虚拟主机
修改站点虚拟主机配置,去掉包裹AssignUserID的<IfModule>判断(避免模块未加载时配置静默失效),同时添加PHP请求转发规则,示例配置如下:
<VirtualHost *:80> ServerName site1.local ServerAdmin info@site1.local DocumentRoot /home/u-site1/site1.local/html CustomLog ${APACHE_LOG_DIR}/site1.local.log combined ErrorLog ${APACHE_LOG_DIR}/site1.local-error.log # 控制Apache访问静态文件的运行身份,实现静态资源权限隔离 AssignUserID u-site1 u-site1 <Directory "/home/u-site1/site1.local/html"> Options All -Indexes AllowOverride All Require all granted </Directory> # 将PHP请求转发到对应站点的专属FPM池 <FilesMatch \.php$> SetHandler "proxy:unix:/run/php/php7.4-u-site1.sock|fcgi://localhost" </FilesMatch> </VirtualHost>
如果站点需要使用其他PHP版本,只需要把SetHandler里的sock路径替换为对应版本、对应站点的FPM sock路径即可。
6. 配置站点目录权限
按最小权限原则设置目录权限,彻底杜绝跨站读写:
# 重置站点目录属主 sudo chown -R u-site1:u-site1 /home/u-site1/site1.local # 目录权限设为750,其他用户完全无法读取、遍历目录内容 sudo chmod 750 /home/u-site1 sudo chmod 750 /home/u-site1/site1.local sudo chmod -R 750 /home/u-site1/site1.local/html # 仅对需要写入的子目录(如上传目录)单独配置写权限,禁止全局写 # sudo chmod 770 /home/u-site1/site1.local/html/uploads
配置完成后启用站点并重载Apache:
sudo a2ensite site1.local.conf sudo systemctl reload apache2
有效性验证
配置完成后通过以下方式确认隔离生效:
- 访问站点的phpinfo页面,
Environment下的USER字段显示为站点专属用户(如u-site1)而非www-data - PHP脚本创建的文件属主、属组均为站点专属用户/用户组
- 用站点专属用户尝试访问其他站点的目录,会直接返回Permission denied
- 执行
ps aux | grep php可看到每个站点的PHP进程都由对应专属用户运行 - 不同站点配置不同版本的FPM转发规则后,phpinfo显示的PHP版本与配置一致
注意事项
- 不要使用mod_php搭配MPM-ITK做权限隔离,一方面无法支持多PHP版本,另一方面Ubuntu 20.04源内的mpm-itk与mod_php存在setuid兼容问题,会出现文件属主异常的情况
- 禁止多个站点共用同一个FPM默认池(www.conf),否则所有PHP进程都会以www-data身份运行,权限隔离完全失效
- 站点用户的家目录权限不要设为700,否则Apache进程无法进入目录读取文件,会返回403错误,设为750即可
内容的提问来源于stack exchange,提问作者Maq
相关产品推荐
相关产品推荐

