How do you migrate an existing Apache server, to a brand new nginx installation for several websites that use PHP? This is a simple tutorial into changing an Apache installation into a nginx one, without having to change your existing websites.
nginx is a server that scales far better compared to apache running on the same hardware. The tutorial is not super CentOS specific, but all the commands were run on a CentOS.
The Apache server that was migrated, namely this blog, has several virtual hosts, that are all running PHP, some of them Joomla websites. The plan is to take them as they are, and have them available externally the same way as before, using the same virtual host names, the same folder locations, with the same users assigned to them.
The reason is that if we screw up something in the process, we can just revert to our old proven Apache, by just restarting the Apache service and shutting down nginx. Also we can minimize the downtime, since if done right it should be in the end just shutting down apache and starting nginx, but if it doesn't work we can quickly go back to serving the files with Apache until we figure out what is going on.
While it is simple, it is a pretty long read, so grab your coffee, and hack away:
1. Install nginx
This is as simple as running:
Make sure the /etc/nginx/conf.d/default.conf has the paths pointing to /var/www/html, or whatever was the default site for your Apache configuration. (In my case it was /var/www/blog).
2. Enable PHP processing
Unlike Apache, the PHP processing does not take place in the same process as nginx via modules, since nginx doesn't supports modules except at compile time. That's why having a service to do the PHP rendering is required.
Since I already have PHP installed for my apache installation, most of the packages are already installed, so I only needed the FastCGI integration to get it running under nginx.
If you're doing a new installation you would need to fetch also cli and common packages, and whatever other libraries you would need (like gd or whatever else your web application requires).
Now let's add the PHP processing via php-fpm. They should look something like this:
Don't just uncomment the configuration that is there, since it will be prone to attacks, and it won't work out of the box either.
Furthermore since Joomla uses a pretty messed up path segment processing to pass its arguments (e.g. /index.php/blog/96-sun-misc that Joomla uses vs /index.php?category=blog&article=96-sun-misc), you will need to add another rule into the root location of your server:
The line itself looks like:
And added in the root location will look in the end about like this:
Now because we're rewriting the URLs we also need to take special care for our Joomla sites that we don't execute php files from writable folders. Thus we need to add after the root location the following:
Basically php-fpm will do the rendering of the PHP pages, and nginx will just proxy them. For all the other resources nginx itself will serve them. Neat!
We're almost done:
3. Use the apache user
Since we want to reuse the same deployment layout, we will preserve the users and folders. Thus we need to tell nginx to run as the `apache` user.
Edit /etc/nginx/nginx.conf and change the user from nginx to apache.
Note that in theory we would also need to change the user in the php-fpm, but the default user that is used is already apache.
Set the right user for the work folder of nginx.
4. Test the configuration
Then let's start our services:
Then your old website should be appearing.
In my website I had gzip compression for certain mime types (http://ciplogic.com/index.php/blog/98-creating-joomla-responsive-templates) so I had this into my httpd.conf:
So in order to add them as well to nginx, the following changes are needed to be added into a new file named /etc/nginx/conf.d/gzip_compression.conf, and also having the new font mimetypes registered into the existing /etc/nginx/mime.types.
Simply add the mime types, basically the AddType statements from the previous configuration, before the closing bracket into the /etc/nginx/mime.types file.
Enable the gzip compression, and register it for our mime types. Note that text/html is registered by default, and you will get a warning if you add it into the gzip_types.
Restart nginx for changes to take effect.
5.2 Use Local Sockets for php-fgm
If you noticed at step 2, in order to get our PHP running, the nginx server was talking via the loopback device to the php-fpm daemon on port 9000. Since we don't want to transport everything via TCP/IP for no good reason, we'll use local sockets that should be slightly faster in establishing the connections, and actual serialization of data.
Our local socket will be located at: /var/run/php-fpm/php-fpm.socket.
Thus in the /etc/php-fpm.d/www.conf file, we need to change the listen from:
The reason for the other lines is that by default, because of reasons, php-fpm will create the socket with the owner root, despite the fact that the actual runner instances for this pool will run as apache (see step 3). And we want a socket with just enough rights that can be read by nginx.
Thus we will change in both /etc/nginx/conf.d/default.conf the fastcgi_pass to:
6. Virtual Hosts
Now for each virtual host basically the same configuration takes place, but only with the location configuration sections for the root and the PHP processing. For example this is what I use for the codeeditor.ciplogic.com:
7. Make it permanent
Since all seems fine now, the last thing we need to do is to ensure that when rebooting the nginx with php-fpm will start up instead of apache. Thus we need to disable the old httpd service and enable both nginx and php-fpm.
Congratulations! You're done.
Performance wise the speed increase was relatively marginal, about 5% better for fetching the php files. Considering that I didn't changed the PHP version, nor upgraded Joomla, or did anything else, that alone sounds amazing, but not only it was faster, also the memory usage dropped in half, from 240MB under apache to 130MB using nginx + php-fpm.
Faster server, and smaller footprint? Well count me in.