HHVM, Nginx and Laravel

Lots of people have been asking about how to install HHVM with Nginx for use with Laravel. Here's how.

Updated on 3/31/2014 for use with HHVM 3.0!

Assumptions

This article is written for both Ubuntu 12.04 LTS and 14.04 LTS.

However, this can be installed on your Mac as well via Brew (nginx here and hhvm here).

Information on installing HHVM on other server distributions (including newer Ubuntu's) can be found here.

Alright, let's do it!

Install Essentials

First, we'll install some basics needed to get this done:

$ sudo apt-get update
$ sudo apt-get install -y unzip vim git-core curl wget build-essential python-software-properties

Install Nginx

Next, we'll install Nginx. I install Nginx first, as the hhvm package will change some configurations if it determines Nginx (or Apache, for that matter) is installed. We'll also add the ppa:nginx/stable repository to get the latest stable version of Nginx, which usually includes security updates.

$ sudo add-apt-repository -y ppa:nginx/stable
$ sudo apt-get update
$ sudo apt-get install -y nginx

Install HHVM

Now we get to it! As per the HHVM blog, we can install HHVM with FastCGI. This will both install HHVM and set it up to be run with FastCGI. As per the official documentation, we'll install HHVM, which also includes the ability to start HHVM with FastCGI.

Prior to this, HHVM-Fastcgi was it's own installable package. This is no longer the case.

Ubuntu 12.04:

$ sudo add-apt-repository -y ppa:mapnik/boost
$ wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add -
$ echo deb http://dl.hhvm.com/ubuntu precise main | sudo tee /etc/apt/sources.list.d/hhvm.list
$ sudo apt-get update
$ sudo apt-get install -y hhvm

Ubuntu 14.04:

$ wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add -
$ echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list
$ sudo apt-get update
$ sudo apt-get install -y hhvm

Configure HHVM

Once this is installed, you'll get some important output to pay attention to!

********************************************************************
* HHVM is installed. Here are some more things you might want to do:
* 
* Configure your webserver to use HHVM:
* $ sudo /usr/share/hhvm/install_fastcgi.sh
* $ sudo /etc/init.d/nginx restart
* $ sudo /etc/init.d/apache restart
* $ sudo /etc/init.d/hhvm restart
* 
* Run command line scripts with HHVM:
* $ hhvm whatever.php
* 
* 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
********************************************************************

We can see that HHVM has a script to install and configure FastCGI for us! Run the command they give:

$ sudo /usr/share/hhvm/install_fastcgi.sh # This restarts Nginx for us

# Set this to start on system bootup
$ sudo update-rc.d hhvm defaults

# Restart the service now
$ sudo service hhvm restart                      # We'll also restart HHVM

Running PHP

Now, HHVM is essentially its own version of PHP, so we don't need to do any further installation of PHP.

After this install, you can use hhvm just like you used PHP. For example, you can run PHP files like this:

$ hhvm some_file.php

Since we likely have items (composer, phpunit) which assume "php" (technically php-cli) is available via the command line, we need a way to run HHVM instead of PHP. Note that the second to last line of our above HHVM install output says as much. We can run the one-liner displayed to use HHVM when PHP is called:

$ sudo /usr/bin/update-alternatives --install /usr/bin/php php /usr/bin/hhvm 60

Now you can use "php" just like normal!

$ php -v
HipHop VM 3.0.0 (rel)
Compiler: tags/HHVM-3.0.0-0-g59a8db46e4ebf5cfd205fadc12e27a9903fb7aae
Repo schema: 48906efe08d29a403bbe13414f32ccd256708e0b

Fast-CGI

HHVM actually configured Nginx for us already (sweet!). Notice the new file /etc/nginx/hhvm.conf. If you've used PHP-FPM with Nginx before, the contents of hhvm.conf will look familiar:

# Note this will work with "hack" files as well as php files!
location ~ \.(hh|php)$ {
    fastcgi_keep_conn on;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include        fastcgi_params;
}

If you open up the default Nginx server, you'll also see that it now includes hhvm.conf inside of it! Check out /etc/nginx/sites-available/default:

... Stuff above this omitted ...
    # Make site accessible from http://localhost/
    server_name localhost;
    include hhvm.conf;  # HERE'S THE MAGIC

    location / {
... Stuff below this omitted ...

So, the HHVM developers have thoughtfully made this "just work" for us!

Get some PHP going

Let's play with this. Note the default document root is root /usr/share/nginx/html, which contains an index.html file. If we check out our localhost, we'll see that file there:

vagrant@vaprobash:~$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
... More stuff omitted ...

Let's now create a index.php file to test that it can be served. The following one-liner will create a index.php file which simply contains the phpinfo() function:

$ echo "<?php phpinfo();" | sudo tee  /usr/share/nginx/html/index.php

Then we can try to run that:

vagrant@vaprobash:~$ curl localhost/index.php
HipHop

Great! "HipHop" all the phpinfo() function outputs under HHVM, so we know it's working!

Laravel

With this setup, installing Laravel should be more of the usual you're used to. Since we've symlinked PHP, everything should "just work" like normal. Let's try it out.

Configure Nginx

Let's create a quick virtual host for Laravel. We'll create a new Laravel project in the /vagrant directory (the web root will be /vagrant/laravel/public). Create file /etc/nginx/sites-available/laravel:

server {
    listen 80 default_server;

    root /vagrant/laravel/public;
    index index.html index.htm index.php;

    server_name localhost;

    access_log /var/log/nginx/localhost.laravel-access.log;
    error_log  /var/log/nginx/locahost.laravel-error.log error;

    charset utf-8;

    location / {
    	try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt  { log_not_found off; access_log off; }

    error_page 404 /index.php;      

    include hhvm.conf;  # The HHVM Magic Here

    # Deny .htaccess file access
    location ~ /\.ht {
    	deny all;
    }
}

This configuration will take over the default. In this situation, we'll disable the default and then enable the laravel configuration:

$ sudo rm /etc/nginx/sites-enabled/default   # Remove the sym-linked default config
$ sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/laravel    # Create a sym-link to the laravel config

Then reload Nginx:

$ sudo service nginx reload

Install Composer

This will be the usual installation process to get composer installed globally:

$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer

Install Laravel

Then we can use Composer to create a new Laravel project. I'll just call it laravel, which the document root we configured above expects:

# Move to /vagrant so we install Laravel
# into /vagrant/laravel
$ cd /vagrant
$ composer create-project laravel/laravel laravel

Wait a few while Composer installs Laravel's dependencies and we're done! You should now see Laravel's start screen in your browser!

Notes

You'll want to pay close attention to your error logs. HHVM doesn't report errors to the browser by default.

Check your Laravel logs, of course:

# Show last 50 lines written out to laravel log
$ tail -n 50 -f /vagrant/hhlaravel/app/logs/laravel.log

Check the HHVM logs very closely!

$tail -n 50 -f /var/log/hhvm/error.log

You can read more about run-time and other configurations here.

I think the Documentation in the Github Wiki and on the site are both in a state of flux as this project moves pretty fast. Hopefully some good documentation on error reporting/setup will exist soon. The current docs are either barely-existent (on the site) or seem out of date (on the Wiki) currently. Leave a comment if you know better!

Vaprobash

Vaprobash is now on ubuntu 14.04 LTS and is working towards a stable release (with tags thereafter). You can read more about Vaprobash's future here. Using HHVM and Hack will be as simple as setting hhvm = "true" in your Vagrantfile!