Setting Up Nginx & PHP-FPM on Ubuntu 10.04

This is another wonderful setup that I’ve found myself using rather than the traditional Apache & mod_php setup.

What is Nginx?

Nginx (pronounced engine-x) is a fast, powerful, lightweight web server. I won’t go into the theory under-the-hood, but it’s focus is high concurrency with low memory usage. So while Apache is more robust in supporting many different features, nginx focuses on handling the important features very quickly. I still use Apache internally for our SVN & Trac web server. Heck, even at this time I’m using Apache to host this blog. However, Dating DNA, Clipish, CEVO, Alienware Arena, and some other high traffic sites/apis use nginx.

Ngnix, unlike Apache, doesn’t actually load PHP. Instead, it hands it off as a proxy to a “php handler” which acts like an Application Server. So nginx by itself won’t serve PHP files, but just static files.

What is PHP-FPM?

In the past, when working with something like Nginx or lighttpd, you would use spawn-fcgi to host your PHP application. However, spawn-fcgi had some major drawbacks and problems. So a guy named Andrei Nigmatulin created PHP-FPM, which stands for “PHP FastCGI Process Manager.” Since then, several others have contributed and ultimately it was include into the PHP core in version 5.3.3.

So from a high level look, on every PHP request Apache will load the entire installed PHP environment each time. This is for every request, and while it has been optimized as much as it can, that is a lot of overhead! With PHP-FPM, it will spin up a configurable amount of children. Each load the PHP environment and then will serve as many requests as it can without having to reload the environment. This saves on a lot of overhead!

Why use Nginx & PHP-FPM?

I should note, it is possible to configure/compile Apache in such a way that it can have similar performance capabilities. However, it takes a ton of work. Meanwhile, Nginx & PHP-FPM are very fast from the start, so I prefer just using them. You do lose some features, like .htaccess files won’t work so you’ll have to do that configuration in your virtual hosts.

How to Setup Nginx & PHP-FPM

Nginx

First off, lets setup Nginx.

sudo aptitude update
sudo apt-get install nginx
/etc/init.d/nginx start

Thats it! If you go to your server’s IP Address or Domain Name you should see a “Welcome to Nginx!”

PHP-FPM

Because PHP-FPM is only included by default in PHP 5.3.3 and later, and Ubuntu 10.04 LTS only has PHP 5.2.3, we have two options. Either we can install by source, or we can add another repository to install PHP-FPM. The latter is much, much easier, and there is a good PHP-FPM Repo for Ubuntu 10.04. To add it, you just run the following commands:

sudo aptitude install python-software-properties
sudo add-apt-repository ppa:brianmercer/php
sudo aptitude update

Now that we have the new repository, we can install PHP5:

sudo aptitude install php5-cli php5-common php5-mysql php5-suhosin php5-gd php5-dev
sudo aptitude install php5-fpm php5-cgi php-pear php5-memcache php-apc
/etc/init.d/php5-fpm restart

Excellent! Now, if you need to change some of PHP-FPM’s configurations, they are found in /etc/php5/fpm/. The file php5-fpm.conf configures how FPM will opporate, and the php.ini is the settings file that PHP will use while running in FPM.

A few settings I like to change in /etc/php5/fpm/php5-fpm.conf:

pm.max_children = 20

The php5-fpm.conf that comes is pretty well documented on the different settings. Once you make a change, make sure to restart php5-fpm.conf: /etc/init.d/php5-fpm restart

Configuring Nginx

Now, we have a few settings for Nginx. The configuration files are found in /etc/nginx/. First we’ll edit nginx.conf. Here are a few settings we’ll want to change:

user www-data;
worker_processes  4; # 1 to 4, I normally put this to the number of cores

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
    multi_accept on; # uncomment this line
    use epoll; # Add This - We'll want Nginx to use epoll for event timing
}

http {
    include       /etc/nginx/mime.types;

    access_log  /var/log/nginx/access.log;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;
    tcp_nodelay        on;

    gzip  on;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Now, we need to add a VirtualHost! Nginx uses the same layout in Ubuntu as Apache, so we’ll add configurations for each site we want under /etc/nginx/sites-available/. So using vi, nano, or whichever editor you prefer, create a /etc/nginx/sites-available/www.example.com file:

# rewrite from example.com to www.example.com
server { 
	listen 80;
	server_name example.com;
	rewrite ^(.*) http://www.example.com$1 permanent;
}

server {
    listen   80;
    server_name www.example.com;
    access_log /var/log/nginx/www.example.com.access.log;
    error_log /var/log/nginx/www.example.com.error.log;

	client_max_body_size 4M;
	client_body_buffer_size 128k;
	expires 24h;
 
    location / {
        root   /var/www/example.com/;
        index index.html index.php;
		
        # if file exists return it right away
        if (-f $request_filename) {
                break;
        }

        if (-e $request_filename)
        {
                break;
        }

        # Useful rewrite for most frameworks, wordpress
        if (!-e $request_filename) {
                rewrite ^(.+)$ /index.php last;
                break;
        }

    }

    location /nginx_status {
      # copied from http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/
      stub_status on;
      access_log   off;
      allow 127.0.0.1;
      deny all;
    }

    location ~ \.php$ {
        expires off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/example.com/$fastcgi_script_name;
    }
}

Now, we need to create the symlink from sites-enabled to sites-available:

ln -s /etc/nginx/sites-available/www.example.com /etc/nginx/sites-enabled/www.example.com

Restart nginx with “/etc/init.d/nginx restart”. Go ahead and put a test.php file in your directory with a Hello World example, and see if it works. It should work, and you should be good to go.

Justin is currently the Director of Development for the Deseret News. He is active in the Utah Open Source community. He is an advisory member of the Utah Open Source Foundation, and helps with the anual Utah Open Source Conference. He primarily focuses on PHP, MySQL, Redis, HTML, CSS, jQuery, and JavaScript. When he gets the time, he enjoys to play jazz piano. Read More

Tagged with: , , , , ,
Posted in Technology