Skip to content

FastCGI

JavaProphet edited this page Aug 14, 2015 · 38 revisions

Basics

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.

Running the server

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

hhvm --mode server -vServer.Type=fastcgi -vServer.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 -vServer.Type=fastcgi -vServer.FileSocket=/var/run/hhvm/sock

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

hhvm --mode daemon -vServer.Type=fastcgi -vServer.FileSocket=/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, -vAdminServer.Port=9001 will create an additional "admin" server listening on a port 9001.

Making it work with Apache

Apache 2.4

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.

Apache 2.2

Apache 2.2 does not have mod_proxy_fcgi so you need to install libapache2-mod-fastcgi and then enable the module. Additionally you need the actions module which comes bundled with apache 2.2.

a2enmod actions alias

In your virtual host add these lines:

<IfModule mod_fastcgi.c>
    <FilesMatch \.php$>
        SetHandler hhvm-php-extension
    </FilesMatch>

    <FilesMatch \.hh$>
        SetHandler hhvm-hack-extension
    </FilesMatch>

    Alias /hhvm /hhvm
    Action hhvm-php-extension /hhvm virtual
    Action hhvm-hack-extension /hhvm virtual

    FastCgiExternalServer /hhvm -host 127.0.0.1:9000 -pass-header Authorization -idle-timeout 300
</IfModule>

This will make all .php and .hh files go over to the FastCGI server.

Note: It won't work without the "Alias /hhvm /hhvm" line!

Note: It won't work if "/hhvm" is real directory with real files and you are using mod_rewrite rules

If you started hhvm as a socket, change the FastCGIExternalServer line to

FastCGIExternalServer /hhvm -socket /var/run/hhvm/sock -pass-header Authorization -idle-timeout 300

Note: If you use mod_rewrite or get a 404 not found please try adding: -vServer.FixPathInfo=true

Note: If you get a 403 (Access forbidden, "client denied by server configuration: /hhvm" in error.log) try to enable access to "/hhvm"

   <Location /hhvm>
       # here we prevent direct access to this Location url,
       # env=REDIRECT_STATUS will let us use this "/hhvm" url
       # only after an internal redirect (by Action upper)
       Order Deny,Allow
       Deny from All
       Allow from env=REDIRECT_STATUS
   </Location>

or, if you want to allow urls like /hhvm/example.php

    <Location "/hhvm">
    	Allow from all
    </Location>

Making it work with Nginx

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.

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;
}

Making it work with Avuna

Edit the configuration file at /plugins/FCGI/plugin.cfg (or if your running many VHosts, you may have this specified elsewhere).

    php{
        unix=true                        # Use UNIX sockets, if true, set sock file to ip, port is ignored.
        ip=/var/run/hhvm/sock            # set to localhost or 127.0.0.1 for TCP
        port=-1                          # port number for FCGI if not unix, 9000 by default.
        mime-types=application/x-php     # comma delimited, default is .php files.
    }

Also, make sure you set enabled=true.

Note: Any autoconfiguration(say in Avuna Panel), will not work well with HHVM yet.

Architecture

All the I/O is non-blocking. The server uses two types of threads: I/O worker threads and HHVM worker threads:

  • A single I/O worker thread is responsible for accepting connections.
  • A few I/O worker threads jointly handle I/O on the open connections. Under heavy load there will roughly be a single I/O thread per CPU which is the optimal setup. New connections are distributed among I/O threads using a round robin algorithm. I/O threads never block waiting on a single connection. An I/O thread will only block if there is no activity on either of the connections that it handles (it then waits on a call to select or a similar system routine).
  • HHVM worker threads are in charge of PHP execution. They may block waiting for the body of the message (this will typically happen only for large POSTs). Translation cache is shared by all the worker threads and lives on after request handling is finished. This approach works well with JIT. When the same file is executed multiple times, you will see significant speed-ups.
Clone this wiki locally