Migrating from Apache & mod_php to Nginx & PHP-FPM


Why we migrated...

Simply put, it was the best decision we have made about our application infrastructure this year. In our particular case we have noticed (what feels like) upwards of 200% speed increase in request times and asset loading. Now we are not saying that apache is trash, but we are saying that a non-blocking IO and event driven web server has its advantages.

When we were using Apache and MOD_PHP each request required Apache to load up another 20mb instance of MOD_PHP and that doesnt come cheap in either time nor system resources. We are sure you are just as uninterested in wasting money on resources when all you need to do is alter your development/hosting stack, and thats precisely what we did.

We heard claims of 6,000 requests with Nginx using no more than 80mb of RAM. This sort of boasting is worth checking out.

Nginx to the rescue...


Putting our ear to the ground and investigating what wonderful information is available on the web concerning Nginx, we found many people have made the switch with great success. Some even boasting up to 500% improvement to content delivery speeds. This sounded too good to be true so we had to find out for ourselves.


After we got all of our ducks in a row and got Nginx and PHP-FPM working together. It truly did turn out to be bliss. We have seen just about a 300% initial request latency improvement, most of it being due to the limited spin-up time and less required over head.

How we migrated...

Basic Assumptions

Lets assume you have a virgin Ubuntu 14.04LTS Server (or VM) up and running with at least 1gb Ram, 1 core, and internet access.

Installing NGINX and PHP-FPM

So we will now install Nginx and PHP-FPM (and some additional extensions if your application requires it)

sudo apt-get install nginx php5-fpm php5-cli php5-curl php5-dev php5-json php5-redis

This will take a couple moments to complete. Once this installation is completed we need to get ourselves into some config files!

Configuring PHP-FPM

Since this tutorial is here to get you up and running quickly, we will skip any talk of tunning PHP-FPM and use the stock configuration file for PHP-FPM's global settings. Assuming the default values are in /etc/php5/fpm we can move on to creating the process pool for your web application.

Configure your PHP-FPM process pool:

Lets star by creating the file /etc/php5/fpm/pool.d/myapp.conf

sudo vi /etc/php5/fpm/pool.d/myapp.conf
 

Now copy & paste the following into the file you just created.

[myapp]
listen = /var/www/myapp/tmp/php.sock
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 100
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 1000
pm.status_path = /php_status

After you have edited the contents of the file to represent your application's requirements, we can restart PHP-FPM

sudo service php5-fpm restart
 

Once this is completed. Verify that the unix socket has been created.

ls -al /var/www/myapp/tmp/php.sock
 

Now lets get started on setting up NGINX work with PHP-FPM.

Configuring NGINX:


For the sake of brevity, we wont be covering global configuration settings for NGINX, but will instead focus on the getting your web application off and running!

First off we will need to create the virtual host file in

sudo vi /etc/nginx/sites-available/myapp.conf
 

At this point you can copy & paste the text below into the file and edit it to suit your web app's specific requirements.

upstream backend {
        server unix:/var/www/myapp/tmp/php.sock;
}

server {
        listen 80 default;
        root /var/www/myapp/web/app/webroot/;
        index index.php;
        #rewrite ^(.*) /$1 permanent;
        
        access_log /var/www/myapp/logs/access.log;
        error_log /var/www/myapp/logs/error.log;

        location / {
                #try_files $uri $uri/ /index.php;
                try_files $uri $uri/ /index.php?$uri&$args;
        }
        
        location ~ \.php(/|$) {
                try_files $uri =404;
                fastcgi_pass backend;
                fastcgi_index index.php;
                fastcgi_split_path_info ^(.+\.php)(/.*)$;
                fastcgi_param SCRIPT_FILENAME /var/www/myapp/web/$fastcgi_script_name;
                include fastcgi_params;
        }
        
        # This location block is used to view PHP-FPM stats
        location ~ ^/(php_status|php_ping)$ {
                fastcgi_pass backend;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
                include fastcgi_params;
                allow 127.0.0.1;
                deny all;
        }
        
        # This location block is used to view nginx stats
        location /nginx_status {
                stub_status on;
                access_log off;
                allow 127.0.0.1;
                deny all;
        }
}

Lets save this file now and give NGINX a quick kick in the head with

sudo service nginx restart
 

Load up your browser and check http://serverIP/ and you should see your web app living happily on your new NGINX and PHP-FPM stack!