Setting Up a Load Balancer With HAProxy

Danuka Praneeth
5 min readJan 3, 2022

--

This article will cover few important things to be considered when using HAProxy as a load balancer with the sample configurations for each of these points.

1) Handling TCP Requests

HAProxy is able to handle both TCP and HTTP API traffic. Below is a basic LB configuration to redirect the traffic reaching the LB via port xxx to three of the available backend systems.

frontend tcp_listner
bind *:48453
mode tcp
default_backend tcp_backend_48453
backend tcp_backend_48453
balance roundrobin
mode tcp
server infra-node1 172.226.120.33:30453 check
server infra-node2 172.226.120.34:30453 check

The section defined as frontend is the inbound condition for the API requests reaching the LB. So HAProxy is listening in port number 48453 for TCP requests. Here you can see there are no SSL configurations to the TCP listeners. So this behave as a SSL Passthrough connection which means any SSL validations will happen only at the target backend.

The section defined under backend contain the details on the target endpoints to which the API request get redirected. The requests will get redirected in roundrobin approach.

2) Handling HTTP Requests

Similar to the above example, HAProxy is able to handle API requests via the HTTP protocol. In this method, you need to configure your inbound connection using either of the below three modes.

HTTP Interface

This is a basic and unsecure way of exposing inbound connections. It does not any encryption for the data reaching the LB. This will be useful to support the integration of certain legacy systems.

frontend http_insecure_passthrough
bind *:8080
mode tcp
default_backend insecure_passthrough_backend
backend insecure_passthrough_backend
balance roundrobin
mode tcp
server infra-node1 172.226.121.33:32080 check
server infra-node1 172.226.121.33:32080 check

This configuration is similar to the previous configuration to handle the TCP requests. But if you notice carefully, the backend port for the redirected request is different. In my example, the backend application running in port 32080 is a HTTP endpoint.

HTTPS Interface with SSL Termination at the LB

This is a more secure approach to configure the load balancers with end to end encryption for all the incoming API requests. Here we are need to have a SSL certificate to enforce the encryption with a desired TLS version.

frontend http_secure
bind *:443 ssl crt /etc/ssl/mynwk.com/mynwk.pem force-tlsv12
mode http
option http-server-close
option forwardfor except 127.0.0.0/8
option httplog
acl has_api path_beg /api
use_backend secure_api_backend if has_api
default_backend secure_backend
backend secure_api_backend
balance roundrobin
mode http
server infra-node1 172.226.122.33:32444 check ssl verify none
server infra-node1 172.226.122.34:32444 check ssl verify none
backend secure_backend
balance roundrobin
mode http
server infra-node3 172.226.122.35:32443 check ssl verify none
server infra-node4 172.226.122.36:32443 check ssl verify none

Here you will notice that the SSL configurations are enforced to the port 443. These SSL/TLS configs include the path to the location of the SSL certificate and the TLS version.

Also you can see now we are redirecting the request to two backend groups based on the API context path in the incoming requests.

You should also notice an additional configuration in the above rule ‘option forwardfor except 127.0.0.0/8’. This configuration will help us to include the source IP in the redirect API request header. Otherwise, the IP address of the LB will get included as the source IP in the redirect API request.

HTTPS Interface with SSL Passthrough at the LB

Configuring this is similar to the above HTTP Interface. HAProxy is not handling any SSL/TLS validations. Instead, it simply redirect everything to the HTTPS secure backend running in port 32443 which handle all the SSL/TLS validations.

frontend http_secure_passthrough
bind *:8443
mode tcp
default_backend passthrough_backend
backend passthrough_backend
balance roundrobin
mode tcp
server infra-node1 172.226.123.33:32443 check
server infra-node1 172.226.123.33:32443 check

3) Configuring Logs for HAProxy

  1. Uncomment the below line in the file /etc/haproxy/haproxy.cfg
log 127.0.0.1 local2

2) Restart the HAProxy service:

systemctl restart haproxy.service

3) Edit rsyslog configuration file to receive haproxy logs by creating a new file within /etc/rsyslog.d/ directory, like /etc/rsyslog.d/haproxy.conf

# Collect log with UDP
$ModLoad imudp
$UDPServerAddress 127.0.0.1
$UDPServerRun 514

# Creating separate log files based on the severity
local2.* /var/log/haproxy-traffic.log
local2.notice /var/log/haproxy-admin.log

4) Restart the rsyslog service:

systemctl restart rsyslog.service

5) Trigger some API requests and check access logs to the haproxy in the file:

/var/log/haproxy-traffic.log
/var/log/haproxy-admin.log

6) Creating the log rotation file in /etc/logrotate.d directory:

To rotate and compress the haproxy log file, we can use logrotate service. Now create the log rotation file in /etc/logrotate.d directory:

$ cat /etc/logrotate.d/haproxy

/var/log/haproxy-traffic.log {
daily
rotate 10
missingok
notifempty
compress
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
/bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}

4) URL Rewrite in HAProxy

I will discuss the URL rewiring scenarios in HAProxy using two available functions.

1) set-path

frontend secure_https_5443
bind *:443
mode http

acl has_old_api path_beg /old_api/ws
http-request set-path /new_api/https-ws if has_old_api
acl has_abc path_beg /abc
http-request set-path /new_endpoint/xyz/%[path] if has_abc

The above section contain two inbound rules. First rule will help you achieve below url rewrite scenarios.

https://mynwk.com/old_api/ws >> https://mynwk.com/new_api/https-wshttps://mynwk.com/old_api/ws/xxx?key=value >> https://mynwk.com/new_api/https-ws

Second rule will help you achieve below URL rewrite scenarios.

https://mynwk.com/abc >> https://mynwk.com/new_endpoint/xyz/abchttps://mynwk.com/abc/xxx?key=value >> https://mynwk.com/new_endpoint/xyzn/abc/xxx?key=value

2) set-path with regsub

frontend secure_https_5443
bind *:443
mode http
acl has_abc path_beg /abc
http-request set-path %[path,regsub(^/abc/,/new_api/xyz/)] if has_abc

The above rule will help you achieve below url rewrite scenarios.

https://mynwk.com/abc >> https://mynwk.com/new_api/xyz/https://mynwk.com/abc/xxx?key=value >> https://mynwk.com/new_api/xyz/xxx?key=value

Thank You!

--

--

Danuka Praneeth

Senior Software Engineer | BSc (Hons) Engineering | CIMA | Autodidact | Knowledge-Seeker