Nov. 22nd, 2012

reddragdiva: (geek)

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.

March 2022

S M T W T F S
  12 345
6789101112
13141516171819
20212223242526
2728293031  

Style Credit

Expand Cut Tags

No cut tags