
This assumes you have installed HAProxy.
Let's say you have two servers, www1.example.com and www2.example.com, and these servers both serve the www.example.com web pages. By default, HAProxy will use round robin to alternate the requests between www1.example.com and www2.example.com. Sticky Sessions can be used so that if a users first request hits www1.example.com, their subsequent requests will go to www1.example.com.
Listen Block
One option would be to use the listen block.
- The prefer-last-server and cookie directives are used for sticky sessions. Replace "default-cookie" with anything you would like for the cookie name.
- The httplog, http-request and log-format directives are not needed for sticky sessions, but are really helpful for debugging. Refer to HAProxy Logging for more details on logging.
listen web
bind *:80
mode tcp
balance roundrobin
option httplog
http-request capture req.hdrs len 1024
log-format "%ci:%cp [%tr] %ft [[%hr]] %hs %{+Q}r"
option prefer-last-server
cookie default-cookie prefix insert indirect nocache
server www1 www1.example.com:80 check cookie www1
server www2 www2.example.com:80 check cookie www2
If you have a firewall, such as iptables or firewalld, you will need to allow the HAProxy bind port, not the ports being used by the "server" directives. In this example, only the http (port 80) service would need to be allowed.
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload
SInce the httplog, http-request and log-format directives were included, the /var/log/haproxy.log should now show that the header contains the cookie (default-cookie in this example), something like this.
- Notice in this example that default-cookie contains "www1". The prefix option is what includes the server (www1 in this example).
Feb 21 03:27:58 localhost haproxy[6083]: 192.168.0.104:59642 [21/Feb/2022:03:27:58.090] main
[
[
{
host: www.freekb.net
cache-control: max-age=0
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
referer: http://www.freekb.net/Article?id=12345
accept-encoding: gzip, deflate
accept-language: en-US,en;q=0.9
default-cookie=www1
}
]
]
Frontend / Backend
Or, the frontend and backend blocks can be used. However, this is more commonly used for more complex situations, such as when there are two web servers serving multiple domains.
hdr is short for HTTP headers. For example, the curl command can be used to see the "host" header.
~]$ curl http://www.freekb.net --verbose
> GET / HTTP/1.1
> Host: www.freekb.net
> User-Agent: curl/7.79.1
> Accept: */*
In this example
- acl node hdr(host) -i node.freekb.net is used to route requests to the node backend when going to node.freekb.net (the -i flag means case insensitive)
- the name of the cookie will be "sticky"
frontend main
bind *:80
bind *:443 ssl crt /etc/pki/tls/foo.pem
balance roundrobin
option prefer-last-server
acl node hdr(host) -i node.example.com
use_backend node if node
default_backend node
backend stage
cookie sticky insert indirect nocache
server server1 10.0.0.1:12345 check cookie server1
server server2 10.0.0.2:12345 check cookie server2
Let's say 10.0.0.1 is a Docker system that contains a NodeJS Express app that returns Hello World.
Likewise, let's say 10.0.0.2 is a Docker system that contains an identical NodeJS Express app that also returns Hello World.
Now when going to node.freekb.net the NodeJS Express app is returned from either server1 or server2.
And there should be a cookie named "sticky" (in this example) in your browser since we named our cookie in HAProxy "sticky". Notice also the request hit server1.
And /var/log/haproxy.log should now that the request hit server1.
May 26 03:45:35 localhost haproxy[30781]: 65.89.100.90:63361 [26/May/2024:03:45:35.640] my_domains~ node/server1 71/0/2/11/84 200 274 - - --NI 2/2/0/1/0 0/0 "GET / HTTP/1.1"
Now, if we reload the browser a few times, we should see that /var/log/haproxy.log shows that subsequent request remain on server1. Perfect!
May 26 03:51:12 localhost haproxy[30781]: 65.89.100.90:63609 [26/May/2024:03:51:10.938] my_domains~ node/server1 1285/0/1/2/1288 200 274 - - --VN 2/2/0/1/0 0/0 "GET / HTTP/1.1"
May 26 03:51:14 localhost haproxy[30781]: 65.89.100.90:63609 [26/May/2024:03:51:12.226] my_domains~ node/server1 2228/0/1/2/2231 200 274 - - --VN 2/2/0/1/0 0/0 "GET / HTTP/1.1"
May 26 03:51:15 localhost haproxy[30781]: 65.89.100.90:63609 [26/May/2024:03:51:14.458] my_domains~ node/server1 1524/0/1/3/1528 200 274 - - --VN 2/2/0/1/0 0/0 "GET / HTTP/1.1"
May 26 03:51:17 localhost haproxy[30781]: 65.89.100.90:63609 [26/May/2024:03:51:15.986] my_domains~ node/server1 1189/0/1/2/1192 200 274 - - --VN 2/2/0/1/0 0/0 "GET / HTTP/1.1"
May 26 03:51:18 localhost haproxy[30781]: 65.89.100.90:63609 [26/May/2024:03:51:17.178] my_domains~ node/server1 1060/0/1/3/1064 200 274 - - --VN 2/2/0/1/0 0/0 "GET / HTTP/1
Did you find this article helpful?
If so, consider buying me a coffee over at