HAProxy - small but handy
HAProxy is open source software that is most often used as a reverse proxy to ensure load balancing and high availability of application servers.
Instead of connecting directly to the servers of an application, clients (e.g. of a browser) do it from a reverse proxy, which uses additional rules to pass the requests to the application servers and send the responses back to the client.
The project has been actively developed since 2002 and has seen increased popularity due to the proliferation of distributed systems, in particular architectures based on microservices. It is in use by such household names as Digital Ocean, GitHub, Dropbox, Instagram or StackOverflow. It is also a component of the OpenShift containerization platform.
The software is available for all popular Linux distributions, also as a Docker image.
Typical usages of HAProxy
Ensuring load balancing
One of the basic usages of HAProxy is as a software load balancer. With several nodes in an application, the traffic between them needs to be managed. To do that you need to declare an object called backend in the HAProxy configuration, which will represent a cluster of the application servers. Next, you need to declare an object called frontend, to which clients will be directed and frontend-to-backend traffic rules:
frontend my-load-balancer
bind 172.19.0.1:81
default_backend my-application-servers
backend my-application-servers
balance roundrobin
server my-app-server-1 172.19.0.2:8080
server my-app-server-2 172.19.0.3:8080
server my-app-server-3 172.19.0.4:8080
As a result of the above configuration, the connection on endpoint 172.19.0.1:81 will be redirected to one of the servers on a round-robin basis.
Ensuring High Availability
HAProxy can monitor the state of the servers declared in the backend section and halt directing traffic to the servers that have stopped working correctly. The server can be configured to determine how often HAProxy is supposed to check the server’s status, how many times the verification has to fail in order for the server to be considered faulty, and how many times the verification has to succeed for the excluded server to be regarded as healthy again. For example:
server my-app-server-1 172.19.0.2:8080 check inter 5s fall 3 downinter 1m raise 5
means that:
- server status will be checked every 5 seconds (inter 5s),
- server will be excluded if three consecutive verifications fail (fall 3),
- excluded server will be checked every minute (downinter 1m),
- server will be considered operational again if three consecutive verifications are successful (raise 5).
TLS/SSL
For managing encrypted TLS/SSL connections, HAProxy can work in one of the following modes:
- regular proxy
- terminating encryption
- encrypting traffic again
Regular proxy
In this mode, HAProxy simply passes the stream of bytes from the frontend to the backend, disregarding the fact that the traffic is encrypted.
Terminating encryption
In this mode, HAProxy receives encrypted traffic from the frontend, decrypts it using a private key and passes the decrypted traffic to the backend. An example configuration:
frontend my-terminating-load-balancer
bind 172.19.0.1:443 ssl crt /etc/ssl/certs/my-certs.pem
default_backend my-application-servers
backend my-application-servers
balance roundrobin
server my-app-server-1 172.19.0.2:8080
server my-app-server-2 172.19.0.3:8080
Encrypting traffic again
In this mode, HAProxy receives encrypted traffic from the frontend, decrypts it using a private key, and then encrypts it again and passes it to the backend. An example configuration:
frontend my-terminating-load-balancer
bind 172.19.0.1:443 ssl crt /etc/ssl/certs/my-certs.pem
default_backend my-secure-application-servers
backend my-secure-application-servers
balance roundrobin
server my-secure-app-server-1 172.19.0.2:8443 ssl
server my-secure-app-server-2 172.19.0.3:8443 ssl
As a result of decryption, in this mode HAProxy can manipulate the HTTP requests that it redirects, unlike in the regular proxy mode.
Session affinity
HAProxy can be configured so that the requests from a given user will always be directed to the same application server. The need for this occurs, e.g. when you are using local user sessions that exist only on the application server which they were created on. An example configuration that is based on a session cookie prefix:
frontend my-sticky-load-balancer
bind 172.19.0.1:81
default_backend my-application-servers
backend my-application-servers
cookie JSESSIONID prefix nocache
server my-app-server-1 172.19.0.2:8080 cookie node1
server my-app-server-2 172.19.0.3:8080 cookie node2
With this configuration, all requests that carry a session cookie with the “node1” prefix will be directed to the first application server.
ACL
HAProxy enables the user to configure rules (ACL - Access Control List) which determine how particular requests are supposed to be handled. An example configuration:
frontend my-acl-load-balancer
bind 172.19.0.1:81
acl is-passive method GET
use_backend my-passive-application-server if is-passive
default_backend my-active-application-server
backend my-passive-application-server
server my-passive-app-server-1 172.19.0.2:8080
backend my-active-application-server
server my-active-app-server-1 172.19.0.3:8080
With this configuration, GET requests will be directed to a passive application server, whereas all other requests will be directed to an active one.
A useful tool in your programming toolbox
Besides the traditional use case as a reverse proxy that ensures load balancing and high availability, HAProxy can be used to great effect in a range of programming scenarios. Let me present some examples from my own experience.
Easily changeable routing
While developing an application that calls services from different applications, you might want to be able to switch between various addresses of those external services, e.g. between real applications and their mock versions. Restarting an application is often time-consuming, while changing the IP address to external services requires editing more than one file. In this case, HAProxy may act as a convenient “hub”, in which you can easily switch between various versions of the external services. By configuring HAProxy as follows:
frontend my-forward-proxy
bind 172.19.0.1:81
default_backend my-external-services
backend my-external-services
server my-external-server-1 172.19.0.2:8080
backend my-mocked-services
server my-mocked-server-1 172.19.0.3:8080
and setting the address of external services in your application to 172.19.0.1:81, you can modify its external dependencies by changing the “default_backend” value and a quick reload of HAProxy, without the need to restart the application.
Monitoring TLS/SSL
If the services in your system send data through encrypted TLS/SSL connections, debugging communication using network traffic analyzers such as tcpdump or Wireshark might be difficult. However, you can set HAProxy as a proxy between the services that will terminate an encrypted connection and will allow you to monitor the network traffic.
Delaying requests
While developing an application you might sometimes need to test how it will behave if calling an external service is processed for a longer time than expected. You can simulate this kind of delay with HAProxy acting as the proxy to external services. HAProxy itself does not have this capability but it enables you to extend its functionalities with Lua scripts. An example script introducing a delay:
function delay_request(txn)
core.msleep(15000)
end
core.register_action("delay_request", { "http-req" }, delay_request);
Loading the script to HAProxy:
lua-load /etc/haproxy/delay.lua
and usage in the configuration:
frontend my-delay-frontend
bind 172.19.0.1:81
mode http
http-request lua.delay_request
default_backend my-delay-backend
backend my-delay-backend
server my-external-server-1 172.19.0.2:8080
A simple static content server
Interestingly, you can use HAProxy as a simple server for static files. For every backend, you can configure the files that are supposed to be served in the case of particular HTTP statuses. On the other hand, when no server has been defined in the backend’s configuration, HAProxy generates HTTP status 503. By combining these two facts, you can configure the frontend to return a static file for particular requests:
frontend my-frontend
bind 172.19.0.1:81
mode http
use_backend my-backend-static if { path_end /index.html }
default_backend my-backend-services
backend my-backend-static
mode http
errorfile 503 /etc/haproxy/index.html
backend my-backend-services
server my-external-server-1 172.19.0.2:8080
Connecting to a session
As a developer you might need to connect with a browser to a user session on a server using the session’s ID. Modern desktop browsers usually allow you to manually add a session cookie to a website’s cookie set. But what if you need to serve less popular or mobile browsers? HAProxy may come in handy in this situation as well:
frontend my-setcookie-frontend
bind 172.19.0.1:81
mode http
default_backend my-setcookie-backend
backend my-setcookie-backend
mode http
http-request redirect location http://172.19.0.1:80/\r\nSet-Cookie:\ JSESSIONID=%[urlp(session_id)] code 302
With this configuration, an attempt to access http://172.19.0.1:81/?session_id=123456 from any browser will be redirected to http://172.19.0.1:80 with an already set session cookie (here, we are using the fact that the cookies set for this domain do not take ports into consideration).
Summary
As you can see, HAProxy has a number of typical and inventive applications. Its big advantages are a relatively simple configuration, a runtime performance and being “lightweight”, which makes the changed configuration load in a split second.
I’m sure that any designer of distributed systems or an agile developer will find HAProxy to be a very useful tool in their work.
Translation by Piotr Żurawski-
SENIOR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 14 900 - 20 590 PLN brutto
B2B 19 680 - 27 220 PLN netto -
REGULAR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 11 300 - 15 900 PLN brutto
B2B 14 950 - 21 000 PLN netto -
ZOBACZ WSZYSTKIE OGŁOSZENIA
technical
newsletter
-
SENIOR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 14 900 - 20 590 PLN brutto
B2B 19 680 - 27 220 PLN netto -
REGULAR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 11 300 - 15 900 PLN brutto
B2B 14 950 - 21 000 PLN netto -
ZOBACZ WSZYSTKIE OGŁOSZENIA