Setup

My setup consists of a Debian 11 server with HAProxy, and 2 Apache web servers running on Alpine linux:

  • Debian: 192.168.100.121
  • Alpine 1: 192.168.100.120
  • Alpine 2: 192.168.100.130

The webservers are hosting the following contents on port 80:

#Alpine 1
Node 1: 192.168.100.120

#Alpine 2
Node 2: 192.168.100.130

Install and Enable HAProxy

apt install haproxy -y

systemctl enable --now haproxy

HAProxy configuration

HAProxy is configured with mode http by default, including timeout settings. My setup:

# frontend

frontend apache_alpine_front
	bind *:80
        default_backend 	apache_alpine_backend_servers
		option 				forwardfor

# backend

backend apache_alpine_backend_servers

	balance		roundrobin
	server		alpine 192.168.100.120:80
	server		alpine2 192.168.100.130:80
  • frontend: Where requests will be received. It’s listening on all IPs on port 80.

  • option forwardfor: Adds the X-Forwarded-For header in all requests to the backend.

  • backend: Servers that will process the requests.

  • balance: Defines how the requests will be distributed.

Restart haproxy, and verify the configuration by accessing the frontend:

MacBook-Pro:~ kavish$ for i in `seq 1 7`; do curl 192.168.100.121; done
Node 1: 192.168.100.120
Node 2: 192.168.100.130
Node 1: 192.168.100.120
Node 2: 192.168.100.130
Node 1: 192.168.100.120
Node 2: 192.168.100.130
Node 1: 192.168.100.120

Note: make sure your webservers are up and running.

TLS/SSL Termination

Communication from the client to the proxy will be encrypted, and communication from HAProxy to the backend will be plain HTTP. HAProxy require the private key and certificate to be in the same file:

$ cd /etc/ssl/private
$ mkcert localhost
$ mv localhost.pem
$ cat localhost-key.pem localhost.pem > localhost-haproxy.pem
$ rm -f localhost-cert.pem localhost-key.pem
$ chmod 640 localhost-haproxy.pem

Configure the frontend section:

# Define frontend
frontend apache_alpine_front
	bind *:443 ssl crt  /etc/ssl/private/localhost-haproxy.pem
	http-request redirect scheme https unless { ssl_fc }

    	default_backend 	apache_alpine_backend_servers
		option 			    forwardfor

Force TLS

On a local network, users won’t include https://. To redirect all traffic over port 443, use the http-request redirect scheme:

# Define frontend
frontend apache_alpine_front
	bind *:443 ssl crt  /etc/ssl/private/localhost-haproxy.pem
	http-request redirect scheme https unless { ssl_fc }

    	default_backend 	apache_alpine_backend_servers
		option 			    forwardfor

Implement TLS/SSL for backend servers

If for some reason you want to encrypt the comunication of HAProxy to the backend servers, replace 80 with 443, and the ssl keyword:

# Define backend
backend apache_alpine_backend_servers

	balance		roundrobin
	server		alpine 192.168.100.120:80
	server		alpine2 192.168.100.130:443 ssl

For Self Signed Certificates

It’s not neccesarry to verify SSL certificates for local servers. Unless you have the CA certificate, just use verify none:

# Define backend
backend apache_alpine_backend_servers

	balance		roundrobin
	server		alpine 192.168.100.120:80
	server		alpine2 192.168.100.130:443 ssl verify none

Health checks

By default, HAProxy will route traffic to webservers on your backend, even if the servers are offline. Only servers that respond with a 200 status code should remain in the backend queue. To perform health checks, you should use option httpchk, and check directives in the backend section:

# Define backend
backend apache_alpine_backend_servers

	option httpchk

	balance		roundrobin
	server		alpine 192.168.100.120:80 check
	server		alpine2 192.168.100.130:443 ssl verify none check

Specific Health Checks

The check can be more specific. For example, perform a GET request on / for each server every 20 seconds:

# Define backend
backend apache_alpine_backend_servers

	option httpchk GET /
	default-server inter 20s

	balance		roundrobin
	server		alpine 192.168.100.120:80 check
	server		alpine2 192.168.100.130:443 ssl verify none check

Or perform the check every 20s, except for alpine2, which a check will be perform every 10s:

# Define backend
backend apache_alpine_backend_servers

	option httpchk GET /
	default-server 20s

	balance		roundrobin
	server		alpine 192.168.100.120:80 check
	server		alpine2 192.168.100.130:443 ssl verify none check inter 10000

More examples can be found here.

Server Stats

You can enable the global stats page, by appending the following in your configuration file:

listen stats
	bind 	:8000
	mode 	http
	stats 	enable
	stats 	hide-version
	stats 	uri /
	stats 	admin if TRUE

Modify your firewall to allow the specified port, and browse to yoursite:8000. Stats can be enabled or configured for specific frontend/backend sections. You can read more about it here.

Be the change that you wish to see in the world.”Mahatma Gandhi