Wednesday, June 3, 2015

Hiding Services Behind HAProxy

This is an update to the article here, on hiding services behind Apache.

With the latest version of Open Media Vault, the default web server has been changed from Apache to Nginx.  This means that if you want to follow my guide on hiding services behind Apache, you'll need to install and run a dedicated instance of Apache web server.  IMHO, this seems like overkill.  Alternatively, you could use Nginx to redirect traffic to your various applications.  Do a quick Google search, and you'll find a few guides on how to redirect traffic to Sickbeard, Couchpotato, and probably a few other applications.  But personally, I decided to take the opportunity to re-think my approach to this, and try something different.


HAProxy is a piece of software designed to perform load-balancing and proxying.  It has a couple of neat features.  It's small, lightweight and very efficient.  And unlike Apache (or Nginx), HAProxy is not just limited to redirecting HTTP traffic, but also works with other protocols in the TCP stack.

My needs are generally pretty simple, though.  I just want HAProxy to redirect traffic from port 80, to various ports, based on the URL path.  The extra features in HAProxy are a bonus really, the main thing I want is something lightweight.

Installation and Configuration

On Debian (and probably Debian-based distributions), you can install HAProxy via apt-get.  The installation process should install the HAProxy software, as well as create a configuration directory with a default config file (in /etc/haproxy) and create an init script for starting and stopping the HAProxy service (/etc/init.d/haproxy).  As a starting point, I recommend taking a backup of the default configuration script.

Now let's start playing with possible configurations...

There are two parts we are interested in... the frontend, and the backend.
The frontend is where HAProxy is given instructions on traffic to listen for, and where to direct that traffic.  Here's the frontend instructions in my HAProxy configuration file;

frontend public :80
        mode http
        option forwardfor
        option http-server-close
        option http-pretend-keepalive
        acl is_sab path_beg /sabnzbd
        use_backend sabnzbd if is_sab

This config is basically telling HAProxy to listen for public HTTP traffic, incoming via port 80.  Seems pretty straight forward, but what does it do with that traffic?  Well, the config also includes an acl instruction (short for access control list), called "is_sab" which is looking for any incoming traffic that has a URL path that begins with /sabnzbd.  The second instruction says that if HAProxy finds traffic that meets this criteria, it should be forwarded to the backend called "sabnzbd".

At this stage, though, we haven't specified any details about this backend, so we need to add a new configuration entry;

backend sabnzbd
        option httpclose
        option forwardfor
        server sab localhost:8080/sabnzbd

This config specifies a new backend, called "sabnzbd", which references a server called "sab", which is located at localhost:8080/sabnzbd.  Note that the backend does not need to be the localhost, but could be another machine on whatever port.  In our case, though, sabnzbd runs locally and listens to port 8080.

Adding Services

If you are running more services than just SABnzbd, you'll want to add multiple entries to the HAProxy configuration.  Since we have already configured a frontend, we just need to add additional entries for each service.  For example;

frontend public :80
        mode http
        option forwardfor
        option http-server-close
        option http-pretend-keepalive
        acl is_sab path_beg /sabnzbd
        use_backend sabnzbd if is_sab

        acl is_sickbeard path_beg /sickbeard
        use_backend sickbeard if is_sickbeard
        default_backend omv

So this expanded config now includes instructions for listening to port 80, and checking for traffic with a url that begins with /sickbeard.  I've also included a "default_backend" command, which directs traffic through to a backend called "omv" when it doesn't match any of the acl criteria.  Since I'm redirecting traffic to a backend called "sickbeard", I'd better create an entry for it;

backend sickbeard
        option httpclose
        option forwardfor
        server sb localhost:8081/sickbeard

Like the SABnzbd entry, this basically redirects traffic from /sickbeard to the server localhost:8081/sickbeard.

Furthermore, since I created an entry to redirect traffic through to a backend called "omv", I'll need to create an entry for that backend;

backend omv
        timeout server 30s
        server omv localhost:7000

Note that since HAProxy is now listening to port 80, I've shifted the Open Media Vault web console to now listen on port 7000.  And any traffic that doesn't match my list of acl entries will, by default, be directed to the OMV console at localhost:7000.

This is just an example of some configuration options.  HAProxy has got a really comprehensive configuration manual, but it can be a bit overwhelming and there are often multiple ways to do the same tasks.

Kicking Things Off

Once you're happy with your HAProx configuration, you'll need to restart the service by issuing the command;

service haproxy restart

 Any time you make a config change, you'll need to restart the haproxy service in order for it to re-read the new configurations.


A couple of things I forgot to add.

Firstly, if you are using these instructions for Open Media Vault, then you'll need to change the settings so that the OMV web interface doesn't listen to port 80 (and therefore, conflict with HAProxy).  This is found under System->General Settings.

Secondly, if you want to access services from outside your network, you'll need to configure your modem/router.  Typically, this involves "port forwarding" any traffic from port 80 to the internal network address of your server -- typically something like 192.168.1.XX or something similar.

1 comment:

  1. Thanks for the info. I have a similar setup but using server name indication for SSL sites (RD Gateway, OMV, Fw Console, with Startssl certs) and this function performed by nginx, since I didn't know how to do it. Will try to integrate everything at the haproxy level. Thanks!