Nathan Evans' Nemesis of the Moment

Deploying HA-Proxy + Keepalived with Mercurial for distributed config

Posted in Automation, Source Control, Unix Environment by Nathan B. Evans on February 27, 2011

Something I have learnt (and re-learnt) too many times to count is that one of the strange wonders of working for a startup company is that the most bizarre tasks can land on your lap seemingly with no warning.

We’ve recently been doing a big revamp of our data centre environment, including two shiny new Hyper-V hosts, a Sonicwall firewall and the decommissioning of lots of legacy hardware that doesn’t support virtualisation. As part of all this work we needed to put in place several capabilities for routing application requests on our SaaS platform:

  1. Expose HTTP/80 and HTTPS/443 endpoints on the public web and route incoming requests based upon URL to specific (and possibly many) private internal servers.
  2. Expose a separate and “special” TCP 443 endpoint (on public web) that isn’t really HTTPS at all but will be used for tunnelling of our TCP application protocol. We intend to use this when we acquire pilot programme customers that don’t want the “hassle” of modifying anything on their network firewalls/proxies. Yes, really. Even worse, it will inspect the source IP address and, from that, determine what customer it is and then route it to the appropriate private internal server and port number.
  3. Expose various other TCP ports on public web and map these (in as traditional “port map” style as possible) directly to one specific private internal server.
  4. Be easy to change the configuration and be scriptable, so we can tick off the “continuous deployment” check box.
  5. Configuration changes must never tamper with existing connections.
  6. Optional bonus, be source controllable.

My first suggestion was that we would write some PowerShell scripts to access the Sonicwall firewall through SSH and control its firewall tables directly. This was the plan for several months in fact, whilst everything was getting put in place inside the data centre. I knew full well it wouldn’t be easy. First there was some political issues inside the company with regard to a developer (me) having access to a central firewall. Second, I knew that creation and testing of the scripts would be difficult and that the whole CLI on the Sonicwall would surely not be as good as a Cisco.

I knew I could achieve #1 and #3 easily on a Sonicwall, like with any router really. But #2 was a little bit of an unknown as, frankly, I doubted if a Sonicwall could do it without jumping through a ton of usability hoops. #4 and #6 were the greatest unknown. I know you can export a Sonicwall’s configuration from the web interface. But it comes down as a binary file; which sort of made me doubt whether the CLI could do it properly as some form of text file. And of course if you can’t get the configuration as a text file then it’s not really going to be truly source controllable either, so that’s #6 out.

Fortunately an alternative (and better!) solution presented itself in the form of HA-Proxy. I’ve been hearing more and more positive things about this over the past couple years: most notably from the Stack Exchange. And having recently finally shed my long-time slight phobia of Linux, I decided to have a go at setting it up this weekend on a virtual machine.

The only downside was that as soon as you move some of your routing decisions away from your core firewall then you start to get a bit worrisome about server failure. So naturally we had to ensure that whatever we came up with involving HA-Proxy can be deployed as a clustered master-master or master-slave style solution. That would mean that if our VM host “A” had a failure then Mr Backup over there, “B”, could immediately take up the load.

It seems that Stack Exchange chose to use the Linux-HA Heartbeat system for providing their master-slave cluster behaviour. In the end we opted for Keepalived instead. It is more or less the same thing except that it’s apparently more geared towards load balancers and proxies such as HA-Proxy. Whereas Heartbeat is designed more for situations where you only ever want one active server (i.e. master-slave(s)). Keepalived just seems more flexible in the event that we decide to switch to a master-master style cluster in the future.

HA-Proxy Configuration

Here’s the basic /etc/haproxy/haproxy.conf that I came up with to meet requirements #1, #2 and #3.

# Global settings for HA-Proxy.
	maxconn 8192

# Default settings for all sections, unless overridden.
	mode http

	# Known-good TCP timeouts.
	timeout connect 5000ms
	timeout client 20000ms
	timeout server 20000ms

	# Prevents zombie connections hanging around holding resources.
	option nolinger

# Host HA-Proxy's web stats on Port 81.
listen HAProxy-Statistics *:81
	mode http
	stats enable
	stats uri /haproxy?stats
	stats refresh 20s
	stats show-node
	stats show-legends
	stats auth admin:letmein

# Front-ends
	# Public HTTP/80 endpoint.
	frontend Public-HTTP
		mode http
		bind *:80
		default_backend Web-Farm

	# Public HTTPS/443 endpoint.
	frontend Public-HTTPS
		mode tcp
		default_backend Web-Farm-SSL

	# A "fake" HTTPS endpoint that is used for tunnelling some customers based on the source IP address.
	# Note: At no point is this a true TLS/SSL connection!
	# Note 2: This only works if the customer network allows TCP 443 outbound without passing through an internal proxy (... which most of ours do).
	frontend Public-AppTunnel
		mode tcp

		# Bind to a different interface so as not to conflict with Public-HTTPS (above).

		# Pilot Customer 2 (testing)
		acl IsFrom_PilotCustomer2 src
		use_backend App-PilotCustomer2 if IsFrom_PilotCustomer2

# Back-ends
# General
	# IIS 7.5 web servers.
	backend Web-Farm
		mode http
		balance roundrobin
		option httpchk
		server Web0 check
		server Web1 check

	# IIS 7.5 web servers, that expose HTTPS/443.
	# Note: This is probably not the best way, but it works for now. Need to investigate using the stunnel solution.
	backend Web-Farm-SSL
		mode tcp
		balance roundrobin
		server Web0 check
		server Web1 check

# Back-ends
# Application Servers (TCP bespoke protocol)
	# Customer 1
	listen App-Customer1
		mode tcp
		bind *:35007
		server AppLive0 check

	# Pilot Customer 2 (testing)
	listen App-PilotCustomer2
		mode tcp
		bind *:35096
		server AppLive0 check

I doubt the file will remain this small for long. It’ll probably be 15x bigger in a week or two 🙂

Keepalived Configuration

And here’s the /etc/keepalived/keepalived.conf file.

vrrp_instance_VI_1 {
	state MASTER
	interface seth0
	virtual_router_id 51
	! this priority (below) should be higher on the master server, than on the slave.
	! a bit of a pain as it makes Mercurial'ising this config more difficult - anyone know a solution?
	priority 200
	advert_int 1
	authentication {
		auth_type PASS
		auth_pass some_secure_password_goes_here
	virtual_ipaddress {

It is rather straight forward as far as other Keepalived configurations go. It is effectively no different to a Windows Server Network Load Balancing (NLB) deployment, with the right options to give the master-slave behaviour. Note the only reason I’ve specified two virtual IP addresses is because I need to use the TCP port 443 twice (for different purposes). These will be port mapped on the Sonicwall to different public IP addresses, of course.

Mercurial, auto-propagation script for haproxy.conf

cd /etc/haproxy/

# Check whether remote repo contains new changesets.
# Otherwise we have no work to do and can abort.
if hg incoming; then
  echo "The HA-Proxy remote repo contains new changesets. Pulling changesets..."
  hg pull

  # Update to the working directory to latest revision.
  echo "Updating HA-Proxy configuration to latest revision..."
  hg update -C

  # Re-initialize the HA-Proxy by informing the running instance
  # to close its listen sockets and then load a new instance to
  # recapture those sockets. This ensures that no active
  # connections are dropped like a full restart would cause.
  echo "Reloading HA-Proxy with new configuration..."
  /etc/init.d/haproxy reload

  echo "The HA-Proxy local repo is already up to date."

I turned the whole /etc/haproxy/ directory into a Mercurial repository. The script above was also included in this directory (to gain free version control!), called I cloned this repository onto our central Mercurial master server.

It is then just a case of setting up a basic “* * * * * /etc/haproxy/” cronjob so that the script above gets executed every minute (don’t worry it’s not exactly going to generate much load).

This is very cool because we can use the slave HA-Proxy server as a sort of testing ground of sorts. We can modify the config on that server quite a lot and test against it (by connecting directly to it’s IP rather than the clustered/virtual IP provided by Keepalived). Then once we’ve got the config just right we can commit it to the Mercurial repository and then push the changeset(s) to the master server. Within 60 seconds then the other server (or servers, in your case possibly!) will then run the synchronisation script.

One very neat thing about the newer versions of HA-Proxy (I deployed version 1.4.11) is that they have an /etc/init.d script that already includes everything you need for doing configuration file rebinds/reloads. This is great because what actually happens is that HA-Proxy will send a special signal to the old process so that it stops listening on the front-end sockets. Then it will attempt to start the new instance based upon the new configuration. If this fails it will send another signal to the “old”, but now resurrected process, that it can resume listening. Otherwise the old process will eventually exit once all its existing client connections have ended. This is brilliant because it meets and rather elegantly exceeds exceeds our expectations for requirement #5.

The fact that our HA-Proxy’s will contain far more meticulous configuration details than even our Sonicwall, I think that this solution based upon Mercurial is simply brilliant. We have what is effectively a test and slave server all-in-one, and a hg revert or hg rollback command is of course only a click away.

It’s still a work in progress but so far I’m very pleased with the progress with HA-Proxy.


14 Responses

Subscribe to comments with RSS.

  1. […] is sort of a follow-up to the Deploying HA-Proxy + Keepalived with Mercurial for distributed config […]

  2. Mike said, on September 23, 2012 at 5:47 PM

    I’ve just started experimenting with HAProxy for some request and response rewriting, and this post has proved most useful. Thank you.

  3. dexion racking said, on November 28, 2012 at 8:20 PM

    Pretty section of content. I just stumbled upon your site and in accession capital to assert that I get in fact enjoyed
    account your blog posts. Anyway I’ll be subscribing to your feeds and even I achievement you access consistently fast.

  4. terafirma said, on December 11, 2012 at 1:50 AM

    You can also go one better with HAproxy 1.5 how allows the tables to be syn’d between peers using the peers function that way when you fail-over or reload users are always redirected to the same server and don’t notice any outage at all.

  5. said, on January 6, 2013 at 5:36 AM

    hello there and thank you for your information – I’ve definitely picked up anything new from right here. I did however expertise several technical points using this website, since I experienced to reload the site many times previous to I could get it to load properly. I had been wondering if your web host is OK? Not that I am complaining, but sluggish loading instances times will very frequently affect your placement in google and could damage your high-quality score if advertising and marketing with Adwords. Well I am adding this RSS to my email and can look out for a lot more of your respective interesting content. Make sure you update this again very soon.

  6. Randell said, on February 2, 2013 at 5:17 AM

    hey there and thank you for your information – I have definitely picked
    up anything new from right here. I did however expertise some
    technical points using this web site, since I
    experienced to reload the web site lots of times previous to I could get it to load properly.

    I had been wondering if your web host is OK?
    Not that I am complaining, but sluggish loading instances times will very frequently affect your placement
    in google and could damage your high quality score if advertising and marketing with Adwords.
    Well I’m adding this RSS to my email and can look out for much more of your respective interesting content. Make sure you update this again soon.

  7. Chaitali Varughese said, on February 2, 2013 at 4:50 PM

    Hmm it seems like your site ate my first comment (it was super long)
    so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog.
    I too am an aspiring blog writer but I’m still new to the whole thing. Do you have any points for newbie blog writers? I’d really appreciate it.

  8. Students Visitors said, on February 28, 2013 at 4:48 PM

    Nice post. I was checking constantly this blog and I am
    impressed! Extremely useful information specifically the last part :
    ) I care for such info a lot. I was looking for this certain information for
    a very long time. Thank you and best of luck.

  9. Immigration Solicitors in Rochester said, on February 28, 2013 at 4:59 PM

    I am regular visitor, how are you everybody? This article posted at
    this web page is actually pleasant.

  10. Immigration Advice in Havering said, on February 28, 2013 at 5:00 PM

    Hi all, here every person is sharing these experience, therefore it’s good to read this blog, and I used to go to see this website every day.

  11. Immigration Solicitors in Barking said, on March 7, 2013 at 7:11 PM

    Hola! I’ve been reading your weblog for a while now and finally got the courage to go ahead and give you a shout out from Humble Tx! Just wanted to say keep up the good work!

  12. Immigration Advicers maidstone said, on March 13, 2013 at 2:37 PM

    Simply want to say your article is as surprising.
    The clarity to your submit is simply cool and that i could suppose you’re knowledgeable on this subject. Well together with your permission let me to clutch your RSS feed to keep updated with approaching post. Thanks 1,000,000 and please keep up the gratifying work.

  13. […] Mercurial (for haproxy.cfg synchronization).  Nathan Evans has a great post on doing this here:….  Andy Leonard also has some tips for getting HAProxy and keepalived working here: […]

  14. click here all my faves why search said, on September 24, 2013 at 12:31 AM

    The truth is, at times, men do not have enough testosterone.

    It’s a cost-effective way to market yourself and your business.
    You are going to notice that you’ll be able to pick out a flower girls
    dress that will match up with the other ladies who
    will be in the wedding party.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: