How To: Set Up and Configure HHVM on Ubuntu 14.04

HHVM or HipHop Virtual Machine is an virtual machine that executes code written in PHP or Hacklang using a just-in-time (JIT) compilation approach to realize greater performance than would otherwise be achievable. In this post, I will be running through how to install and set up HHVM on an Ubuntu 14.04 Server set up using an Apache Virtual Hosts configuration. In the end, you will be able to run traditional and HHVM-based PHP-powered web applications side-by-side on the same system. ## Install HHVM We don't need to all get fancy compiling anything, so we will simply install the prebuilt HHVM packages for Ubuntu 14.04 (64-bit). Run the following... ```bash 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 hhvm ``` *Source: https://github.com/facebook/hhvm/wiki/Prebuilt-Packages-on-Ubuntu-14.04* Next, we need a way to hook HHVM into our Apache web server. This is done using FastCGI, which we will need to install. Luckily, HHVM provides a shell script to set this up. Run the following... ```bash sudo /usr/share/hhvm/install_fastcgi.sh ``` Also, to ensure HHVM fires up at boot, run this... ```bash sudo update-rc.d hhvm defaults ``` ## Configure HHVM and Apache Virtual Hosts The install script will ask you to restart both HHVM and Apache. Don't just yet, otherwise your site visitors will be seeing some 404 action coming their way. Instead, open hhvm_proxy_fcgi.conf and comment the single ProxyPassMatch line that's in there. ```bash sudo nano /etc/apache2/mods-available/hhvm_proxy_fcgi.conf ``` ```apacheconf # ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/$1 ``` This stops all PHP/Hack scripts from being routed through FastCGI, this will allow you to choose which web applications you'd like to send through HHVM. If you're only running a single web application in your web server root, you don't need to do this, but I feel it's a smart move regardless. Right now HHVM is running but has no way for scripts to be handed off to it. We need to add the ProxyPassMatch configuration to the Virtual Host Configuration for the web applications we'd like HHVM to power. Add this to each Virtual Host instance in each configuration file (both secure and non-secure traffic covered in the example below.). ```bash sudo nano /etc/apache2/sites-available/hhvm.example.com.conf ``` ```apacheconf # HHVM Example - hhvm.example.com <VirtualHost *:80> ServerName hhvm.example.com DirectoryIndex index.php DocumentRoot /var/www/sites/hhvm.example ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/sites/hhvm.example/$1 </VirtualHost> <VirtualHost *:443> ServerName hhvm.example.com DirectoryIndex index.php DocumentRoot /var/www/sites/hhvm.example SSLEngine On SSLCertificateFile /etc/ssl/certs/hhvm.crt SSLCertificateKeyFile /etc/ssl/private/hhvm.key SSLCACertificateFile /etc/ssl/certs/hhvm.ca.crt ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/sites/hhvm.example/$1 </VirtualHost> ``` #### *Pro-Tip* You can also designate another port to explicitly use HHVM if you'd like to quickly A/B test the performance gains. To do this, simply open the port in /etc/apache2/ports.conf ```apacheconf Listen 8080 ``` Then in your Virtual Host configuration, create another instance with the new port specified and add the ProxyPassMatch configuration to the one you'd like to run HHVM on. ```apacheconf <VirtualHost *:80> ... </VirtualHost> <VirtualHost *:8080> ... ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/$1 </VirtualHost> ``` ## Restart Apache and HHVM Now, we are ready to kick Apache and HHVM in the head. Restart both services... ```bash sudo service apache2 restart sudo service hhvm restart ``` The web application should load as you would normally expect, only a bit quicker. ### *I'm getting 503'd!* If you jumped over to your web application only to be greeted with a 503 error, this means you just need to fire up the daemon manually this first time or restart. Subsequent restarts will automatically fire this up. ```bash hhvm --mode daemon -vServer.Type=fastcgi -vServer.Port=9000 ``` ## Testing It's not immediately apparent whether your code is being passed through HHVM. There are a few ways to test this. ### Client-Side The easiest way to check if HHVM is doing it's thing is to inspect the response headers we get back from our web application. At the bottom of the header list, you will find **X-Powered-By** which should show **HHVM/3.2.0**. To get to this, you can right click on the page, inspect any element, then click the "Network" tab in the developer tool panel. It will appear to be empty or nearly empty. Refresh the page and it will repopulate fully. Scroll to the top of the list and click the first item, it will be labeled with the domain name (hhvm.example.com in my case). ### Server-Side Drop the following into your application root and then access this script. If it returns **PHP**, it's not working. If it returns **HHVM**, you're golden! ```php <?php if (defined('HHVM_VERSION')) { echo "HHVM"; } else { echo "PHP"; } ```