HAProxy is an open source load balancer, capable of balancing any TCP based service. It’s commonly used for balancing HTTP, and can help solve traffic problems on your web server. Here’s how to set it up.
What Is HAProxy?
Load balancers like HAProxy allow you to split traffic over multiple servers, making it easier to handle. Instead of pointing your IP at your web server, you’d point it at an HAProxy server, which would decide where to send it from there. HAProxy is very lightweight, and doesn’t need a lot of resources to operate, so you can use a single load balancer for many backend servers. Ideally, you want both your HAProxy server and your web servers to be hosted in the same datacenter, from the same cloud provider, to cut down on latency.
HAProxy also allows your network to be more resilient. If one web server goes down, HAProxy can route traffic to the rest while you diagnose the issue. For it to be truly resilient, you’ll want to have a backup HAProxy server, in case your load balancer goes down.
Even with HAProxy, you’ll still often want a full site CDN in front of it, both to handle additional load and to have multiple points of presence closer to the end user.
How To Set Up HAProxy Load Balancing
First, install HAProxy from your distro’s package manager. For Debian based systems like Ubuntu, that would be:
apt-get install haproxy
Next, you’ll need to turn it on by editing the init script at
/etc/default/haproxy and setting
ENABLED to 1:
Now, if you run
service haproxy, you should see that it is enabled and ready to be configured. We’ll start by archiving the default configuration file:
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.old
Create a new config file in its place, and start by adding a few global settings:
global log 127.0.0.1 local0 notice maxconn 2000 user haproxy group haproxy stats enable stats uri /haproxy?stats stats realm HAProxy Statistics stats auth admin:password
log setting specifies the syslog server that HAProxy sends logs to. You’ll need to have a server like rsyslog running to make use of this. The
maxconn setting specifies the max concurrent connections, and
group specify which Unix user HAProxy operates as.
The last few lines turn on HAProxy’s built in statistics page, which you can view by navigating to the URI in your browser. In this case, that would be
http://your_ip/haproxy?stats, but you can view a demo of it here.
Next, we’ll set the default config that will apply to all
listen blocks if they don’t make any changes to it:
defaults log global mode http option httplog option dontlognull retries 3 option redispatch timeout connect 5000 timeout client 10000 timeout server 10000
We’re setting the default to use the global log setting, operate on HTTP, and set some settings related to connection timeouts.
We’ll create a
frontend block that will do the heavy lifting, and forward connections to the backend:
frontend proxy bind *:80 # ACL function declarations acl is_abuse src_http_req_rate(Abuse) ge 10 acl inc_abuse_cnt src_inc_gpc0(Abuse) gt 0 acl abuse_cnt src_get_gpc0(Abuse) gt 0 # Rules tcp-request connection track-sc0 src table Abuse tcp-request connection reject if abuse_cnt http-request deny if abuse_cnt http-request deny if is_abuse inc_abuse_cnt option httpclose option forwardfor use_backend appname
The first line binds this frontend to port 80, where HAProxy will listen on.
The next two sections are for rate limiting. First, the access control list (ACL) functions are declared, which determine if an IP address is abusive. Then, a set of rules will reject a connection if it’s making too many requests.
forwardfor option will forward the client’s IP address to the server. Since HAProxy acts as a reverse proxy, your nginx server would only see your HAProxy server’s IP address. This option sets the
X-Forwarded-For HTTP header to the client’s IP address.
And finally, we set this
frontend block to use the backend “appname,” which we’ll need to create. The
backend block simply defines the servers to forward to, along with a few options:
backend appname your_ip:80 balance roundrobin cookie SERVERNAME insert server web1 web1_ip:80 check cookie web1 server web2 web2_ip:80 check cookie web2
balance directive defines how HAProxy balances requests between servers. The most common option is
roundrobin, which will rotate connections through each server in order. If you run into issues with balance, you can try using the option
leastconn, which selects based on concurrent connections. If you need users to access the same server over multiple connections, you can use the
source option, which selects based on a hash of the client’s IP address.
The last two lines allocate servers to this
listen block. You give them a name (
web2) specify their addresses, and then list a few options. Here, we use the
check parameter to make sure the server is healthy and accepting connections, and the
cookie parameter to set the
SERVERNAME cookie (which we inserted directly above) to the name of the server, which is used for session stickiness (so the user doesn’t switch servers while using your site). The
balance source option achieves this same effect.
And because we’re using rate limiting, we’ll actually need another backend to store IP addresses:
backend Abuse stick-table type ip size 100K expire 30m store gpc0,http_req_rate(10s)
This doesn’t actually forward any connections; it functions as a table to store addresses in. Addresses are flushed after 30 minutes, so addresses deemed abusive will be blocked for 30 minutes.
Finally, you can start the HAProxy service by running:
service haproxy start