虚拟主机方案 – Apache + SuEXEC + (F)CGI + PHP-CGI

首先非常感谢浪点主机技术支持给我的方向,使我有机会能够了解虚拟主机的另一方案。

A. 特点
1. 权限分离,用户间互不干扰。
2. 相对使用ITK MPM方案内存需求更小,响应速度更快,并发高。
3. 可定制性强。

B. 应用程序说明
Apache: 不多说,HTTP服务器。
SuEXEC: Apache的模块,用于实现CGI或SSI应用程序的用户权限分离。
(F)CGI: Apache的模块,用于使Apache能够执行CGI和PHP-CGI。
PHP-CGI: PHP的CGI接口版本。

C. CGI模块和FastCGI模块的区别和适用环境
CGI模块为每个CGI请求fork一个新的进程,处理完成后该进程释放。适用于并发要求不高,内存资源少的系统。
FastCGI模块采用常驻的进程处理请求,由模块统一调度。适用于并发要求高,内存充足的系统。

D. 以Ubuntu 10.04 系统为例的配置实例
1. 安装应用程序
CGI方案

sudo apt-get install apache2 apache2-mpm-worker apache2-suexec-custom php5-cgi

FastCGI方案

sudo apt-get install apache2 apache2-mpm-worker apache2-suexec-custom libapache2-mod-fcgid php5-cgi

2. 配置Apache2
a. 为 /etc/apache2/conf.d/security 增加如下内容

<Directory />
	Options -FollowSymLinks +SymLinksIfOwnerMatch
</Directory>

注:禁止用户通过软链接访问其它用户文件。

b. 启用模块
CGI方案

sudo a2enmod actions
sudo a2enmod cgi
sudo a2enmod include
sudo a2enmod rewrite
sudo a2enmod suexec

FastCGI方案

sudo a2enmod fcgid
sudo a2enmod include
sudo a2enmod rewrite
sudo a2enmod suexec

3. 配置 SuEXEC
文件 /etc/apache2/suexec/www-data 内容如下

/var/web
web/cgi-bin

4. 配置 PHP-CGI
为 /etc/php5/cgi/php.ini 增加一行

cgi.fix_pathinfo=1

5. 配置用户
a. 创建目录

sudo mkdir -p /var/web/username/{config,php-cgi-bin,home}
sudo mkdir -p /var/web/username/home/web/{www,cgi-bin}

b. 创建用户与组

sudo useradd -d /var/web/username/home -u xxx -g xxx -G sftp -s /bin/false username
sudo usermod -G username -a www-data

注:sftp 方案详见我的另一日志;www-data需要加入此用户组,这样才能访问用户文件。

c. 虚拟主机配置文件模板
/var/web/username/config/vhost 为虚拟主机配置文件,将软链接到 /etc/apache2/site-enabled/ 目录中。下面是模块,需要修改USERNAME部分。
CGI方案

<VirtualHost *:80>
    ServerName DOMAIN_NAME
    ServerAdmin ADMIN_EMAIL_ADDRESS
 
    DocumentRoot /var/web/USERNAME/home/web/www
    ScriptAlias /php-cgi-bin /var/web/USERNAME/php-cgi-bin/
    <Directory /var/web/USERNAME/home/web/www>
        AddHandler application/x-httpd-php5 php
        Action application/x-httpd-php5 /php-cgi-bin/php-cgi-wrapper
        AllowOverride AuthConfig FileInfo Indexes Limit
        AddType text/html .shtml
        AddOutputFilter INCLUDES .shtml 
        Options +Includes 
        Order allow,deny
        allow from all
	<Files ~ "\.(php.|php3.|php5.)">
		Order allow,deny
		Deny from all
	</Files>
    </Directory>
 
    ScriptAlias /cgi-bin/ /var/web/USERNAME/home/web/cgi-bin/
    <Directory "/var/web/USERNAME/home/web/cgi-bin">
        AllowOverride AuthConfig FileInfo Indexes Limit
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
    </Directory>
 
    <IfModule mod_suexec.c>
        SuExecUserGroup USERNAME USERNAME
    </IfModule>
</VirtualHost>

FastCGI方案

<VirtualHost *:80>
    ServerName DOMAIN_NAME
    ServerAdmin ADMIN_EMAIL_ADDRESS
 
    DocumentRoot /var/web/USERNAME/home/web/www
	<IfModule mod_fcgid.c>
		<Directory /var/web/USERNAME/home/web/www>
		    Options +ExecCGI +Includes 
		    AddHandler fcgid-script .php
		    FCGIWrapper /var/web/username/php-cgi-bin/php-cgi-wrapper .php
		    AllowOverride AuthConfig FileInfo Indexes Limit
		    AddType text/html .shtml
		    AddOutputFilter INCLUDES .shtml
		    Order allow,deny
		    allow from all
		    <Files ~ "\.(php.|php3.|php5.)">
			Order allow,deny
			Deny from all
		    </Files>
		</Directory>
	</IfModule>
 
    ScriptAlias /cgi-bin/ /var/web/USERNAME/home/web/cgi-bin/
    <Directory "/var/web/USERNAME/home/web/cgi-bin">
        AllowOverride AuthConfig FileInfo Indexes Limit
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
    </Directory>
 
    <IfModule mod_suexec.c>
        SuExecUserGroup USERNAME USERNAME
    </IfModule>
</VirtualHost>

d. php-cgi-wrapper 程序源代码
/var/web/username/php-cgi-bin/php-cgi-wrapper 为 php 的 cgi-wrapper 程序,源代码如下
CGI方案

/* php-cgi-wrapper.c
 * Heiher <admin@heiher.info>
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char * argv[])
{
	setenv("PHPRC", "/etc/php5/cgi/", 1);
	execv("/usr/lib/cgi-bin/php", NULL);
 
	return 0;
}

FastCGI方案

/* php-cgi-wrapper.c
 * Heiher <admin@heiher.info>
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char * argv[])
{
	setenv("PHPRC", "/etc/php5/cgi/", 1);
	setenv("PHP_FCGI_MAX_REQUESTS", "8192", 1);
	setenv("PHP_FCGI_CHILDREN", "8", 1);
 
	execv("/usr/lib/cgi-bin/php", NULL);
 
	return 0;
}

e. 编译 php-cgi-wrapper 并安装
在合适的开发环境使用如下命令编译安装

gcc -o php-cgi-wrapper php-cgi-wrapper.c
cp php-cgi-wrapper /var/web/username/php-cgi-bin/

f. 设置目录权限

sudo chown root:root /var/web/username
sudo chmod 755 /var/web/username
sudo chown -R www-data:www-data /var/web/username/config
sudo chmod 750 /var/web/username/config
sudo chown -R username:username /var/web/username/php-cgi-bin/
sudo chmod 750 /var/web/username/php-cgi-bin/
sudo chown root:root /var/web/username/home
sudo chmod 755 /var/web/username/home
sudo chown -R username:username /var/web/username/home/web/
sudo chmod 750 /var/web/username/home/web/

g. 启用此用户的虚拟主机

sudo ln -s /var/web/username/config/vhost /etc/apache2/site-enabled/xxxx-username
sudo service apache2 reload

至此配置就结束了,说复杂也不是很复杂,关键就是文件的隶属关系和权限需要注意一定得正确。

Over!

4 thoughts on “虚拟主机方案 – Apache + SuEXEC + (F)CGI + PHP-CGI”

Leave a Reply

Your email address will not be published. Required fields are marked *