How to Set Up an HAProxy Load Balancer

0
272

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:

ENABLED=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

The 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 user 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.

The 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

The 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 (web1 and 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