Recently we encountered a scenario where we needed to look for an alternative for Amazon Web Services (AWS) Elastic Load Balancing (ELB) due to an existing IIS configuration used in an organisation. We found that HAProxy was the best candidate in terms of simplicity & the suitability for scenario we were addressing.
This post will show you how you can leverage HAProxy to load balance IIS web servers hosted in AWS EC2 and explain briefly why HAProxy is best suited to address our scenario.
Consider you have two web servers you need to load balanced; each hosts several websites configured using multiple IP addresses. In this case, there is no need to handle SSL at the load balancer (LB) layer, the LB only passes through SSL requests to the backend servers.
Web server 1 hosts the following websites:
- KloudWeb port 80 with IIS binding to 192.168.137.31:80
- KloudWeb port 443 with IIS binding to 192.168.137.31:443
- KloudMetro port 80 with IIS binding to 192.168.137.15:80
- KloudMetro port 443 with IIS binding to 192.168.137.15:443
- Note: 192.168.137.31 is the primary interface IP address of web server 1.
Web server 2 hosts the following websites:
- KloudWeb port 80 with IIS binding to 192.168.137.187:80
- KloudWeb port 443 with IIS binding to 192.168.137.187:443
- KloudMetro port 80 binding to 192.168.137.107:80
- KloudMetro port 443 binding to 192.168.137.107:443
- Note: 192.168.137.187 is the primary interface IP address of web server 2.
Why Amazon Elastic Load Balancer is less ideal in this case?
ELB only delivers traffic and load balance the primary interface i.e. eth0. To make this scenario work with ELB, the IIS binding configuration needs to be amended to either the following:
- KloudWeb or KloudMetro will need to change ports other than port 80 or 443 for the HTTP and HTTPS respectively; or
- Use different host headers
Those alternatives could not be employed as we needed to migrate environments as-is. Given this, replacing ELB is the most viable option to support the scenario. Note: There are merits for binding different IPs for different sites, however a similar goal can be achieved with a single IP address by assigning custom ports on the binding settings in IIS – host headers. Further details on the pros and cons on both approaches can be found here.
HAProxy is a very popular choice for replacing ELB in many AWS scenarios. It provides both the features of L4 & L7 traditional load balancers and a flexibility that is rarely found in a software based load balancer. We also assessed alternatives such as LVS or NGINX – both of which are free for use, but decided to go ahead with HAProxy since it supports SSL pass-through using its tcp port forwarder feature and the simplicity it provides.
One thing to note: at the time of writing, HAProxy stable release 1.4 does not support SSL termination at the load balancer (there are 3rd party tools that can support them e.g. bundled with nginx). The newest version (in dev) now supports SSL offload capability therefore eliminating the need to install any components outside HAProxy to handle SSL.
The Preparation Steps
To prepare, we need the following info:
- The Load Balancer “VIP” addresses
- Backend addresses (since you need to bind the VIP addresses to the different backend addresses)
- LB listener ports and backend server ports
Let’s get hands on
First of all, you may be surprised by how simple it is to configure HAProxy on AWS. Key thing is to understand what goal or scenario you would like to achieve and (once again), the preparation to collect relevant information.
- We have chosen to use the ‘vanilla’ Amazon Linux AMI in Sydney. Spin this instance up on the UI or command line
- Assigned two IP addresses for this HAProxy instance to host the two websites
- Created a security group which only allows SSH (port 22) and Web connections (port 80 & 443). You can also separate them to limit SSH connection from certain addresses for an additional security
- Connect to your newly created instance (via Putty or the built-in AWS Java console)
Configure your HAProxy
- Make sure you have changed as root or an account with a sudo right
- Install haproxy – yum install haproxy
- Once it is installed, browse to the /etc/haproxy directory and review the haproxy.cfg file
- Backup the haproxy.cfg file – cp haproxy.cfg haproxy.cfg.backup
- Modify the original file with the following configuration – vi haproxy.cfg
# Global settings
# to have these messages end up in /var/log/haproxy.log you will
# need to:
# 1) configure syslog to accept network log events. This is done
# by adding the ‘-r’ option to the SYSLOGD_OPTIONS in
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# local2.* /var/log/haproxy.log
log 127.0.0.1 local2
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
# common defaults that all the ‘listen’ and ‘backend’ sections will
# use if not designated in their block
option forwardfor except 127.0.0.0/8
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
# KloudWeb & KloudMetro Web Servers
stats auth admin:apassword
option httpchk /kloudlb/test.aspx
server webserver1 192.168.137.31:80
server webserver2 192.168.137.187:80
server webserver1 192.168.137.31:443
server webserver1 192.168.137.187:443
stats auth admin:apassword
option httpchk /kloudlb/test.aspx
server webserver1 192.168.137.15:80
server webserver2 192.168.137.107:80
server webserver1 192.168.137.15:443
server webserver1 192.168.137.107:443
Once you have modified the file, run HAProxy to test its functionality
- On a SSH console, enter – service haproxy start
- HAProxy will verify the configuration and start the service
- From this point you can see the built-in dashboard of your new HAProxy configuration by going to the link below
- Hit or access your website (with IP or DNS)
- Any new requests will update the stats shown here in real time (see kloudmetrohttp for updated stats)
The HAProxy Configuration explained
Apart from the default configuration, this section briefly details the configuration file we used above. See the following documentation for more info. There are ways you can leverage the vast features of HAProxy such as performing advanced health checks based on regular expression and modifying polling time which are beyond the scope of this blog post.
# listen <name> -- this specifies Haproxy listener group, you can define a logical name for your servers # bind <IP addr of LB>:<LB listener port> -- The binding IP address & port # mode <http or tcp> -- this is set to http (L7 load balancing) or TCP (L4 load balancing) # stats enable -- Enable the Haproxy stats # stats auth admin:<anypassword> -- Set the username and password for accessing the site # balance roundrobin -- this sets the algorithm used for load balancing requests. # option httpchk <uri> -- this configuration will perform an optional health check to put the listener in or out of service # server <name> <server ip addr>:<server port> check port <server port> -- this sets the backend servers which will be load balanced.