19 February 2018

TLS Load Balancing the JSON RPC Interface of Monero Without Wrecking Authentication

One of the key elements of Ablative Hosting is that it will primarily use cryptocurrencies so it can't have it's funding sources pulled as happened to FetLife.

Bitcoin transactions are entirely public, ZCash has issues when moving funds between shielded and normal addresses so for the customer who demands the utmost privacy the obvious choice is Monero. When I first set about implementing support for generating Monero addresses (and monitoring transactions to the that address) I had standardised on using nginx to reverse proxy connections to various daemons.

Using nginx has various advantages including the ability to set HTTP headers (such as HSTS), work with LetsEncrypt and could be restarted easily when new nodes were added or the LetsEncrypt certificates changed without risking a delay to the APIs (e.g. checking / validating the blockchain on restart).

Unfortunately the Monero daemon uses digest authentication and it appeared that Nginx would consume the digest before proxying the request which resulted in failed authentication attempts.

Thankfully HAProxy is a brilliant tool for handling load balancing and SSL terminated proxying, in HTTP mode the same behaviour was seen but HAProxy can also work in plain TCP mode and this works fine!

# Monero frontend
frontend  main
    bind :10010 ssl crt /etc/haproxy/monero_balancer.pem
    mode tcp

    default_backend             monero_full_node

# Monero backend(s)
backend monero_full_node
    mode tcp
    balance     roundrobin
    option httpchk get /json_rpc
    http-check expect rstatus (2|3|4)[0-9][0-9]
    server  app1 yy.yy.yy.yy:8990 check
    server  app2 xx.xx.xx.xx:8990 check

So, if you're looking at fronting the JSON RPC interface of one or more of your Monero nodes and are having problems with digest authentication give HAProxy (or OpenBSD's relayd!) a try.