suexec, php-5.1.4, fastcgi and cpanel
The idea of using FastCGI first struck me on Monday. I had previously transitioned my server to use SuEXEC for PHP. Pages were loading slower than I would have liked. PHP was running as a CGI application. Each time there was a request for a page the server woud have to open a new instance of PHP. This on a VPS server is not always fast.
One option was to go back to using mod_php. This would definitely have sped things back up. I always want to keep the server as secure as I know how. This was not an option. SuEXEC runs the PHP process as the user that the page is owned by. This means that there is no longer a need to chmod 777 certain files. SuEXEC in fact will not work with files chmod’ed 777 as they are a huge security risk.
To keep using SuEXEC but also speed up the server I had to get FastCGI going. To minimize the chance of messing things up or causing new problems down the road, I decided to try to leave much as it is.
From FastCGI.com:
FastCGI is a language independent, scalable, open extension to CGI that provides high performance without the limitations of server specific APIs.
From FastCGI – Wikipedia:
Instead of creating a new process for every request, FastCGI uses a single persistent process which handles many requests over its lifetime. Processing of multiple requests simultaneously is achieved either by using a multi-threaded responder process, or with non-blocking I/O and an event loop. FastCGI also allows programs to get the web server to do certain simple operations, like reading in a file, before the request is handed over. Environment information and page requests are sent from the web server to the process over a TCP connection (for remote processes) or Unix domain sockets (for local processes). Responses are returned from the process to the web server over the same connection. The connection may be closed at the end of a response, but the web server and the process are left standing.
The server uses cPanel. This means that many files are not where they would normally be. cPanel has a lot of scripts in /usr/local. This server has duplicate versions of some software. It is important to use the cPanel versions. cPanel keeps track of security issues, and distributes tested new versions of the software. This guide assumes Apache 1.3.
If you are not currently using SuEXEC with PHP, I highly recommend that you do not jump into this change. SuEXEC will not allow scripts chmoded 777 to run. It also does not allow you to set configuration options for PHP in .htaccess files.
If you decide to follow any of the advice in this post, you are doing so at your own risk. Each and every server is configured slightly differently. Where possible use an identically configured test server first.
These are the steps that I have taken that worked for me:
Recompile Apache and PHP using WHM
First recompile Apache and PHP through WHM. At the main WHM screen click on Software, then click on Apache Update. Choose the options that you want to be compiled in to Apache and the version and configuration options for PHP. Make sure to select PHP suEXEC Support, and SuEXEC Module. I chose to use PHP 5.1.4 as I like the object-oriented features that PHP 5 provides.
This process takes a while.
Find out the path of php.ini and the configure command that was used
Create a PHP file in the public_html folder of one of your accounts that contains the following:
<?php
phpinfo();
?>
Visit that page on your site and copy the contents of Configure Command and Configuration File (php.ini) Path. We will be using these a little bit later on.
Download and install the FastCGI library
Download the FastCGI library from http://www.fastcgi.com/dist/.
The current version as of this writing is fcgi-2.4.0.tar.gz.
wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
tar xzvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure
make
make install
Install mod_fastcgi
Download mod_fastcgi from http://www.fastcgi.com/dist/. Install it as a DSO.
The current version as of this writing is mod_fastcgi-2.4.2.tar.gz.
wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
tar xzvf mod_fastcgi-2.4.2.tar.gz
cd mod_fastcgi-2.4.2
/usr/local/apache/bin/apxs -o mod_fastcgi.so -c *.c
/usr/local/apache/bin/apxs -i -a -n fastcgi mod_fastcgi.so
These commands build the DSO and install it. Check your httpd.conf file to make sure that the proper entries were automatically added.
nano -w /etc/httpd/conf/httpd.conf
Check to make sure that the lines LoadModule fastcgi_module and AddModule mod_fastcgi.c were automatically added.
Note: I specified the absolute path of the apxs binary. There are two copies on my server. The one in /usr/local/apache/bin/ is the one installed by cPanel. I am not sure if there would be negative consequences to using the system-provided binary.
Download and compile PHP
I could not for the life of me get the PHP 5.1.4 source patched by cPanel to compile a FastCGI binary. The cPanel patched version is found in /home/cpapachebuild/buildapache/php-5.1.4/. After trying unsuccessfully several times, I decided to download the official source and install it.
Download PHP 5.1.4 from http://www.php.net/downloads.php.
wget http://us2.php.net/get/php-5.1.4.tar.bz2/from/this/mirror
tar xjvf php-5.1.4.tar.bz2
cd php-5.1.4
This is where you need to use the PHP configure line from before. This line needs to be slightly modified.
Make sure that your configure line does not contain ‘–with-apxs’, or ‘–with-apache’.
Modify your configure line. If any of these options are set with different values, simply change the values.
‘–prefix=/usr/local/php5-fcgi’ ‘–enable-fastcgi’ ‘–enable-force-cgi-redirect’ ‘–disable-cli’
./configure your_modified_configure_line
make
make install
/usr/local/php5-fcgi/bin/php -v
The last command should return PHP 5.1.4 (cgi-fcgi).
Note:
Setting ‘–prefix=/usr/local/php5-fcgi’ keeps your FastCGI binary separate from your standard CGI version.
The FAQ at FastCGI.com says to use ‘–with-fastcgi’. That option works with some versions of PHP 4. It is no longer used.
I disabled building the cli to save time. There is already a perfectly good version of the cli already installed. It was compiled from WHM.
Create a symbolic link to the php.ini file
Link your php.ini file so that this binary will use your existing configuration. If you have multiple versions of PHP you may need multiple versions of php.ini. In that case you would have to modify these instructions.
ln -s location_of_php.ini (from previous step) /usr/local/php5-fcgi/lib/
The command for my server was
ln -s /usr/local/Zend/etc/php.ini /usr/local/php5-fcgi/lib/
Configure Apache
Edit your httpd.conf file to configure mod_fastcgi.
nano -w /etc/httpd/conf/httpd.conf
Find the part of the file that contains lines similar to this:
AddType application/x-httpd-php4 .php
I wanted to configure this in a flexible way that would allow me to disable mod_fastcgi and reenable it. To do this use the IfModule module_name.c and IfModule !module_name.c directives. Put the configuration options for when the module is enabled in the former and in the latter when it is disabled.
I use these options:
<IfModule mod_fastcgi.c>
FastCgiSuExec /usr/local/apache/bin/suexec
FastCgiIpcDir /tmp/fcgi_ipc/
FastCgiConfig -autoUpdate -singleThreshold 100 -killInterval 300 -idle-timeout 240 -maxClassProcesses 5 -maxProcesses 20 -pass-header HTTP_AUTHORIZATION
AddHandler fastcgi-script .fcgi
Action application/x-httpd-php4 "/php5.fcgi"
AddType application/x-httpd-php4 .php
AddType application/x-httpd-php4 .php4
AddType application/x-httpd-php4 .php3
AddType application/x-httpd-php-source .phps
AddType application/x-httpd-php4 .phtml
Action application/x-httpd-php5 "/php5.fcgi"
AddType application/x-httpd-php5 .php5
</IfModule>
<IfModule !mod_fastcgi.c>
Action application/x-httpd-php4 "/cgi-sys/php5"
AddType application/x-httpd-php4 .php
AddType application/x-httpd-php4 .php4
AddType application/x-httpd-php4 .php3
AddType application/x-httpd-php-source .phps
AddType application/x-httpd-php4 .phtml
Action application/x-httpd-php5 "/cgi-sys/php5"
AddHandler application/x-httpd-php5 .php5
</IfModule>
Note: My FastCgiConfig limits the effectiveness of FastCGI somewhat. I had to do this because otherwise FastCGI was constantly taking up too many resources.
-maxClassProcesses 5 -maxProcesses 20 are the lines that will most likely need to be adjusted upwards.
A complete listing of the different configuration options is available here http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html.
Create /tmp/fcgi_ipc directory and assign proper permissions
mkdir /tmp/fcgi_ipc/
mkdir /tmp/fcgi_ipc/dynamic/
chmod -R 777 /tmp/fcgi_ipc/
php5.fcgi mess
This is the part of the installation that I dislike the most. Each public_html folder must have a script named php5.fcgi. The script must be owned by the user and group that the virtual machine for that directory uses.
The content of the file that I used is:
#!/bin/sh
PHP_FCGI_CHILDREN=2
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/local/php5-fcgi/bin/php
I also placed a copy of this file in the /root/cpanel3-skel/public_html/ folder with the hopes that it will be automatically added to new user’s accounts.
If anyone knows of a better way to do this, please let me know. If there is not a better way, then we need a shell script to make the addition of this file to each user’s public_html directory easier. I will try to write one if I get the time.
Restart Apache
/scripts/restartsrv_httpd
Sources
- FastCGI.com
- FastCGI FAQ
- timdorr.com – PHP4 and PHP5 Side-By-Side
- wiki.rubyonrails.org – How to Install and Run Ruby on Rails On cPanel
- FastCGI – Wikipedia
Please add a comment if you find any typos, incorrect information, or out-of-date information.
November 10th, 2006 at 10:25 am
Thanks for the tutorial i followed and used php5.2.0 which works quite well.
One question though. suexec_logs indicate that the php5.fcgi scipt is executed not the .php file. Can this be fixed?
Apart from that you can have php files with root permissions or chmoded to 777 which is not allowed by suexec. suexec works because if i change the permissions of php5.fcgi then nothing can be executed.
But allowing php scripts to have incorrect permissions isn’t a security threat?
November 25th, 2006 at 1:49 pm
Nice Tutorial!
I think i found a solution to the php5.fcgi-in-every-virtual-host-directory problem:
Create a directory /usr/share/cgi-bin and put the php5.fcgi file in it.
Be sure that the directory is readable and executable by apache (and all of the virtual host users).
Now, add the following to the apache config:
Alias /shared-cgi-bin/ /usr/share/cgi-bin/
AllowOverride none
Options +ExecCGI
And finally modify the path in the “Action php5-fcgi …” configuration lines to /shared-cgi-bin/php5.fcgi
I haven’t tried it with virtual hosts with different users yet, but it think it will work
November 25th, 2006 at 2:19 pm
Sorry for taking so long to reply.
—
Christos,
I am not sure if there is a way to fix the suexec_logs file. The php5.fcgi is executed and that in turn runs php which parses the file.
To have php files with incorrect permissions is certainly a security threat.
—
Jos van Bakel,
Your method would work; however, I believe it would cause problems in a virtual host environment. The suexec mechanism runs the php5.fcgi file as the user that owns the file. I did see somewhere where there were directives that could be added to Apache’s virtual host sections to specify the exact user that scripts are to be run as.
Looks like I need to do some further research. I will have to do some testing, as I like your way of doing it much better and have always been somewhat dissatisfied with the way I have outlined in this guide.
November 25th, 2006 at 2:39 pm
There is apparently one way that this can be done. There is a patch to the apache suexec code to tell it to stop checking for the uid/gid of files that it is to run. Then you can place the php5.fcgi script in a central location and change some of the config files around. Apache would run the file as whatever uid/gid was set in its virtualhost declaration.
The problem with doing this is that the suexec mechanism checks uid/gid to limit exposure to certain security risks. I would be concerned about stripping out one of the security mechanisms from suexec.
—
uid = user id
gid = group id
December 5th, 2006 at 11:53 pm
I am having the worse time getting php5 to work on cpanel server as fastcgi.
i am constantly getting unable to load pgsql.so (even though it is in the right place). Specifically it says undefined symbol PQescapeStringConn.
any advice?
October 6th, 2007 at 10:56 am
Nice tutorial, It works with php 5.2.4 on centos 4.5, It needs just a minor change, as the binary file is /usr/local/php5-fcgi/bin/php-cgi