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.
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 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.
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/
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!
