Installing nginx on Ubuntu 12.04 as a high performance web server.

I’ve been working on a number of large websites recently all of which have been developed on-top of my own web application framework called RocketPack. RocketPack is a simple to learn and code-on MVC framework  written in PHP, in my opinion (but then again I guess I’m biast) contains a nice set of utility classes of which I have developed and continue to maintain, anyway… back to the point… I’ve decided to re-build my web hosting server into a web application hosting power-house. – I’ll be installing a new VPS with nginx, php-fpm and MySQL only… I’ll not be using an mail server on that VPS and will be installing memcached for memory caching.

So lets begin, starting with a clean installation of Ubuntu 12.04 Server I’ll begin by installing MySQL:-

apt-get install mysql-server mysql-client

After these packages have been downloaded you may be asked to enter a new MySQL ‘root’ password, do so and make sure you make a note of what it was 🙂

OK so now we’ll install nginx:-

apt-get install nginx
/etc/init.d/nginx start

If you now type in your server’s IP address you should see a page saying something like ‘Welcome to nginx’… Thats great! – Lets move on to installing PHP….

We will now install PHP-FPM (PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites) which we install as follows:

apt-get install php5-fpm

PHP-FPM is a daemon process (with the init script /etc/init.d/php5-fpm) that runs a FastCGI server on port 9000.

We now need to finish up the nginx installation, we need to configure it to work with PHP etc, so we need to edit the configuration file like so:-

nano /etc/nginx/nginx.conf

First (this is optional) adjust the number of worker processes and set the keepalive_timeout to a reasonable value:-

[...]
 worker_processes 4;
 [...]
 keepalive_timeout 2;
 [...]

You should find the configuration easy to understand but if notyou can learn more about it here: http://wiki.nginx.org/NginxFullExample and here: http://wiki.nginx.org/NginxFullExample2.

The virtual hosts are defined in server {} containers. The default vhost is defined in the file /etc/nginx/sites-available/default – let’s modify it:-

 nano /etc/nginx/sites-available/default

You should modify it as follows:-

[...]
server {
        listen   80; ## listen for ipv4; this line is default and implied
        listen   [::]:80 default ipv6only=on; ## listen for ipv6

        root /usr/share/nginx/www;
        index index.php index.html index.htm;

        # Make site accessible from http://localhost/
        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to index.html
                try_files $uri $uri/ /index.html;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules
        }

        location /doc/ {
                alias /usr/share/doc/;
                autoindex on;
                allow 127.0.0.1;
                deny all;
        }

        # Only for nginx-naxsi : process denied requests
        #location /RequestDenied {
                # For example, return an error code
                #return 418;
        #}

        #error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/www;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                include fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /\.ht {
                deny all;
        }
}
[...]

Uncomment both listen lines to make nginx listen on port 80 IPv4 and IPv6.

server_name _; makes this a default catchall vhost (of course, you can as well specify a hostname here likewww.example.com).

I’ve added index.php to the index line. root /usr/share/nginx/www; means that the document root is the directory/usr/share/nginx/www.

The important part for PHP is the location ~ \.php$ {} stanza. Uncomment it to enable it. Please note that I’ve added the line try_files $uri =404; to prevent zero-day exploits (see http://wiki.nginx.org/Pitfalls#Passing_Uncontrolled_Requests_to_PHP and http://forum.nginx.org/read.php?2,88845,page=3). Alternatively, if you don’t want to use the try_files $uri =404; line, you can set cgi.fix_pathinfo = 0; in /etc/php5/fpm/php.ini (don’t forget to reload PHP-FPM afterwards).

Now save the file and reload nginx:

/etc/init.d/nginx reload

We now need to add PHP support to nginx.. To get MySQL support in PHP, we can install the php5-mysql package. It’s a good idea to install some other PHP5 modules as well as you might need them for your applications. You can search for available PHP5 modules like this:

aptitude search php

Pick the ones you need and install them like this:

apt-get install php5-mysql php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl

By default PHP-FPM is listening on port 9000 on 127.0.0.1. It is also possible to make PHP-FPM use a Unix socket which avoids the TCP overhead. To do this, open /etc/php5/fpm/pool.d/www.conf like so…

nano /etc/php5/fpm/pool.d/www.conf

… and make the listen line look as follows:

[...]
;listen = 127.0.0.1:9000
listen = /tmp/php5-fpm.sock
[...]

Next go through your nginx configuration and all your vhosts and change the line fastcgi_pass 127.0.0.1:9000; to fastcgi_pass unix:/tmp/php5-fpm.sock;, e.g. like this:

nano /etc/nginx/sites-available/default

And amend the file like so…

[...]
 location ~ \.php$ {
 try_files $uri =404;
 fastcgi_split_path_info ^(.+\.php)(/.+)$;
 fastcgi_pass unix:/tmp/php5-fpm.sock;
 fastcgi_index index.php;
 include fastcgi_params;
 }
[...]

Finally reload nginx:

/etc/init.d/nginx reload

Your server should now be ready! – Don’t forget to harden it though with a firewall, PPK authentication, changing the default port for SSH and something like fail2ban.