Articles

PHP Running as a CGI with Apache SuExec

Author: nathacof
Published: Wednesday 15th of July 2009

Running PHP as a CGI can improve your experience dramatically if you're running multiple sites on a single server. First this will allow you to configure PHP settings per site, rather than through the global php.ini, or the php_admin_engine for mod_php. In addition it will prevent PHP scripts from running as the Apache user, further restricting the possibility of an attack affecting multiple sites on your server.

cPanel and Plesk users need not attempt this! cPanel allows you to configure PHP via mod_php or CGI. Plesk requires the use of the php_admin_engine to enforce limitations on each site, which is only available with mod_php.

However, with Plesk, this is a viable way to run two versions of PHP in parallel, as long as you maintain the distribution's version of the Apache PHP module.

Prequisites

Apache SuExec

Your sites should be served from /var/www/, otherwise you will need to recompile Apache!

 suexec -V
 AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=100
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_EXEC="/var/log/httpd/suexec.log"
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=500
 -D AP_USERDIR_SUFFIX="public_html"

In this article let's assume the Apache DocumentRoot is configured to point to, /var/www/example.com/htdocs.

PHP-CGI

PHP should be compiled with CGI support. RedHat ships php-cgi by default with it's PHP RPM:

which php-cgi
/usr/bin/php-cgi

CentOS users need to install the php-cli via yum.

Zend Server does not come with php-cgi, but does offer the PHP source, such that you can compile php-cgi for yourself. However, special care will be necessary to load only Non-Thread Safe PHP extensions. For example, you'll have to disable all the neat features of Zend Server.

PHPWrapper

The PHPWrapper script is actually just a *nix shell script which is used to configure environment variables, and launch the php-cgi executable. Apache will call this script any time someone requests a PHP page.

Let's create the script. Outside of the website's DocumentRoot we will create our PHPWrapper script:

cd /var/www/example.com/
mkdir cgi-php/ etc/

Now we've got our directories setup lets create the necessary files:

cp /etc/php.ini etc/
vi cgi-php/phpwrapper
#!/bin/bash
# PHP_INI_SCAN_DIR=/etc/php.cgi.d/
# export $PHP_INI_SCAN_DIR
 
PHPRC=/var/www/example.com/etc/
PHP_CGI=/usr/bin/php-cgi
 
### Export Environment Variables
export PHPRC
 
### Execute the php-cgi
exec $PHP_CGI
~
:wq
chown -R nathacof:nathacof cgi-php/ etc/
chmod -R 755 cgi-php/ etc/

Apache Configuration

You will need to add the following to the domain's VirtualHost container:

SuExecUserGroup nathacof nathacof
 
# Adjust handler to run our wrapper script
ScriptAlias /cgi-php/ /var/www/example.com/cgi-php/
AddHandler php5-cgi .php
Action php5-cgi /cgi-php/phpwrapper

That's all there is too it. Let's test our configuration and restart Apache!

$ /sbin/service httpd configtest
Syntax OK
$ /sbin/service httpd restart
Stopping httpd:             [  OK  ]
Starting httpd:             [  OK  ]

Now you can edit the site's php.ini to your liking without affecting other sites. I would recommend you change the following settings for security and performance reasons.

;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;

; Adjust the following to your liking
max_execution_time = 30     
max_input_time = 60     

; Keeping a low memory_limit allows more sites per server
memory_limit = 8M      

;;;;;;;;;;;;;;;;;;;
; Security        ;
;;;;;;;;;;;;;;;;;;;

; Restrict file access to the following directories
open_basedir = /var/www/example.com:/tmp

; Save sessions inside our basedir
session.save_path = /var/www/example.com/tmp

; Save file uploads inside our basedir
upload_tmp_dir = /var/www/example.com/tmp/uploads

Let's make sure these directories exist and have proper permissions.

mkdir -p /var/www/example.com/tmp/uploads
chown -R nathacof:nathacof /var/www/example.com/tmp

To prevent regular users from editing their php.ini you can make the file immutable.

sudo chattr +i etc/php.ini

If you want to make edits to the file later run the following commands.

sudo chattr -i etc/php.ini
sudo vi etc/php.ini
sudo chattr +i etc/php.ini

That's all there is to it!

Article Search

Social Networks