因为FasiCGI,CGI模式下均有少许问题,所以一直以来都给Apache使用mod_php方式执行PHP。
但此模式的资源占用可要给差评了,在网站访问量大的时候,特别是被CC的时候,FORK出的大量Apache进程经常会变成“僵尸”进程,无法正常退出,即使访问量恢复正常,攻击已结束,那些“僵尸”进程一样占用着你的资源,有时攻击猛烈些,直接整个系统宕掉,非硬重启无法救活。纵使有些人会使用如CloudLinux,BetterLinux之类的限制单用户的进程,但还是会有以Apache默认的执行身份fork出的进程……
为了给虚拟主机带来更稳定,更安全的使用环境,必须更换PHP执行方式!
经过测试与研究,最后采用了PHP FPM。
WHY PHP FPM?
PHP FPM不仅能满足使用admin value,opcache的需求,还能针对每个不同的pool的最大进程数量进行限制。这也就意味着,可以防止某个站点占用服务器过多的资源。
同时,让Apache使用worker模式运行,仅负责静态资源,仅需数个进程就能处理大量的访问。
可见,PHP FPM性能,安全皆具备!
很可惜,一直以“强大”著称的cPanel/WHM的,在PHP设置的选项中并没有表现出任何的强大:
很明显,这要自己动手了。
动手前,先定一个大概的步骤:
1. 切换Apache为worker模式。
2. 编译安装PHP。
3. 给cPanel/WHM添加HOOK。
4. 给已有的用户创建PHP FPM POOL配置文件。
5. 重建所有站点的Apache配置文件。
因为服务器有已有虚拟主机的用户,因此“改造”过程中尽量减少Apache的暂停时间。
切换Apache为worker模式
看了一下cPanel/WHM编译Apache的的参数,是使用–with-mpm指定mpm模块的,要更换的话,只能重新编译。EasyApache中并未mod_proxy_fcgi,要让Apache使用FastCGI Server,此模块是必须的。
既然如此,那自行编译是最好不过的选择了。
下载Apache,APR,APR-UTILS:
1 2 3 4 5 6 |
wget http://mirror.nus.edu.sg/apache//httpd/httpd-2.4.10.tar.bz2 -O- | tar xjvf - -C /usr/src/ cd /usr/src/httpd-2.4.10 wget http://mirror.nus.edu.sg/apache//apr/apr-1.5.1.tar.bz2 -O- | tar xjvf - -C ./srclib/ wget http://mirror.nus.edu.sg/apache//apr/apr-util-1.5.4.tar.bz2 -O- | tar xjvf - -C ./srclib/ mv ./srclib/apr-1.5.1 ./srclib/apr mv ./srclib/apr-util-1.5.4 ./srclib/apr-util |
开始编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
./configure \ --disable-v4-mapped \ --enable-access-compat=static \ --enable-actions=static \ --enable-alias=static \ --enable-auth_basic=static \ --enable-authn_core=static \ --enable-authn_file=static \ --enable-authz_core=static \ --enable-authz_groupfile=static \ --enable-authz_host=static \ --enable-authz_user=static \ --enable-autoindex=static \ --enable-cache=static \ --enable-cache-disk=static \ --enable-cgi=static \ --enable-deflate=static \ --enable-dir=static \ --enable-echo=static \ --enable-env=static \ --enable-expires=static \ --enable-ext-filter=static \ --enable-file-cache=static \ --enable-filter=static \ --enable-headers=static \ --enable-include=static \ --enable-info=static \ --enable-ldap=static \ --enable-log_config=static \ --enable-logio=static \ --enable-mime=static \ --enable-modules=none \ --enable-negotiation=static \ --enable-proxy=static \ --enable-proxy-connect=static \ --enable-proxy-http=static \ --enable-proxy-fcgi \ --enable-rewrite=static \ --enable-setenvif=static \ --enable-slotmem_shm=static \ --enable-socache_dbm=static \ --enable-socache_shmcb=static \ --enable-ssl=static \ --enable-status=static \ --enable-suexec=static \ --enable-unique-id=static \ --enable-unixd=static \ --enable-userdir=static \ --enable-vhost-alias=static \ --enable-remoteip \ --prefix=/usr/local/apache \ --with-included-apr \ --with-ldap \ --enable-mpms-shared=all \ --with-pcre=/opt/pcre \ --with-ssl=/usr \ --with-suexec-caller=nobody \ --with-suexec-docroot=/ \ --with-suexec-gidmin=100 \ --with-suexec-logfile=/usr/local/apache/logs/suexec_log \ --with-suexec-uidmin=100 \ --with-suexec-userdir=public_html && make && make install |
configure的参数,你可以根据自己的需要做出修改。
这里不能重启Apache,否则无法启动了。
编辑/etc/httpd/conf/includes/pre_main_global.conf文件,在里面加入下列代码:
1 2 |
LoadModule proxy_fcgi_module /usr/local/apache/modules/mod_proxy_fcgi.so LoadModule mpm_worker_module /usr/local/apache/modules/mod_mpm_worker.so |
这样,就成功切换Apache为worker模式运行,并启用mod_proxy_fcgi模块。
由于是自行编译的Apache,如果使用/scripts/rebuildhttpdconf,会出现“This tool unavailable until Apache is built by EasyApache 3.x”的提示,编辑/scripts/rebuildhttpdconf文件,把此行:
1 |
die 'This tool unavailable until Apache is built by EasyApache 3.x' if !Cpanel::Config::Httpd::is_ea3(); # issafe |
注释,或者删掉即可。
编译安装PHP
这里使用的是PHP 5.4.31:
1 2 |
wget http://hk1.php.net/get/php-5.4.33.tar.bz2/from/this/mirror -O- | tar xjvf - -C /usr/src/ cd /usr/src/php-5.4.33 |
编译安装,并配置,把下面的代码保存到一个文件,使用“bash 文件名”方式执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
VERSION="php54" PREFIX="/usr/local/${VERSION}" SCANDIR="${PREFIX}/etc/conf.d" MYSQLSOCK="/var/lib/mysql/mysql.sock" ./configure \ --enable-bcmath \ --enable-calendar \ --enable-exif \ --enable-ftp \ --enable-gd-native-ttf \ --enable-intl \ --enable-libxml \ --enable-mbstring \ --enable-pdo=shared \ --enable-soap \ --enable-sockets \ --enable-wddx \ --enable-zip \ --enable-fpm \ --prefix=${PREFIX} \ --with-config-file-path=${SCANDIR} \ --with-config-file-scan-dir=${SCANDIR} \ --with-bz2 \ --with-curl=/opt/curlssl/ \ --with-freetype-dir=/usr \ --with-gd \ --with-gettext \ --with-icu-dir=/usr \ --with-imap=/opt/php_with_imap_client/ \ --with-imap-ssl=/usr \ --with-jpeg-dir=/usr \ --with-kerberos \ --with-libexpat-dir=/usr \ --with-libxml-dir=/opt/xml2 \ --with-libxml-dir=/opt/xml2/ \ --with-mcrypt=/opt/libmcrypt/ \ --with-mysql=/usr \ --with-mysql-sock=${MYSQLSOCK} \ --with-mysqli=/usr/bin/mysql_config \ --with-openssl=/usr \ --with-openssl-dir=/usr \ --with-pcre-regex=/opt/pcre \ --with-pdo-mysql=shared \ --with-pdo-sqlite=shared \ --with-png-dir=/usr \ --with-snmp \ --with-xmlrpc \ --with-xpm-dir=/usr \ --with-xsl=/opt/xslt/ \ --with-zlib \ --with-zlib-dir=/usr \ --with-ldap \ --with-mhash && make && make install || exit 1 mkdir -p ${PREFIX}/etc/fpm.d/ ${SCANDIR} /usr/local/${VERSION}/sockets/ \cp -ar ./php.ini-production ${SCANDIR}/php.ini && chown -R root:root ${SCANDIR} && chmod -R 755 ${SCANDIR} cat>${PREFIX}/etc/php-fpm.conf<<EOF include=etc/fpm.d/*.conf [global] EOF \cp -ar sapi/fpm/init.d.php-fpm /etc/init.d/${VERSION}-fpm && chown root:root /etc/init.d/${VERSION}-fpm && chmod 755 /etc/init.d/${VERSION}-fpm && chkconfig --add ${VERSION}-fpm && chkconfig ${VERSION}-fpm on sed -r -i "s#php_opts=\"(.*)\"#php_opts=\"\1 -c \${prefix}/etc/conf.d/php.ini\"#g" /etc/init.d/${VERSION}-fpm |
同样的,编译参数你可以自行更改。
给cPanel/WHM添加HOOK
根据cPanel/WHM的官方文档,使用HOOK Script实现在成功创建用户后创建PHP FPM的POOL配置文件,以及成功删除用户后PHP FPM POOL配置文件。
编辑/scripts/postwwwacct,加入下列代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#!/bin/bash while [ "${1}" != "user" ] do echo "Shift ${1}" shift done eval ${1}=${2} echo ${user} if [ "${user}" = "root" ] || [ "${user}" = "" ];then exit; fi cat>/usr/local/php54/etc/fpm.d/${user}.conf<<EOF [${user}] user = \$pool group = \$pool listen = /usr/local/php54/sockets/\$pool.sock listen.owner = \$pool listen.group = nobody listen.mode = 660 pm = ondemand pm.max_children = 20 pm.process_idle_timeout = 20 php_admin_value[open_basedir] = /home/${user}/:/tmp/:/var/tmp/:/usr/local/php54/lib/ ;php_admin_value[mail.log] = /home/${user}/php-mail.log security.limit_extensions = .php .php52 .php53 .php54 .php55 .php60 .php54 .php0 EOF /usr/sbin/usermod -aG ${user} apache /etc/init.d/httpd restart /etc/init.d/php54-fpm reload |
还有/scripts/postkillacct:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/bash while [ "${1}" != "user" ] do echo "Shift ${1}" shift done eval ${1}=${2} echo ${user} if [ "${user}" = "root" ] || [ "${user}" = "" ];then exit; fi rm -f /usr/local/php54/etc/fpm.d/${user}.conf /usr/sbin/groupdel ${user} /etc/init.d/php54-fpm reload |
赋予上述文件的执行权限:
1 |
chmod +x /scripts/postwwwacct /scripts/postkillacct |
给已有的用户创建PHP FPM POOL配置文件
用户多的话,手动创建是不可能的,这里提供一个Shell Script:
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/bash cd /home/ killall -9 php-fpm killall -9 httpd for username in * do if [ "$(cat /etc/passwd | egrep "^${username}:")" != "" ];then echo "Create PHP FPM configration file for user ${username}." && /usr/local/cpanel/scripts/postwwwacct user ${username} && echo "${username}.conf create successfully." || echo "${username}.conf create unsuccessfully." fi done service php54-fpm start service httpd start |
如果一切无误,启动PHP FPM:
1 |
service php54-fpm start |
重建所有站点的Apache配置文件
先添加一个Apache的用户:
1 |
useradd -rmd /var/www -s /sbin/nologin apache |
修改cPanel/WHM的Apache配置文件模板,进入/var/cpanel/templates/apache2_4(如果你之前使用的是Apache2.2,应该要进入/var/cpanel/templates/apache2)文件夹,创建自定义配置文件模板:
1 2 3 |
cp -a main.default main.local cp -a ssl_vhost.default ssl_vhost.local cp -a vhost.default vhost.local |
这样cPanel/WHM就会使用.local结尾的作为模板创建Apache的配置文件。
修改main.local文件,找到此行:
1 |
User [% main.user.item.user % |
将其更改为:
1 |
User apache |
分别编辑ssl_vhost.local,vhost.local,在文件首行,也就是”<VirtualHost[% FOREACH ipblock IN vhost.ips %] [% ipblock.ip %]:[% ipblock.port %][% END %]>”之前,加入这些代码:
1 2 3 |
<Proxy "unix:/usr/local/php54/sockets/[% vhost.user %].sock|fcgi://php-fpm54.[% vhost.user %]/"> ProxySet min=0 </Proxy> |
接下来,找到“UserDir enabled [% vhost.user %]”,在他后面三行的“[% END -%]”后加入一行:
1 |
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/usr/local/php54/sockets/[% vhost.user %].sock|fcgi://php-fpm54.[% vhost.user %][% vhost.documentroot %]/$1 |
如图所示:
完成上述修改后,执行:
1 |
/scripts/rebuildhttpdconf |
重建所有用户的配置文件。
最后,让Apache对配置文件进行检测:
1 |
/usr/local/apache/bin/apachectl configtest |
如果出现类似的提示:
1 2 |
[Thu Oct 02 17:45:30.490596 2014] [:crit] [pid 752:tid 3067594544] Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You need to recompile PHP. AH00013: Pre-configuration failed |
那你离成功不远了,访问Configure PHP and suEXEC,把PHP 5 Handler改为none即可:
一般提交后,WHM会自动帮你重启Apache,不过我这里建议最好还是再使用configtest参数检测一下,并重启Apache。
到这里,改造就完成了,可以用雅黑PHP探针对PHP环境进行检测:
能看到“PHP运行方式”一项为“FPM-FCGI”,那就说明大功告成了。
Comments are closed.