HAProxy
info
HAProxy is an alternative to NGINX. Unlike NGINX it is simply a proxy handler, it cannot be used to host static web pages.
When used from within docker, be aware that browsers such as chrome will cache references to the <ip>:<port> location. If the location is invalid, the browser seems to hold onto to the cached data. As an example, we initially set up the frontend section to bind to wrong host (the docker address) on port 8080.
When we ran the proxy via docker we mapped 8090 out to 8080, this was the wrong way round, it should have been 8080 out to 8090. When we tried to access <docker ip>:8080 or <docker ip>:8090 from Chrome, they both failed for obvious reasons.
We then corrected the forntend section to bind on all interfaces at port 8080 "*:8080". We ran docker, exporting docker port 8080 to host port 8090, then tried to access the proxy at <docker ip>:8090 and it still failed. We then tried to access the proxy at <docker ip>:8090 from another browser - Opera, and it also failed.
We brought the docker container down and re-run (not restart) it, tried again from chrome, it still failed, but from Opera, it now worked.
Finally we changed the docker port mapping to host 8095 and container to 8080, access worked from both Chrome and Opera.
All access has failed from MS Edge???
Working with Docker
- Create the haproxy.cfg file, use the example script below as a template
- Create a shared folder within the Windows //Users/<username>/<somefolder>/<some shared folder>/, this will be used in the mount option of docker run
# Simple configuration for an HTTP proxy listening on port 80 on all # interfaces and forwarding requests to a single backend "servers" with a # single server "server1" listening on 127.0.0.1:8000 global daemon maxconn 256 defaults mode http timeout connect 5000ms retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s frontend http-in bind *:8080 default_backend servers backend servers mode http balance roundrobin server server1 192.168.99.100:8081 maxconn 32 server server2 192.168.99.100:8082 maxconn 32
To make life easy mount a shared folder to /usr/local/etc/haproxy. Let's look at this in more detail with the command we will use the docker run haproxy
docker run -p 8095:8080 -dit --name haproxy-instance -v //c/Users/Selvyn/demo/vm_share/haproxy:/usr/local/etc/haproxy haproxy
Breakdown of command
- -p 8095:8080 - expose the container port 8080 onto the host port of 8095 (examine the haproxy.cfg and look for the bind command)
- --name haproxy-intance - we register this container instance with docker as haproxy-instance, useful for docker rm, stop, and docker start commands
- -v //c/Users/Selvyn/demo/vm_share/haproxy - host folder that we will mapped to a mounted folder within the container
- -v :/usr/local/etc/haproxy - the mounted folder within the container
Using mounted volumes (folders/files) in docker makes it a lot easier to pass data between the host and the container environment. Any changes in the host environemt to a folder and all its contents, or a file are immediately reflected in the container environemt. Conversley any changes in the container environemt to a folder and all its contents, or a file are immediately reflected in the host environment.
Adding Sticky Sessions to the server's behaviour
ONe of my main reasons for moving to HAProxy was to enable HTTP session management at as little cost as possible. The following is a description of how to enable this in HAProxy.
If you want web sessions to have persistent connections to the same server, you can use a balance
algorithm such as
hdr, rdp-cookie, source, uri, orurl_param.
If your implementation requires the use of the
leastconn
,roundrobin
, orstatic-rr
algorithm,
you can implement session persistence by using server-dependent cookies.
To enable session persistence for all pages on a web server, use the cookie
directive to define the name of the cookie to be inserted and add the cookie
option and server name to the server
lines, for example:
cookie WEBSVR insert server websvr1 192.168.1.71:80 weight 1 maxconn 512 cookie 1 check server websvr2 192.168.1.72:80 weight 1 maxconn 512 cookie 2 check
HAProxy includes an additional Set-Cookie:
header that identifies the web server in its response to the client, for example: Set-Cookie: WEBSVR=
. If a client subsequently specifies the N
; path=page_path
WEBSVR
cookie in a request, HAProxy forwards the request to the web server whose server cookie
value matches the value of WEBSVR
.
The following example demonstrates how an inserted cookie ensures session persistence:
Shell scripting example
$ while true; do curl http://10.0.0.10; sleep 1; done
This is HTTP server websvr1 (192.168.1.71).
This is HTTP server websvr2 (192.168.1.72).
This is HTTP server websvr1 (192.168.1.71).
^C
$ curl http://10.0.0.10 -D /dev/stdout
HTTP/1.1 200 OK
Date: ...
Server: Apache/2.4.6 ()
Last-Modified: ...
ETag: "26-5125afd089491"
Accept-Ranges: bytes
Content-Length: 38
Content-Type: text/html; charset=UTF-8
Set-Cookie: WEBSVR=2; path=/
This is HTTP server svr2 (192.168.1.72).
$ while true; do curl http://10.0.0.10 --cookie "WEBSVR=2;"; sleep 1; done
This is HTTP server websvr2 (192.168.1.72).
This is HTTP server websvr2 (192.168.1.72).
This is HTTP server websvr2 (192.168.1.72).
^C
To enable persistence selectively on a web server, use thecookie
directive to specify that HAProxy should expect the specified cookie, usually a session ID cookie or other existing cookie, to be prefixed with theserver cookie
value and a~
delimiter, for example:
cookie SESSIONID prefix server websvr1 192.168.1.71:80 weight 1 maxconn 512 cookie 1 check server websvr2 192.168.1.72:80 weight 1 maxconn 512 cookie 2 check
If the value of SESSIONID
is prefixed with a server
cookie
value, for example: Set-Cookie: SESSIONID=
, HAProxy strips the prefix and delimiter from the N
~Session_ID
;SESSIONID
cookie before forwarding the request to the web server whose server cookie
value matches the prefix.
The following example demonstrates how using a prefixed cookie enables session persistence:
Shell scripting example
$ while true; do curl http://10.0.0.10 --cookie "SESSIONID=1~1234;"; sleep 1; done
This is HTTP server websvr1 (192.168.1.71).
This is HTTP server websvr1 (192.168.1.71).
This is HTTP server websvr1 (192.168.1.71).
^C
A real web application would usually set the session ID on the server side, in which case the first HAProxy response would include the prefixed cookie in the Set-Cookie:
header.