Installing Apache + mod_fastcgi + PHP-FPM on Ubuntu Server Maverick
Recently I was looking to speed up one of my Apache + mod_php installs. The problem with Apache + mod_php is that Apache must spawn and then destroy a new instance of PHP whenever a script is called. This leads to performance degradation and eventually process bloat as the Apache process expands in memory to astronomical sizes.
Lots of options with similar names
There are lots of alternatives to speed up Apache + PHP, but unfortunately they all have similar-sounding names and can be combined in a few permutations. It can be confusing deciding which alternative to pick, and even more confusing figuring out how to set it up. I want to quickly describe some of the main alternatives to help clear things up before we start (but for those of you with short attention spans, the best one appears to be Apache + mod_fastcgi + PHP-FPM).
Apache + mod_fastcgi: FastCGI is a module that allows you to neatly solve mod_php’s big problem, namely that it must spin up and destroy a PHP instance with every request. FastCGI instead keeps an instance of PHP running in the background. When Apache receives a request it forwards it to FastCGI, which feeds it to its already running instance of PHP and sends the result back to Apache. Apache then serves the result.
Without the constant build-and-destroy of new PHP processes, FastCGI is a great memory saver and performance booster. My Apache + mod_php install, which would constantly bloat to 1000′s of MB in memory usage and invoke OOM-Killer without mercy, has been humming along at a steady ~200MB for the past few months without a single problem after switching to mod_fastcgi.
- Apache + mod_fcgid: Why, oh why, did someone build an alternative to FastCGI only to call it by the almost-identical name of fcgid? From what I understand, fgcid is a binary-compatible alternative to FastCGI–that is, it does more or less the same thing, but in a different way. It seems that some people prefer mod_fcgid over mod_fastcgi because of better stability and maybe even slightly better performance. But for the kind of traffic I’m getting, there wasn’t any difference.
Apache + mod_fastcgi + PHP-FPM: PHP-FPM (A.K.A. PHP5-FPM) is a process manager for PHP. Confusingly, it was only recently bundled with PHP, so you might find some tutorials telling you to download the source and others to just use apt-get. I believe that if you’re using PHP >= 5.3, which you would be if you installed it in Maverick with apt-get, that you don’t need to download the source to get it working. I’ll talk more about this later.
From what I understand, PHP-FPM is like FastCGI, but with additional PHP-specific optimizations built in. Since it’s specially built for PHP, it should give you the best performance, and so is the best of these three alternatives. It’s the one we’ll be focusing on for this post.
Getting it installed
For some reason it seems that there’s a glut of tutorials for setting up Nginx + PHP-FPM, but almost none for Apache + PHP-FPM. While Nginx is great, Apache has worked well for me for many years and I’m a “if it ain’t broke, don’t fix it” kind of guy.
Thankfully, it turns out that despite the severe lack of simple online tutorials it’s not so hard to set up Apache + mod_fastcgi + PHP-FPM on Ubuntu Server. Here we go!
Enable the Multiverse repository, which is where libapache2-mod-fastcgi lives. For some reason it’s not included in Ubuntu Server, so we have to append it to our /etc/apt/sources.list:
echo -e "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted multiverse\ndeb-src http://archive.ubuntu.com/ubuntu $(lsb_release -cs) main restricted multiverse" | sudo tee -a /etc/apt/sources.list > /dev/null
Install Apache and other required software. You must use the Apache Worker variant, not the Apache Prefork variant. The difference between the two is important, but you can look that up somewhere else.
sudo apt-get install apache2-mpm-worker libapache2-mod-fastcgi php5-fpm
When you start the PHP5-FPM service on a default install, you’ll get a warning about a setting called “pm.start_servers” not being initialized. This won’t affect your install, but it can get annoying. To stop this message from showing up when starting or stopping the PHP5-FPM service, run:
sudo sed -i 's/;pm.start_servers/pm.start_servers/g' /etc/php5/fpm/pool.d/www.conf
Enable some Apache modules that we’ll be using:
sudo a2enmod actions fastcgi alias
And now for the secret sauce: Setting up your Apache virtual host so that it shuffles PHP requests to PHP-FPM/FastCGI. For this example I’ll use Apache’s default site, but you’ll probably want to use your own. Edit /etc/apache2/sites-available/default using Nano (or your favorite editor):
sudo nano /etc/apache2/sites-available/default
Paste the following somewhere in your VirtualHost block using ctrl + shift + v:
FastCgiExternalServer /var/www/php5.external -host 127.0.0.1:9000 AddHandler php5-fcgi .php Action php5-fcgi /usr/lib/cgi-bin/php5.external Alias /usr/lib/cgi-bin/ /var/www/
Remember that when using your own VirtualHost, you’ll probably be changing the default web root from /var/www/ to a different directory.
Also note that the “file” php5.external doesn’t have to exist—it’s just a socket.
Restart both Apache and the PHP-FPM services:
sudo service apache2 restart && sudo service php5-fpm restart
And that should do it!
Testing your install
To test this default install, create a new PHP file in Apache’s default document root and access it from your web browser.
Create the PHP file:
echo "<?php phpinfo(); ?>" | sudo tee /var/www/test.php > /dev/null && sudo chgrp www-data /var/www/test.php
Test it in your browser! Visit http://localhost/test.php and check the output:
And that should be about it. Enjoy your new speedy Apache install!
By the way, I’m more of a developer than a sysadmin, so if any experienced sysadmins want to chime in on this setup then by all means please do so.