How To Deploy HAProxy as a Load Balancer for NGINX on Linux Servers
Configure HAProxy as a Load Balancer for NGINX
By default, HAProxy’s configuration files are stored under the /etc/haproxy directory and its main configuration file is /etc/haproxy/haproxy.cfg. Below is a sample HAProxy configuration for load-balancing requests to NGINX servers.
Page Contents
This example configuration shows some key aspects of HAProxy including SSL termination, redirecting HTTP to HTTPS, redirecting prefix(www to non-www), deleting HTTP headers, adding HTTP security headers, using different backends depending on the domain, setting the load balancing algorithm, and backend health checks.
Here, HAProxy is running in HTTP mode(mode http set in the default section to apply to all other sections). The frontend section is used to receive requests from clients and it listens on the HTTP port 80 and HTTPS port 433. The ssl and crt directives defined with the bind directive are used to enable SSL termination. All HTTP requests are redirected to HTTPS (using redirect scheme https code 301 if !{ ssl_fc } directive).
Requests to the tickets.fg.app domain are redirected to a specific backend (using use_backend nginx_gp2 if { hdr(host) -m dom tickets.fg.app } ), the same applies to mywpsite.com ( use_backend nginx_gp3 if { hdr(host) -m dom mywpsite.com }). Requests to all other applications are sent to the default backend that is specified using the default_backend directive ( default_backend nginx_gp1). To redirect the www prefix to non-www, the redirect prefix directive is used.
Additionally, the backend nginx_gp1 uses the least_conn load balancing algorithm because it has many servers it is passing requests to. It also has several http-response set-header directives for setting security HTTP headers.
The server directive is used to define the backend NGINX servers that HAProxy is forwarding requests to. Ensure that you specify the correct server IP addresses, otherwise, your web application or sites may not load as expected.
#cat /etc/haproxy/haproxy.conf
global
maxconn 50000
log 127.0.0.1 local2
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-options ssl-min-ver TLSv1.2
#ssl-dh-param-file /etc/ssl/kyu/dhparam
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
timeout connect 30s
timeout check 30s
timeout client 20m
timeout server 30m
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen stats
bind *:8500
stats enable
stats hide-version
stats uri /monitor
stats realm Haproxy\ Statistics
stats refresh 5s
stats admin if TRUE
stats auth terpadmin:Lostp@1ss
frontend http_in
bind *:80
bind *:443 ssl crt /etc/ssl/certs/clientwebapp1.com.pem crt /etc/ssl/certs/clientwebapp2.com.pem crt /etc/ssl/certs/fg.app_cert.pem crt /etc/ssl/certs/clientwebapp3.com.pem crt /etc/ssl/certs/mywpsite.com.pem alpn h2,http/1.1
redirect scheme https code 301 if !{ ssl_fc }
redirect prefix https://mywpsite.com code 301 if { hdr(host) -i www.mywpsite.com }
use_backend nginx_gp2 if { hdr(host) -m dom tickets.fg.app }
use_backend nginx_gp3 if { hdr(host) -m dom mywpsite.com }
http-response set-header Strict-Transport-Security max-age=63072000
default_backend nginx_gp1
#backend for passing requests to same client web apps deployed on several servers for HA
backend nginx_gp1
balance least_conn
option httpchk GET /
http-check expect status 200
#add security HTTP headers
http-response set-header X-Frame-Options DENY
http-response set-header X-XSS-Protection 1;mode=block
http-response set-header X-Content-Type-Options nosniff
http-response set-header Strict-Transport-Security max-age=31536000;includeSubDomains;preload
http-response set-header Referrer-Policy no-referrer-when-downgrade
#http-response set-header Content-Security-Policy "default-src self *.kyu.ac.ug *.mubs.ac.ug cdn.jsdelivr.net fonts.googleapis.com fonts.gstatic.com"
http-response set-header Expect-CT enforce,\ max-age=86400
http-response set-header Referrer-Policy strict-origin-when-cross-origin
http-response add-header X-Permitted-Cross-Domain-Policies none
http-response set-header Permissions-Policy "accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(), encrypted-media=(), fullscreen=(self), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), xr-spatial-tracking=(), clipboard-read=(self), clipboard-write=(self), gamepad=()"
#set server cookie
cookie SVR_ID insert indirect nocache dynamic secure httponly
dynamic-cookie-key 934ndsdjefefwe
default-server maxconn 100000
server nginx_gp1_svr1 10.10.1.4:80 check
server nginx_gp1_svr2 10.10.1.4:80 check
server nginx_gp1_svr3 10.20.1.4:80 check
server nginx_gp1_svr3 10.20.1.5:80 check
server nginx_gp1_svr3 10.20.1.6:80 check
#backend for passing requests to tickets.fg.app application
backend nginx_gp2
option httpchk HEAD /
cookie SVR_ID insert indirect nocache dynamic secure httponly
dynamic-cookie-key n3400sddsdje0992
server nginx_gp2_svr1 10.10.1.4:80 check
#backend for passing requests to mywpsite.com web site
backend nginx_gp3
mode http
option httpchk HEAD /
cookie SVR_ID insert indirect nocache dynamic secure httponly
dynamic-cookie-key nKLJLDF00sdd090911
server nginx_gp3_svr1 10.10.1.5:80 check
After making changes to your HAProxy configuration file and saving it, I recommend you check it for syntax correctness using this command:
$sudo haproxy -c -f /etc/haproxy/haproxy.cfg OR #haproxy -c -f /etc/haproxy/haproxy.cfg

To apply any changes in the HAProxy configuration, you need to restart the HAProxy service and check its status to ensure that it is up and running, like this:
#systemctl restart haproxy.service #systemctl status haproxy.service

Next, test if you can access your websites and web applications on your local network or the Internet (i.e. your HAProxy server has a publicly accessible IP address, and your DNS configurations are valid for your domains and pointed to that IP).
Conclusion
In upcoming guides, I will be expounding on many of the configuration directives in the NGINX and HAProxy configurations above. Until then, stay with FOSSGuides! Your questions or comments are welcome, via the feedback form below.
References:
1. https://nginx.org/en/docs/
2. https://docs.haproxy.org/