Debian, apache2, virtualhosts, FastCGI and PHP5

I’ve spent an amusing evening revisiting FastCGI under Apache2, in order to server PHP5 content through Apache’s threaded MPM (worker).  I set this up ages ago on my previous web server and then forgot about it.

It was fine for a long time, but I hadn’t really customised it and to be frank, wasn’t really sure what it was doing.  I just know at the time it was very confusing reading a lot of conflicting stuff on the web.  But it worked.  Until recently, when I noticed the server was running out of memory and processes were being killed.  I didn’t really spend much time looking at the cause though.

When I moved to the new server, I thought I’d try out the prefork MPM again, as per my previous posts and it seemed okay.  However, it’s not okay (although I may do some more load testing if I get a chance).  So I quickly switched back to the worker MPM and FastCGI.

Which is where I started getting frustrated again – I wanted to understand better what’s going on with FastCGI and make sure I was handling it correctly.

If you search the web, there’s a lot of stuff, much of it from 2007 – 2009 with conflicting information and stuff you might or might not need to do.

So, first some caveats,

  1. this is Debian Squeeze, other distributions might be different.
  2. I run PHP5 under FastCGI and nothing else, so my config changes only affect PHP5.
  3. I’m guessing about most of this stuff – so if I’m wrong, please feel free to provide constructive comments.

Here’s what I learned.

Two FastCGI Modules?

Debian comes with two FastCGI modules, those being libapache2-mod-fcgid and libapache2-mod-fastcgi.  They are binary compatible, I’m lead to believe, but fcgid is newer and works better with suexec.  So you should use libapache2-mod-fcgid unless you know you need libapache2-mod-fastcgi for some specific reason.  If you read examples talking about libapache2-mod-fastcgi you can probably just use libapache2-mod-fcgid instead.

Don’t install them both at once – you can do, but there’s no point and it’ll only cause confusion.  You only need one.

Some Fcgid settings are per virtual host.

I run with a low memory setup, so I wanted the PHP5 processes to shut down after a while, rather than hang around.  I couldn’t work out why they weren’t going away.  Also, I couldn’t work out why there were so many.  But it looks to me like you get at least one PHP5 process per virtual host, sometimes more (if the load is high, but remember, these are mostly vanity VPS’s, low load).  The default settings for fcgid processes is to start with none, and create as many as needed, and then drop back to 3.  But it looks like with the way I’ve got it configured (maybe all ways), that’s per virtual host.  I had to set the FcgidMinProcessesPerClass to be 0, so that on each virtual host, fcgid will close all the unused PHP5 processes after a while.

Wrappers?

Most of the articles online suggest you write a little wrapper to launch your PHP5 stuff via Fast CGI.  I couldn’t remember doing that on the previous server and spent a while looking for my wrapper script – until I realised I’d not created one.  You don’t need a wrapper script, but you do need to tell your virtual host to run PHP5 code using the Fast CGI module.  I have this in each of my virtualhost Apache2 config sections.

AddHandler fcgid-script .php
FCGIWrapper /usr/lib/cgi-bin/php5 .php
Options ExecCGI

You need to add the ExecCGI to the Options directive to ensure the PHP pages can be run as CGI apps, and the Handler and FCGIWrapper lines tell Apache2 how to run the PHP.  The default wrapper is just the PHP5 CGI binary (as shown above).  You can put a shell script there and set some defaults, but you don’t have to, it ran fine for over a year on my other server without doing so.

You can set values in fcgid.conf

Because I’m only running PHP5 stuff via Fast CGI, I can happily put settings in Apache’s fcgid.conf file.  Some articles suggest creating a PHP specific one, and putting the wrapper script stuff above in that as well.  I’m sure that works, but so does the way I did it (there’s always more than one way!).  Here’s my fcgid.conf,

<IfModule mod_fcgid.c>
 AddHandler    fcgid-script .fcgi
 FcgidConnectTimeout 20
 FcgidIOTimeout              60
 FcgidMaxRequestsPerProcess  400
 FcgidIdleTimeout            60
 FcgidMinProcessesPerClass   0
</IfModule>

The two Timeout entries ensure unused PHP5 processes are closed down.  The MinProcessesPerClass is required as mentioned above, otherwise it defaults to 3 per virtualhost.  The MaxRequestsPerProcess I’ve set at 400.  PHP will by default handle 500 and then shutdown, it can do that even if Fast CGI has already made a connection, resulting in a 500 error at the client.  If you force Fast CGI to stop PHP after <500 requests, you avoid that issue.  You can if you want write a PHP Wrapper script, and increase PHP’s max requests value, but you don’t have to.

There’s always another way

This is one way of setting it up, there’s always another way, and with Linux there’s usually another 10 ways.  I may do some more testing to narrow down some confusion I still have and see what the benefits of wrapper scripts may or may not be, and whether it’s worth moving some of the per-virtualhost config entries into the fcgid.conf file (like the handler bits).