Jeb Wilkins

Coding and climbing in Cumbria.

PHP and Mod_fcgid

I’ve just moved the server this blogs hosted on and one of my objectives was set the new machine up using mod_fcgid with PHP via FastCGI rather than the more traditional apache + mod_php. Why?

  1. Apache + mod_php is not the most memory efficient solution, every time a static asset is requested, apache is forked, complete with an entire copy of php, itself much larger than the copy of Apache its embedded within.

  2. Security - mod_php is pretty bad from a security point of view - all php code runs as the web process, hence if an attacker manages to get code onto the server (eg someones insecure uploader) that code can not only read the files from the site they have compromised, but from every other site on the box.

  3. I want to run rails code on the machine as well and it seems insane to have a request destined for a rails app being processed by a small apache process with a large copy of php embedded within it (see point 1)

In reality this has proven more difficult than I’d anticipated, and is probably not as efficient as I’d hoped.

Installing Apache is relatively straightforward, the computer in question is running Ubuntu 10.04 LTS, so installing apache-mpm-worker will get you an up and running web server, and you can configure vhosts as normal.

To run PHP scripts you also need to install libapache2-mod-fcgid, php5-cgi, apache2-suexec. You’ll then need an executable FastCGI wrapper script, you need one of these per user account, and these need to exist within /var/www - so I’d recommend disabling /var/www as a web root, otherwise these scripts will be exposed to the web. The other gotcha with these scripts is that they need to be owned by the user account you are suexec’ing to, and so does their parent directory

I created the following in /var/www/fcgi-wrappers/jebw/php-fcgi-script

#!/bin/sh
PHPRC=/etc/php5/cgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=2
exec /usr/lib/cgi-bin/php

You then need to set ownership and permissions

chown -R jebw:jebw /var/www/fcgi-wrappers/jebw
chmod 755 /var/www/fcgi-wrappers/jebw/php-fcgi-script

At this point you can setup fcgi in you apache vhost

<VirtualHost *:80>
  ServerName www.jdwilkins.co.uk
  DocumentRoot /home/jebw/website/
  <IfModule mod_fcgid.c>
    SuexecUserGroup jebw jebw
    <Directory /home/jebw/website/>
      Options +ExecCGI
      AllowOverride All
      AddHandler fcgid-script .php
      FCGIWrapper /var/www/fcgi-wrappers/jebw/php-fcgi-script .php
      Order allow,deny
      Allow from all
    </Directory>
  </IfModule>
</VirtualHost>

One final tweak is to php.ini (in /etc/php5/cgi/php.ini - since we’re using FastCGI)

cgi.fix_pathinfo=1

At that point you’re all set to go. The bonus of this method is that things like file uploads get the correct file ownership, the definite downside is that you end up with separate copies of PHP running for every user account.