We recently had an infrastructure overhaul in order to allow us to expand our hosting options and the uptime and availability of the popular Tumblr Stalkr application.
We needed a platform that was easily scalable, had little overhead and was able to cope with a large volume of concurrent connections. Our traffic has been steadily increasing and whilst Apache has been great and is by-far the most well-known, we needed something that would aid performance rather than hinder it. That's why we looked into Nginx and after some consideration, we decided on a setup and got to work migrating everything over.
Step 1 - Install Nginx
Unlike Ubuntu, CentOS doesn't have the repository needed to get Nginx installed so we first need to add the EPEL and Remi repositories:
Now we can install Nginx:
Potential Problems
When we were setting up Nginx we encountered a wrath of issues on our main VPS that we were using. Mainly, our VPS was running a LAMP stack and cPanel was running lfd which blocked the repository so when we tried to install Nginx we got 'No package nginx found'.
If you encounter any errors, I'd firstly advise making sure the EPEL and Remi repositories are enabled, to do this you can:
Now find [remi] and [remi-php55] and make sure they're both set to 'enabled=1', alternatively, you can prepend the yum command below with:
If you're still having issues, you can manually create the CentOS Nginx repository yourself, create the new file:
Add the following contents (if you're not used to vi, you can press "* and i" to get into insert mode:
Now try installing Nginx again:
Step 2 - Installing PHP-FPM using the Remi Repository
Before we configure Nginx, we want to setup PHP-FPM, its dependencies and then MySQL. In our instance, we already had MySQL installed and the extensions we'll need, so we missed this step but I've included details below.
If you encounter the error message 'No package php-fpm available' I'd advise that you ensure Remi is installed and active with the following command:
If you don't see Remi, repeat the steps above to enable the repository and try again.
Step 3 - Install MySQL and PHP Extensions
With PHP-FPM installed we can now move to setting up any extensions we may want, below is a list of all available extensions and configuring MySQL (though you may already have this installed, if you do, scrap the last two packages on the list below):
Running the query above will automatically install all our required dependencies. You're able to add any other extensions you feel that you may need:
APC (php-pecl-apc) – APC caches and optimizes PHP intermediate code
CLI (php-cli) – Command-line interface for PHP
GD (php-gd) – A module for PHP applications for using the GD graphics library
MBString (php-mbstring) – A module for PHP applications which need multi-byte string handling
MCrypt (php-mcrypt) – Standard PHP module provides mcrypt library support
Memcache (php-pecl-memcache) – Extension to work with the Memcached caching daemon
Memcached (php-pecl-memcached) – Extension to work with the Memcached caching daemon
MongoDB (php-pecl-mongo) – PHP MongoDB database driver
MySQL (php-mysqlnd) – A module for PHP applications that use MySQL databases
PEAR (php-pear) – PHP Extension and Application Repository framework
PDO (php-pdo) – A database access abstraction module for PHP applications
PostgreSQL (php-pgsql) – A PostgreSQL database module for PHP
SQLite (php-sqlite) – Extension for the SQLite v2 embeddable SQL Database Engine
XML (php-xml) – A module for PHP applications which use XML
Step 4 - Start PHP-FPM
Great, PHP-FPM is installed so now lets start it so Nginx can use it:
Step 5 - Test Nginx Alongside Apache
If you're considering switching over from Apache to Nginx, you'd be crazy to get to this point and start Nginx without configuring it and testing everything works. We want a solution that'll let us test everything thoroughly to ensure there's no downtime. If, like us, your VPS has cPanel, your Apache installation will nicely and automatically build all your VirtualHosts for you. Sadly this isn't the same for Nginx and you'll need to configure them.
To begin with, I'm going to run Nginx on port 81 and when I'm happy with everything, I'll switch Nginx over to 80 and turn off Apache (scary!).
Let's setup Nginx to use port 81 by editing the main configuration file:
In our file, look for similar to below and update the number of worker processes and GZIP:
Now lets edit our default configuration:
We want to tell Nginx to listen on port 81 whilst we get everything setup:
Once you've saved, use the commands below to start Nginx.
Step 6 - Fire up Nginx
Enable the Nginx service on startup and then use any of the commands below to start, stop or restart Nginx:
You should now be able to test your Nginx installation by heading over to your VPS IP address and put a port of 81 on the end.
Step 7 - Setting up Nginx Virtual Hosts
In CentOS 6.5, Nginx stores any vhost's in /etc/nginx/conf.d/virtual.conf. Here you can create new server blocks, or create separate .conf files for each one you want to add.
If you've got access to your Apache hosts, then you're pretty much able to copy and paste parts in without much hassle. However, you'll need to convert all your .htaccess files over (if you have any). We found Winginx to be the most reliable htaccess to Nginx converter.
If you want to route everything to an index.php file, similar to how Wordpress works then you can use the following code, same applies to separate directories:
Now save the file, reload Nginx and you should have your first site up and running.
Everything Else that Could Go Wrong
It'd be great if I could say that was potentially the end of the errors.. though you may need to tweak your PHP-FPM configuration to enable it to have more children workers.
To find where PHP-FPM is installed (this was the initial problem for us, it wasn't where we expected), run the command:
Then navigation to the configuration folder and edit its content. When you're editing, you'll see:
We ran into some permission problems where Nginx was dispatched as 'nginx' whilst PHP-FPM was running as 'nobody' which meant it didn't have write permission to our folders. We setup a separate PHP-FPM pool running on port 9001 and assigned it the user/group we waned, who had the correct permissions on our folders. Sadly, if you've got a lot of vhosts like we did, you'll have to do this for every user. Or just global-assign your web root.
To fix file permissions, you may find the following commands particularly helpful (but don't forget, if you change permissions whilst running Apache, your Apache will give a 403 forbidden). To get around Apache and Nginx issues, we had to create a group that was apache, root and nginx - then assign write permission to that group.
Other Helpful Commands
To list members of a group:
To add a new user to a group:
To add an existing user to a group:
What are the Results?
Moving to Nginx proved rather eventful and in our instance we setup load balancing and Varnish cache in front of everything (we'll get into this next week). Though our server load is under 20 averaging between 250 concurrent tests. Our memory usage is also down to just 12% on average, meaning we could rewrite a lot of our CMS code to optimise it for Memcache, Redis and Varnish.
Overall, I'd strongly recommend Nginx to any budding enthusiast who wants to improve their website performance.
Next time, we'll look into setting up load balancing using Nginx, putting Varnish in front of everything and the server setup using multiple cloud instances with synchronisation between the servers. We'll also look into sticky sessions using Nginx, Memcache optimisation tips and dedicated MySQL database servers.