Installing Nginx, php-fpm, HHVM on Ubuntu 14.04

Installing Nginx, php-fpm, HHVM on Ubuntu 14.04

In this post I am going to show you how to setup PHP in a different way, instead of using the our old friends Apache and mod_php we will use Nginx web server, php-fpm and HHVM stack.

So why should we ditch Apache? I have been using Apache for over 10 years now and it is very good at what it does but for small website being served on small server it's not so good as it's using a ton of memory then add to that MySQL server and soon you will find your memory being quickly swallowed by these two.

HHVM (Hip Hop Virtual Machine) is best left to the creators to describe it.

What is HHVM?

HHVM is an open-source virtual machine designed for executing programs written in Hack and PHP. HHVM uses a just-in-time (JIT) compilation approach to achieve superior performance while maintaining the development flexibility that PHP provides.

PHP-FPM (FastCGI Process Manager) comes bundled with PHP 5.5 and above and is a better alternative to PHP FastCGI a full list of FPM feasters are on the php.net site, so without further ado lets install all this.

Install PHP and PHP-FPM

First let install PHP and PHP-FPM, all these are really easy with Ubuntu as they are in the main repositories, so to do this lets install PHP with some standard modules. In the terminal type

sudo apt-get install php5-fpm php5 php5-common php5-gd php5-mysql php5-imap php5-cli php5-cgi php-pear php-auth php5-imagick imagemagick php5-curl php5-intl php5-ming php5-ps php5-pspell php5-recode php5-sqlite php5-tidy php5-xmlrpc php5-xsl

When that is done run php -v and you should get back something like


PHP 5.5.9-1ubuntu4.11 (cli) (built: Jul  2 2015 15:23:08)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies

Now with PHP installed lets move on

Install Nginx

Again this is straight forward as Nginx is in the main repositories so in the terminal enter

sudo apt-get install nginx

To check your web server in a browser navigate to 'localhost' if you are installing this on you computer, if you are installing this on a remote server navigate to that address and you should see.

nginx.png

Okay so now we will install HHVM

Install HHVM

This is a little more complicated as we will have to add the HHVM repository and Ubuntu doesn't have it in its the main repository so again in the terminal enter

wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add -

This will download and install HHVM's repository key now add the repository to apt by entering

echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list

Now update apt

sudo apt-get update

And install HHVM by

sudo apt-get install hhvm

Once this has finished you should see at the end this

********************************************************************
* HHVM is installed.
*
* Running PHP web scripts with HHVM is done by having your
* webserver talk to HHVM over FastCGI. Install nginx or Apache,
* and then:
* $ sudo /usr/share/hhvm/install_fastcgi.sh
* $ sudo /etc/init.d/hhvm restart
* (if using nginx)  $ sudo /etc/init.d/nginx restart
* (if using apache) $ sudo /etc/init.d/apache restart
*
* Detailed FastCGI directions are online at:
* https://github.com/facebook/hhvm/wiki/FastCGI
*
* If you're using HHVM to run web scripts, you probably want it
* to start at boot:
* $ sudo update-rc.d hhvm defaults
*
* Running command-line scripts with HHVM requires no special setup:
* $ hhvm whatever.php
*
* You can use HHVM for /usr/bin/php even if you have php-cli
* installed:
* $ sudo /usr/bin/update-alternatives \
*    --install /usr/bin/php php /usr/bin/hhvm 60
********************************************************************

This tells us we have do some things to get HHVM working so in the terminal run

sudo /usr/share/hhvm/install_fastcgi.sh

This will install some defaults in nginx then

sudo update-rc.d hhvm defaults

This will make sure HHVM will start when the machine is rebooted, now will still have to configure some things before our php script will use HHVM.

Configuration

So to get HHVM to work we will need to add some rules to the NGINX config so my default nginx site config looks like this

server {
    listen 80;

    root /home/ubuntu/public;
    index index.html index.php;

    # Make site accessible from http://localhost/
    server_name localhost;
    client_max_body_size 100M;

    location / {
        try_files $uri $uri/ /index.php?$is_args$args;
        autoindex on;
    }
    
    location ~ \.(php)$ {
        try_files $uri =404;
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 4k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
    }
}

On line 4 we are telling nginx are web root will be in the folder '/home/ubuntu/public' this is where all our files will be served from.

On line 11-14 we are telling nginx to try serving the requested page first, if it's not there then route all request to our index.php page with all it's request arguments. This is good for MVC applications.

On line 16-26 we are telling nginx to serve all files that end in '.php' to be served through cgi php5-fpm and using the unix socket instead of tcp port. Unix socket has slightly better performance.

Ubuntu automatically configures php5-fpm to use the unix socket. It might be different on other linux distros so beware of this. You may want to check the php5-fpm config file and change the setting in the fpm pool listen = /var/run/php5-fpm.sock

You can check this by adding <?php phpinfo(); to your 'index.php' file in your web root and navigating to it in a browser and you should see the php settings info page. If you see nothing then some thing my be wrong so recheck your setting are correct.

Now to add HHVM to run as default and will will putt php5-fpm as a fallback option as HHVM can fail sometimes. So the HHVM cgi run listens by default on a TCP sockets that being 127.0.0.1:9000 so again we will alter our config so we need to change our php location block to

location  ~ \.(php|hh)$ {
    proxy_intercept_errors on;
    proxy_buffer_size 128k;
    proxy_buffers 4 128k;
    error_page 500 501 502 503 = @fallback;

    fastcgi_keep_conn on;
    fastcgi_buffers 16 128k;
    fastcgi_buffer_size 128k;

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_read_timeout 1200;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include        fastcgi_params;
}

On line 2 we are telling nginx to intercept all error so we can catch them and deal with them.

On line 5 we are telling nginx to send all 500, 501, 502 and 503 server errors to our fallback.

On line 11 we are telling nginx to pass all php requests to to hhvm listening on port 127.0.0.1 and port 9000.

Now we need to add our fallback block so we add

location  @fallback {
    proxy_buffer_size 128k;
    proxy_buffers 4 128k;

    include fastcgi_params;

    fastcgi_buffers 16 128k;
    fastcgi_buffer_size 128k;
    fastcgi_index  index.php;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_read_timeout 300;
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

All this does is pass all request to php5-fpm via the unix socket if hhvm gives us a server error.

so our our whole block should like

server {
    listen 80;

    root /home/ubuntu/public;
    index index.html index.php;

    # Make site accessible from http://localhost/
    server_name localhost;
    client_max_body_size 100M;

    location / {
        try_files $uri $uri/ /index.php?$is_args$args;
        autoindex on;
    }
    
    location  ~ \.(php|hh)$ {
        proxy_intercept_errors on;
        proxy_buffer_size 128k;
        proxy_buffers 4 128k;
        error_page 500 501 502 503 = @fallback;

        fastcgi_keep_conn on;
        fastcgi_buffers 16 128k;
        fastcgi_buffer_size 128k;

        fastcgi_pass   127.0.0.1:9000;
        fastcgi_read_timeout 1200;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    location  @fallback {
        proxy_buffer_size 128k;
        proxy_buffers 4 128k;

        include fastcgi_params;

        fastcgi_buffers 16 128k;
        fastcgi_buffer_size 128k;
        fastcgi_index  index.php;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_read_timeout 300;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

All that's need to do is restart nginx with

sudo service nginx restart

and that should be it. You should now notice faster execution times with hhvm.

Just a word of warning not all php applications are compatible with hhvm and also hhvm does not give browser errors only a white screen if you have any errors in your code all errors are logged in the hhvm log file.

Anyway that's all for now with this one, have fun and experiment and if you have question on this use the comments below and I will try to answer them as best as I can.

Thanks.


02/09/2015 12:48:00 Shaun Freeman Filed Under: Linux HHVM, Nginx, PHP, php-fpm, Ubuntu

Twitter Feed
Shaun Freeman @Zendmaster

Shaun Freeman @Zendmaster

I liked a @YouTube video https://t.co/lSFWmpHTX1 Patrick Stewart talks about meeting Sting on the set of DUNE (Funny to the EXTREME)

Shaun Freeman @Zendmaster

I added a video to a @YouTube playlist https://t.co/pmXSmod4ti Anonymous - This will Change Everything You Know... (2018-2019)

Shaun Freeman @Zendmaster

I added a video to a @YouTube playlist https://t.co/GkwTCvBfes Will Artificial Intelligence Take Over The World?

Shaun Freeman @Zendmaster

I liked a @YouTube video https://t.co/Y1ulafmsC6 Frank Abagnale: "Catch Me If You Can" | Talks at Google

Shaun Freeman @Zendmaster

I liked a @YouTube video https://t.co/NBdW2xFnqD ETS2: Special Transport DLC Trailer