Advanced Usage: FastCGI

HHVM has built-in support for two server types: Proxygen and FastCGI.

FastCGI provides a high performance interface between your codebase and web server (e.g., persistent processes between requests, etc.), but which will also obviously require a front-end compatible web server to serve the requests (e.g., nginx).

How FastCGI Works

HHVM-FastCGI works much the same way as PHP-FPM. HHVM, running in FastCGI mode, is started independently of the web server (Apache, nginx, etc). It listens on either a TCP socket (conventionally localhost:9000) or a UNIX socket. The web server listens on port 80 or port 443 like it normally would. When a new request comes in, the web server either makes a connection to the application server or reuses one of the previously open connections, and communicates using FastCGI protocol. Therefore, the web server continues to decode HTTP protocol, and supplies HHVM with information like the path of the file to be executed, request headers, and body. HHVM computes the response and sends it back to the web server using FastCGI again. Finally, the web server is in charge of sending the HTTP response to the client.

Using FastCGI

To run the server in FastCGI mode pass the following parameters to hhvm runtime:

hhvm --mode server -d hhvm.server.type=fastcgi -d hhvm.server.port=9000

The server will now accept connections on localhost:9000. To use a UNIX socket, use the Server.FileSocket option instead:

hhvm --mode server -d hhvm.server.type=fastcgi -d hhvm.server.file_socket=/var/run/hhvm/sock

To turn the server into a daemon, change the value of mode:

hhvm --mode daemon -d hhvm.server.type=fastcgi -d hhvm.server.file_socket=/var/run/hhvm/sock

Note, all the usual options that are accepted by hhvm runtime can be used in FastCGI mode as well. In particular, -d hhvm.admin_server.port=9001 will create an additional "admin" server listening on a port 9001.

Making it work with Apache 2.4

Ensure that you have apache installed via something like:

sudo apt-get install apache2

The recommended way of integrating with Apache is using mod_proxy mod_proxy_fcgi. Enable the modules, then in your Apache configuration, add a line as so:

ProxyPass / fcgi://127.0.0.1:9000/path/to/your/www/root/goes/here/
# Or if you used a unix socket
# ProxyPass / unix://var/run/hhvm/sock|fcgi://127.0.0.1:9000/path/to/your/www/root/goes/here/

This will route all the traffic to the FastCGI server. If you want to route only certain requests (e.g. only those from a subdirectory or ending *.php, you can use ProxyPassMatch, e.g.

ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/path/to/your/www/root/goes/here/$1 

Consult mod_proxy_fcgi docs for more details on how to use ProxyPass and ProxyPassMatch.

Also make sure to set up a DirectoryIndex in your Apache configuration like this:

<Directory /path/to/your/www/root/>
    DirectoryIndex index.php
</Directory>

This will try to access index.php when you send a request to a directory.

Making it work with nginx

Ensure that you have nginx installed via something like:

sudo apt-get install nginx

Now nginx needs to be configured to know where your PHP files are and how to forward them to HHVM to execute. The relevant bit of nginx config lives at /etc/nginx/sites-available/default -- by default, it's looking in /usr/share/nginx/html for files to serve, but it doesn't know what to do with PHP.

Our included script sudo /usr/share/hhvm/install_fastcgi.sh will configure nginx correctly for stock installs. The important part is that it adds include hhvm.conf near the top of of the nginx config mentioned above -- this will direct nginx to take any file that ends in .hh or .php and send it to HHVM via fastcgi.

The default FastCGI configuration from Nginx should work just fine with HHVM-FastCGI. For instance you might want to add the following directives inside one of your location directives:

root /path/to/your/www/root/goes/here;
fastcgi_pass   127.0.0.1:9000;
# or if you used a unix socket
# fastcgi_pass   unix:/var/run/hhvm/sock;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
include        fastcgi_params;

The traffic for the surrounding location directive will be now routed to the HHVM-FastCGI server.

Testing

To test that everything is working, write this hello world script to hello.php in whichever directory nginx looks for its web files -- depending on OS, this may be /usr/share/nginx/html/hello.php or /var/www/html/hello.php or somewhere else:

<?php
echo "Hello world!\n";

If the HHVM server is not running, start it up:

hhvm -m server -d hhvm.server.type=fastcgi -d hhvm.server.port=9000

and then load http://localhost/hello.php and verify you see "Hello world".

Note that by default /usr/share/nginx/html is only writable by root; use chown to set permissions as appropriate, or point /etc/nginx/sites-available/default at a different root, or refer to the nginx documentation to do something more fancy. Basically at this point you know things are working, so you can start from a known-good state as you start customizing your configuration, so it's easy to know if things break later which change broke it.

Admin Server in Nginx

If you ran with -vAdminServer.Port=9001 then something like this would work:

location ~ {
    fastcgi_pass   127.0.0.1:9001;
    include        fastcgi_params;
}