nghttp2: an excellent alternative to an NGINX proxy

Recently at work, I had a very strange problem with an NGINX reverse proxy I was using: it was truncating static files at seemingly arbitrary places. To this day, I don't know what caused it.

On the plus side, a colleague of mine (thanks Mark!) pointed me towards an alternative I could test with: nghttp2.

To be clear: nghttp2 is not a complete NGINX replacement. It does, however, make for a stunningly easy HTTP/2 compliant reverse proxy alternative.

The nghttp2 project actually includes quite a few components: a client (nghttp), server (nghttpd) and a proxy (nghttpx). I'm only looking at the proxy today!

Previously, using NGINX as a reverse proxy required a slightly obtuse (but very powerful) config file and restarting the nginx server. Using nghttpx allows you to directly run the server on-demand, then easily swap it to a system service later.

Running the proxy

Once you've got it installed (packages are available in EPEL for RHEL/CentOS, or in the mainline repos for Fedora), you can run the proxy component directly with the nghttpx command. The syntax can be a little dizzying at first, but is super-easy to tweak and adjust. For example, here's the command my app ended up needing:

nghttpx -s -f'*,443' -b127.0.0.1,9442 /etc/ssl/cert.key /etc/ssl/cert.pem

That starts up a HTTP/2 proxy (-s) on port 443 (-f'*,443') proxying a local HTTP app on port 9442 (-b127.0.0.1,9442) using the cert and key from /etc/ssl. If your upstream is HTTPS-enabled, just change it up slightly:

nghttpx -s -f'*,443' -b'127.0.0.1,9442;;tls' /etc/ssl/cert.key /etc/ssl/cert.pem

The man page includes a lot of info on the various ways to use the -b/--backend option!

It also supports the same -k behaviour as curl if your upstream is using a self-signed cert.

Running as a service

To run it as a service, you'll want to use a config file. Like many other tools nghttpx uses a key-value config file that reflects the same options as the command line switches. Here's the above command as a config file:

frontend=0.0.0.0,443
backend=127.0.0.1,9443;/;tls
insecure=yes
private-key-file=/etc/ssl/cert.key
certificate-file=/etc/ssl/cert.pem

add-x-forwarded-for=yes
accesslog-file=/var/log/nghttpx/access.log
errorlog-file=/var/log/nghttpx/error.log

You may have to create the directories for your log files before starting the service.

Put that config file in the default location of /etc/nghttpx/nghttpx.conf and you're one easy command away from running proxy:

systemctl start nghttpx.service
# or for a start-at-boot server:
systemctl enable --now nghttpx.service

Seriously, if you need to use a reverse proxy for anything you're running (non-production-grade apps, containers, older servers etc), take a look at nghttp2: there's plenty of docs on GitHub and the man page is really detailed and easy to understand.


For anyone who doesn't realise: HTTP/2 is SSL/TLS-only so make sure you've got a cert before you try and jump on the new hotness!