tl;dr If you have WordPress on a server that's short on memory, use fcgid, mpm-worker and WP Super Cache. fcgid is also good for MediaWiki on a cramped server.
The below is currently in place on davidgerard.co.uk/notes, rocknerd.co.uk and newstechnica.com, which live on a 512MB Ubuntu 12.04 VM (Rackspace's cheap loss-leader option; 1GB costs three times as much) running WordPress. It is a first draft. I welcome your experienced advice, suggestions, tweaks and "oh God no that's stupid." This post will be edited as I go.
(Why do you want to do this? When your site runs useful applications like WordPress or MediaWiki, and you have any popularity at all and find yourself running out of memory alarmingly fast and the box choking on swapped Apache processes. So you want to shove PHP off to be a separate problem, and without libphp5 you can use Apache mpm-worker, which is smaller. fcgid is not as fast as the module, but if your limiting factor is memory then it's just the thing.)
What I did:
- sudo -s
apt-get install libapache2-mod-fcgid php5-cgi - Edit /etc/php5/cgi/php.ini and uncomment:
cgi.fix_pathinfo=1 - Here's my /etc/apache2/sites-available/rocknerd.co.uk, changes in red (is there a way to do this for all vhosts?):
<VirtualHost *:80> ServerAdmin dgerard@gmail.com ServerName rocknerd.co.uk ServerAlias www.rocknerd.co.uk ServerAlias rocknerd.org.uk ServerAlias www.rocknerd.org.uk DocumentRoot /home/fun/www/rocknerd.co.uk <Directory /home/fun/www/rocknerd.co.uk> Options Indexes FollowSymLinks +ExecCGI AllowOverride All AddHandler fcgid-script .php FCGIWrapper /usr/lib/cgi-bin/php .php Order allow,deny allow from all </Directory> ErrorLog /home/fun/log/rocknerd.co.uk/apache2/error.log LogLevel warn CustomLog /home/fun/log/rocknerd.co.uk/apache2/access.log combined </VirtualHost>
- I put this in a file called /etc/apache2/conf.d/php-fcgid.conf (these numbers were for a VM with 512MB memory and PHP memory_limit=64M; I have no idea if the numbers in the bottom half are at all sensible):
<IfModule mod_fcgid.c> AddHandler fcgid-script .fcgi .php FcgidConnectTimeout 20 PHP_Fix_Pathinfo_Enable 1 # Where to look for the php.ini file? DefaultInitEnv PHPRC "/etc/php5/cgi" # Maximum requests a process handles before it is terminated MaxRequestsPerProcess 1000 # Maximum number of PHP processes MaxProcessCount 10 # Number of seconds of idle time before a process is terminated IPCCommTimeout 240 IdleTimeout 240 #Or use this if you use the file above FCGIWrapper /usr/bin/php-cgi .php ServerLimit 500 StartServers 3 MinSpareThreads 3 MaxSpareThreads 10 ThreadsPerChild 10 MaxClients 250 MaxRequestsPerChild 1000 </IfModule>
- apache2ctl restart; apache2ctl status and verify the site still loads. All good? Proceed:
- apt-get install apache2-mpm-worker; apache2ctl restart; apache2ctl status and verify the site still loads.
- Now work out how much memory you want to give PHP in /etc/php5/cgi/php.ini and the MaxClients for Apache itself (to serve static content). Read through the mod_fcgid documentation to configure things sanely for your box.
Experienced advice welcomed. The above is currently in place; in my initial attempts to utterly hammer it, the memory fills and the box goes 250MB into swap, but it appears to actually be swapping swappable stuff, the pages get served (eventually ... a bit of a queue), the load average doesn't go nuts and stuff doesn't fall over. In later attempts to hammer it (wget in a loop), it didn't fall over but did take minutes to serve pages on uncached blogs; I'll need to do something about that.
Next victim: rationalwiki.org, which thankfully has 4GB to play with but is actually a bit popular. Victim after that: the LAMP box at work.
Update: I have just put WP Super Cache in front of all the blogs. It caches using mod_rewrite trickery such that Apache does all the serving for cached pages and requests don't touch PHP. So hammering it for 1000 of the same thing, it served them in a few seconds. I also tried hammering the site with 1000 different nonexistent URLs and it was slow but kept serving (and returned blank pages for most of the 404s). I am now confident that if I write something popular, then (a) the server will stay up (b) people will still be able to read it. If I write something unpopular then (c) it should stand up to a mild one-person DOS.
Update, September 2013: Copes well with Slashdot (a few thousand hits), melts with Reddit (20,000 hits, 30 per minute peak). You have to tell WP Super Cache to directly serve the page. Side-effect: comments will take 10 minutes to refresh. Details.