We have been testing for a while our NinjaFirewall sofware running on HHVM (HipHop Virtual Machine), an interesting alternative to PHP.
Compatibility test with HHVM 3.4+
- NinjaFirewall Pro : 100% compatible.
- NinjaFirewall Pro+ : 100% compatible.
- NinjaFirewall WP : 100% compatible.
- NinjaFirewall WP+ : The shared memory option will not be available because HHVM does not support shared memory functions. All other features are fully compatible with HHVM.
Benchmarks
First, let’s have a quick look at some benchmarks. At NinTechNet, we love to stress test all our applications beyond the limits of normal operation and HHVM gives us just another good opportunity to do that.
The test is similar to the first one we performed in 2013, i.e., a massive brute-force attack against WordPress login page using the ab
command: 50,000 login attempts with 5 concurrent requests, as fast and as brutal as possible.
We installed WordPress 4.1, NinjaFirewall (WP edition) 1.3.3 and Nginx 1.4.4 along with:
- PHP-FPM 5.5.6-1
- PHP-FPM 5.5.6-1 + Zend OPcache v7.0.3-dev, the built-in opcode cache
- HipHop VM 3.4.2
The following graph shows the maximum number of requests per second reached during the attack. The higher, the better:
Although all software programs were installed with their default configuration (without any performance optimization), the results are quite impressive on a small dual-core server.
We already knew since our 2013 benchmarks that NinjaFirewall + PHP-FPM could easily handle a 1,000+ RPS brute-force attack, but with the new built-in Zend OPcache available since PHP 5.5, it was able to handle twice as much: 2,600 requests per second.
And with HHVM, out of the box, it reached a total of 3,200 RPS, and processed the 50,000 login attempts in 15 seconds only. Blazing fast.
View ApacheBench raw results: nintechnet_abhhvm2015.txt (6Kb)
PHP INI support
Because NinjaFirewall needs to be loaded before any other PHP script, it relies on the PHP auto_prepend_file
directive which must be added to the website php.ini
(each website must have its own one). But unlike PHP, HHVM lacks support for configuration INI files on a per-directory basis. Instead, it relies on its global /etc/hhvm/php.ini
, a single system INI file used for all sites. This is fine as long as only one site is installed on the server, but it is absolutely not suitable for multiple sites.
We will see however how we can easily bypass this restriction and install multiple instances of NinjaFirewall on several domains including sub-domains and even sub-folders.
Single-site installation
Installing NinjaFirewall on a server running HHVM with one single site is a rather easy task. In our example below, we will install NinjaFirewall Pro on a website named domain.tld
located in the /home/user
folder:
└── /home └── /user └── /domain.tld (NinjaFirewall Pro)
- Upload NinjaFirewall.
- Run its installer until you reach the Integration menu.
- Select HTTP server and PHP SAPI > Other webserver + HHVM and click the Next button.
- On the next screen, copy the
auto_prepend_file
line including the full path to thefirewall.php
script. - Edit HHVM
/etc/hhvm/php.ini
file, and paste that line below the options section:
; NinjaFirewall directive: auto_prepend_file = /home/user/domain.tld/ninjafirewallpro/firewall.php
- Save it and reload HHVM:
# service hhvm restart
- Go back to NinjaFirewall installer and click on the Test NinjaFirewall button.
The firewall should be successfully installed.
Multiple-site installation
We will see a much more complex example here:
- domain_01.tld: will be protected by NinjaFirewall Pro.
- domain_02.tld: must not be protected.
- domain_03.tld: only its WordPress blog located inside the
/blog/
subfolder will require NinjaFirewall WP. The parent directory must not be protected.
Since v3.9, WordPress is fully compatible with HHVM.
└── /home └── /user ├── /domain_01.tld (NinjaFirewall Pro) │ ├── /domain_02.tld (no firewall) │ └── /domain_03.tld (no firewall) └── /blog (NinjaFirewall WP in subfolder)
To achieve our goal, we will create a PHP script inside the /home/user/
folder and use the auto_prepend_file
to load it. It will contain some PHP code to route the HTTP request to the right site/folder and its corresponding NinjaFirewall installation.
1. Installing NinjaFirewall Pro on domain_01.tld:
- Upload NinjaFirewall Pro.
- Run its installer until you reach the Integration menu.
- Select HTTP server and PHP SAPI > Other webserver + HHVM and click the Next button.
- On the next screen, copy the full path to the
firewall.php
script. - Create the PHP script that will be used to route the HTTP request:
<?php // Prepend the firewall for domain_01.tld: if (strpos($_SERVER['SERVER_NAME'], 'domain_01.tld') !== false) { // Add the full path to NinjaFirewall firewall.php: if ( file_exists('/home/user/domain_01.tld/ninjafirewallpro/firewall.php') ) { require('/home/user/domain_01.tld/ninjafirewallpro/firewall.php'); } }
If $_SERVER['SERVER_NAME']
, the requested domain, matches domain_01.tld, it will load NinjaFirewall with the require()
function.
Save this file as /home/user/route.php
.
- Edit HHVM
/etc/hhvm/php.ini
file, and add the full path to that script to theauto_prepend_file
directive:
; NinjaFirewall: load route.php auto_prepend_file = /home/user/route.php
- Reload HHVM:
# service hhvm restart
- Go back to NinjaFirewall installer and click on the Test NinjaFirewall button.
The firewall should be successfully installed for domain_01.tld only.
2. Installing NinjaFirewall WP inside the domain_03.tld/blog/
subfolder:
- Temporarily disable the
auto_prepend_file
directive to prevent any conflict:- Open
/etc/hhvm/php.ini
, comment out theauto_prepend_file
(add a semicolon ‘;’ at the beginning of the line). - Restart HHVM.
- Open
- Install NinjaFirewall WP from your WordPress admin dashboard until you reach the System Configuration page.
- Select HTTP server and PHP SAPI > OtherOther webserver + HHVMand then click the Next button.
- On the next screen, copy the full path to the
firewall.php
script. - Edit
/home/user/route.php
file and append this second part of code for domain_03.tld:
<?php // Prepend the firewall for domain_01.tld: if (!strpos($_SERVER['SERVER_NAME'], 'domain_01.tld') !== false) { // Add the full path to NinjaFirewall firewall.php: if ( file_exists('/home/user/domain_01.tld/ninjafirewallpro/firewall.php') ) { require('/home/user/domain_01.tld/ninjafirewallpro/firewall.php'); } // Prepend the firewall for domain_03.tld/blog/: } elseif ( strpos($_SERVER['SCRIPT_FILENAME'], '/home/user/domain_03.tld/blog') !== false ) { // Add the full path to NinjaFirewall firewall.php: if ( file_exists('/home/user/domain_03.tld/blog/wp-content/plugins/ninjafirewall/lib/firewall.php') ) { require('/home/user/domain_03.tld/blog/wp-content/plugins/ninjafirewall/lib/firewall.php'); } }
This time, we will rely on the $_SERVER['SCRIPT_FILENAME']
server variable to ensure that the requested script is located inside the domain_03.tld/blog/
subfolder in order to load the firewall.
- Open HHVM
/etc/hhvm/php.ini
file and uncomment (remove the semicolon ‘;’) theauto_prepend_file
directive. - Restart HHVM.
- Go back to NinjaFirewall installer and click on the Next Stepbutton.
NinjaFirewall WP edition should be loaded and enabled for the domain_03.tld/blog/
subfolder only, without conflicting with the Pro edition used to protect domain_01.tld
. Other domains are not affected by the firewall.