
This assumes you have installed HAProxy.
Let's say you have two servers, server1 and server2, and these servers both serve the www.example.com web pages. By default, HAProxy will use round robin to alternate the requests between server1 and server2. Sticky Sessions can be used so that if a user's first request hits server1, subsequent requests will go to server1.
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 "server1". The prefix option is what includes the server (server1 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.example.com
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.example.com
accept-encoding: gzip, deflate
accept-language: en-US,en;q=0.9
default-cookie=server1
}
]
]
Or 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.example.com --verbose
> GET / HTTP/1.1
> Host: www.example.com
> User-Agent: curl/7.79.1
> Accept: */*
In this example
- acl node hdr(host) -i foo.example.com is used to route requests to the backend named stage when going to foo.example.com (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 foo.example.com
use_backend stage if foo
default_backend stage
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 server1 (10.0.0.1) is a Docker system that contains a NodeJS Express app that returns Hello World.
Likewise, let's say server2 (10.0.0.2) is a Docker system that contains an identical NodeJS Express app that also returns Hello World.
Now when going to foo.example.com 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~ foo/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~ foo/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~ foo/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~ foo/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~ foo/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