Lightning-fast WordPress with PHP-FPM and nginx

Share this article

Managed servers are slow. They run old versions of PHP on ancient copies of Apache, and loathe the Digg effect (or any similar sudden influx of traffic). In this tutorial, I’ll show how to build a server capable of withstanding a front-page Digg placement, step by step. This will mean your business stays online when it’s most important—when everyone is looking. We’ll go through the process of building a super-fast, bulletproof custom web server for WordPress. The technology stack we’ll use is Ubuntu, nginx, PHP-FPM, and MySQL. In a future article we’ll look at adding memcached to the mix to take performance even further.

Why VPS?

VPS stands for virtual private server. Basically, you receive a piece of a big, expensive machine for a low monthly price. You pay for a guaranteed amount of RAM, and have access to a certain amount of CPU power. This can be a much better deal than managed hosting once you have a few websites up and running. However, you have to manage everything yourself, and take care of your server when something goes wrong.

Why nginx?

Nginx is a small, lightweight web server and reverse proxy. It runs on 5.2% of the top one million web servers. In particular, nginx is well-suited to a high traffic site. Its lightweight nature, compared to Apache, means an nginx server can run in a much smaller memory footprint. This makes it the web server of choice for people looking to squeeze the most performance out of a VPS solution.

Why PHP-FPM?

Included with version 5.3.3 of PHP (released in July of this year) is a new FastCGI manager called PHP-FPM. PHP-FPM is a daemon that spawns processes to manage your online applications. So, rather than have your web server running plugins to display and process your PHP code, your PHP code is now run natively, by PHP-FPM. For our example WordPress installation, we’ll set up an nginx server to serve our static files. When a user requests a PHP page, the nginx server will forward the request to PHP itself. PHP-FPM runs its own server, waiting for users to request their pages. This separation of features means you can see some incredible speed gains.

Why MySQL?

Basically, because there’s no other choice. At the moment, WordPress only supports MySQL. I always use memcached to lighten the load on MySQL. As I mentioned, I’ll be covering the use of memcached in a future post.

Putting It All Together

Since all this software is relatively cutting edge, we’re going to go ahead and build nearly everything from source. This means you’ll need to have build-essential or an equivalent package installed on your system. I’ll assume you have basic familiarity with Linux and SSH. If you’re stuck developing in Windows and want to give this setup a go, I’d recommend installing an Ubuntu server inside the free VirtualBox virtualization application.

Step One: Installing nginx

I recommend downloading and installing nginx from source, as the version in most Linux distributions’ package managers are older than we’d like. Nginx is actively developed, and we might as well take advantage of the developers’ hard work. We’ll start by getting the dependencies; then we’ll grab nginx and build it (check the downloads page for the latest version available):
sudo apt-get install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev
cd ~/downloads
wget http://nginx.org/download/nginx-0.8.53.tar.gz
tar zxvf nginx-0.8.53.tar.gz
cd nginx-0.8.53
Now, before we run through configure, we need to set a few preferences. Specifically, where nginx should be installed to. We’ll also set up nginx to use the SSL module, so https works for our server:
./configure --pid-path=/var/run/nginx.pid --sbin-path=/usr/local/sbin --with-http_ssl_module
Finally, we’ll do a make, and a make install:
make
sudo make install
We’ll make a few quick edits to the nginx configuration file, which is located at /usr/local/nginx/conf/nginx.conf. At the top of that file you’ll see these two lines:
# user nobody;
worker_processes 1;
Uncomment the user line and change nobody to www-data www-data, then change worker_processes to 2 instead of 1. Have a look at the rest of the file; there are a number of settings for logs and other options, a sample server declaration, and a few commented-out examples. We’ll be coming back to this file later, but for now you can save it and close it. nginx doesn’t come with an init script that we can run when the system boots, but there are plenty of good ones available online. Let’s grab one and set it up:

cd ~/downloads
wget http://nginx-init-ubuntu.googlecode.com/files/nginx-init-ubuntu_v2.0.0-RC2.tar.bz2
tar xfv nginx-init-ubuntu_v2.0.0-RC2.tar.bz2
sudo mv nginx /etc/init.d/nginx 
sudo update-rc.d -f nginx defaults
Nginx will now start when your system starts, and you can control it with these commands:

sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx restart
That’s it! At this point you should be able to start up nginx, hit http://localhost/ in your browser, and see the default “Welcome to nginx!” page. Next, we’ll install PHP 5.3.3, then finally, configure everything.

Step Two: Installing PHP 5.3.3

Now we’ll install PHP from source. Feel free to change any of the ./configure parameters as you require—the important ones for our purposes are the --enable-fpm
and --with-fpm lines:

sudo apt-get install autoconf2.13 libbz2-dev libevent-dev libxml2-dev libcurl4-openssl-dev libjpeg-dev libpng-dev libxpm-dev libfreetype6-dev libt1-dev libmcrypt-dev libmysqlclient-dev libxslt-dev mysql-common mysql-client mysql-server
cd ~/downloads
wget http://us3.php.net/get/php-5.3.3.tar.gz/from/us.php.net/mirror/
tar zxvf php-5.3.3.tar.gz
cd php-5.3.3
./buildconf --force
./configure 
	--prefix=/opt/php5 
	--with-config-file-path=/opt/php5/etc 
	--with-curl 
	--with-pear 
	--with-gd 
	--with-jpeg-dir 
	--with-png-dir 
	--with-zlib 
	--with-xpm-dir 
	--with-freetype-dir 
	--with-t1lib 
	--with-mcrypt 
	--with-mhash 
	--with-mysql 
	--with-mysqli 
	--with-pdo-mysql 
	--with-openssl 
	--with-xmlrpc 
	--with-xsl 
	--with-bz2 
	--with-gettext 
	--with-fpm-user=www-data 
	--with-fpm-group=www-data 
	--enable-fpm 
	--enable-exif 
	--enable-wddx 
	--enable-zip 
	--enable-bcmath 
	--enable-calendar 
	--enable-ftp 
	--enable-mbstring 
	--enable-soap 
	--enable-sockets 
	--enable-sqlite-utf8 
	--enable-shmop 
	--enable-dba 
	--enable-sysvmsg 
	--enable-sysvsem 
	--enable-sysvshm
 
make
sudo make install
Next, we’ll configure PHP by copying over the default php.ini and php-fpm.conf files, and setting up PHP-FPM to run when the system boots:
sudo mkdir /var/log/php-fpm
sudo chown -R www-data:www-data /var/log/php-fpm
sudo cp -f php.ini-production /opt/php5/etc/php.ini
sudo chmod 644 /opt/php5/etc/php.ini
sudo cp /opt/php5/etc/php-fpm.conf.default /opt/php5/etc/php-fpm.conf
sudo cp -f sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
sudo chmod 755 /etc/init.d/php-fpm
sudo update-rc.d -f php-fpm defaults
Nice! Now PHP-FPM will be running as a daemon at startup. If you get this or similar when trying to start PHP-FPM:
Starting pfp-fpm ................................ failed.
Make sure your /etc/init.d/php-fpm file has the right path to PHP-FPM, and also ensure you touch the .pid file so that the process can run.
sudo touch /var/run/php-fpm.pid
Success! We now have a running nginx server, and a running PHP-FPM server. All we have to do is combine the two in our site configuration.

Step Three: Setting Up Our WordPress Site

Next, we’ll download WordPress, and install it in our localhost directory for testing. I’m assuming we already have our MySQL database set up with a user specifically for our installation; MySQL is set up exactly the same way, whether you’re using nginx and PHP-FPM or the conventional Apache and PHP stack. First, we’ll set up the directories necessary for our localhost installation:
mkdir ~/public_html
mkdir ~/public_html/localhost/
mkdir -p ~/public_html/localhost/{public,private,logs,backup}
cd ~/downloads
wget http://wordpress.org/latest.zip
unzip latest.zip
mv wordpress/* ~/public_html/localhost/public
cd ~/public_html/localhost/public
vim wp-config-sample.php
Enter your MySQL configuration into wp-config-sample.php. Then, save the file, and rename it to wp-config.php. You now have only one step left! Making nginx and PHP-FPM recognize the new WordPress server.

Step Four: Configuring nginx for PHP-FPM

We’ll set nginx up to work with Debian/Ubuntu’s normal sites-available and sites-enabled folders for site-by-site configuration. You create site configuration files in sites-available, and then symlink those to sites-enabled to activate them. Let’s first create those two folders:
sudo mkdir /usr/local/nginx/sites-available
sudo mkdir /usr/local/nginx/sites-enabled
You now need to tell nginx to load all the configuration files inside sites-enabled. To do this, edit your /usr/local/nginx/conf/nginx.conf file again. Somewhere inside of the http { ... }
block, add the line:
include   /usr/local/nginx/sites-enabled/*;
Then, cut out the entire server { ... } block in nginx.conf—that’s a default server configuration that we’ll be replacing with our virtual hosts in sites-available. Now for the good part. We’ll create a virtual host for our WordPress site, in sites-available. Create a file called localhost (or wordpress, or whatever) inside your sites-available directory. Here’s what to put in it (replace “username” with your username):
server { 
  listen 80; 
  server_name localhost; 
	 
  access_log /home/username/public_html/localhost/logs/access.log; 
  error_log /home/username/public_html/localhost/logs/error.log; 

  location / { 
    root /home/username/public_html/localhost/public; 
    index index.php index.html index.htm; 

    if (-f $request_filename) { 
      expires 30d; 
      break; 
    } 

    if (!-e $request_filename) { 
      rewrite ^(.+)$ /index.php?q=$1 last; 
    } 
  } 
  
  location ~ .php$ { 
    fastcgi_pass   localhost:9000;  # port where FastCGI processes were spawned 
    fastcgi_index  index.php; 
    fastcgi_param  SCRIPT_FILENAME    /home/username/public_html/localhost/public/$fastcgi_script_name;  # same path as above 
    fastcgi_param PATH_INFO               $fastcgi_script_name;
    include /usr/local/nginx/conf/fastcgi_params;
  } 
} 
The configuration is relatively straightforward: first up, we’re defining the web root directory, and specifying which index files the server should look for. Then we set a 30-day expires header on static files, and redirect any other requests to index.php in our WordPress directory. There are far too many available configuration settings for nginx to cover them all here, but there’s a full list on the nginx wiki. Now all that’s left is to add your new site to sites-enabled. We do this with a link:
ln -s /usr/local/nginx/sites-available/localhost /usr/local/nginx/sites-enabled/localhost
sudo /etc/init.d/nginx restart
Open up a browser and go to http://locahost/ (or wherever your server is located). You should see the WordPress installation page. Install your WordPress as you usually do. When setting up clean URLs in the WordPress admin, you’ll need to remove index.php from the permalink structure. (For instance, instead of “example.com/index.php/2010/10/10/my-post/” you’d have “example.com/2010/10/10/my-post/”.) And that’s it! Now you have one lean, mean server for your WordPress site. In the next post, I’ll be looking at a few extra configuration tweaks to our nginx setup, and we’ll also be adding memcached to the mix. Stay tuned!

Frequently Asked Questions (FAQs) about Lightning Fast WordPress with PHP-FPM and Nginx

What are the benefits of using PHP-FPM with Nginx for WordPress?

PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites. It allows the server to handle a higher load. Nginx, on the other hand, is a high-performance HTTP server and reverse proxy. When used together for WordPress, they provide a robust and scalable solution. They can handle a large number of requests, making your WordPress site faster and more efficient. This combination also reduces server response time, improving the overall user experience.

How do I configure PHP-FPM and Nginx for WordPress?

Configuring PHP-FPM and Nginx for WordPress involves several steps. First, you need to install Nginx and PHP-FPM on your server. Then, you need to configure Nginx to work with PHP-FPM. This involves editing the Nginx configuration file to include the necessary PHP parameters. You also need to configure PHP-FPM to work with Nginx, which involves editing the PHP-FPM configuration file. Finally, you need to restart both Nginx and PHP-FPM for the changes to take effect.

Can I use PHP-FPM and Nginx with other CMS platforms?

Yes, PHP-FPM and Nginx can be used with other Content Management Systems (CMS) besides WordPress. They are compatible with any CMS that uses PHP, including Drupal, Joomla, and Magento. The configuration process may vary slightly depending on the specific CMS.

What are the potential issues I might face when using PHP-FPM and Nginx for WordPress?

While PHP-FPM and Nginx can significantly improve your WordPress site’s performance, there are potential issues you might face. These include configuration errors, compatibility issues with certain WordPress plugins, and increased server resource usage. It’s important to thoroughly test your site after configuring PHP-FPM and Nginx to ensure everything works as expected.

How can I troubleshoot issues with PHP-FPM and Nginx on WordPress?

Troubleshooting issues with PHP-FPM and Nginx on WordPress involves checking the error logs for both Nginx and PHP-FPM. These logs can provide valuable information about what might be causing the issue. You can also use debugging tools like WP_DEBUG in WordPress to help identify any issues.

How does PHP-FPM work with Nginx to improve WordPress performance?

PHP-FPM works with Nginx to improve WordPress performance by handling PHP requests more efficiently. Nginx serves static files and passes PHP requests to PHP-FPM. This allows Nginx to focus on what it does best – serving static content – while PHP-FPM handles the dynamic content. This separation of duties results in a more efficient use of server resources and faster page load times.

How do I optimize PHP-FPM and Nginx for WordPress?

Optimizing PHP-FPM and Nginx for WordPress involves fine-tuning various settings. This includes adjusting the number of PHP-FPM workers, configuring Nginx for static file caching, and optimizing your WordPress database. It’s also important to keep your WordPress site, plugins, and themes up-to-date to ensure optimal performance.

Can I use PHP-FPM and Nginx on a shared hosting plan?

While it’s technically possible to use PHP-FPM and Nginx on a shared hosting plan, it’s not typically recommended. Shared hosting environments often have restrictions that can limit the effectiveness of PHP-FPM and Nginx. For best results, it’s recommended to use a VPS or dedicated server.

What are the alternatives to PHP-FPM and Nginx for WordPress?

Alternatives to PHP-FPM and Nginx for WordPress include Apache with mod_php, LiteSpeed with LSAPI, and Microsoft IIS with FastCGI. Each of these combinations has its own strengths and weaknesses, and the best choice depends on your specific needs and server environment.

How do I secure my WordPress site when using PHP-FPM and Nginx?

Securing your WordPress site when using PHP-FPM and Nginx involves several steps. This includes configuring Nginx to block unwanted traffic, setting up a firewall, keeping your server and WordPress site up-to-date, and using strong passwords. You should also consider using a security plugin for additional protection.

Kirk KaiserKirk Kaiser
View Author
nginxPHPWordPress
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form