Route by using existing cookie - haproxy

How can I route requests in haproxy using a cookie that was set on the app servers?
Example: SESS=<hash-of-username>
haproxy should not insert cookies by itself in any case.

For testing a specific server behind haproxy I can recommend this approach:
frontend http
acl is_cookie_hack_1 hdr_sub(cookie) server_test_hack=server1
acl is_cookie_hack_2 hdr_sub(cookie) server_test_hack=server2
... insert your normal acl rules here
use_backend bk_server_1 if is_cookie_hack_1
use_backend bk_server_2 if is_cookie_hack_2
... insert your normal use_backend expressions here
backend bk_server_1
...
backend bk_server_2
...
I insert the server_test_hack cookie by javascript in my browser's js console by this script:
document.cookie="server_test_hack=server1";

You can't use your existing cookie for balancing, the way you could use the URI parameter. You can't just take the md5() or build the hash table of the cookie, at least that is not documented. You could use prefix parameter for the cookie to achieve a different result. It might be what you are looking for (if you want to avoid creation of yet another cookie).
So in your case the config would look like this:
backend bk_web
balance roundrobin
cookie SESS prefix indirect nocache
server s1 192.168.10.11:80 check cookie s1
server s2 192.168.10.21:80 check cookie s2
When the request arrives without a cookie, any server is chosen by round-robin and request is redirected to it. When response arrives from the backend, HAProxy checks for the SESS cookie and if it's set, it prepends the server name (sX) to the cookie and sends it to the client. In the browser, the cookie looks like sX~, but when the next request is sent with that cookie, the backend server only sees in the cookie, as HAProxy strips the sX~ part
Source: load balancing, affinity, persistence, sticky sessions: what you need to know

If you just want to read cookies in the request and route accordingly, you can do something like this in your configuration:
frontend http
acl cookie_found hdr_sub(cookie) COOKIENAME
use_backend app_server if cookie_found
backend app_server
balance roundrobin
server channel1 X.X.X.X:PORT #Host1
server channel2 Y.Y.Y.Y:PORT #Host2

Related

Cookie prefix with dynamic server template

I am trying to implement sticky sessions. I have found out that I can add a prefix to the exiting cookies servers to identify them. See here for more
backend bk_web
balance roundrobin
cookie JSESSIONID prefix nocache
server s1 192.168.10.11:80 check cookie s1
server s2 192.168.10.21:80 check cookie s2
My problem is that I do not have distinct servers which I could hard code the cookie names for. Such as s1 and s2.
backend java_container
balance roundrobin
cookie JSESSIONID prefix nocache
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none
I know the server will be named later worker-1, worker-2 etc but I can't figure out how to give this dynamic info as cookie name. Ideally it would be something like
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none cookie worker
I tried munging the snippets together and it actually worked.
backend java_container
balance leastconn
dynamic-cookie-key MYKEY
cookie JSESSIONID prefix dynamic nocache
server-template worker- 6 worker:8080 check resolvers docker init-addr libc,none
Cookie looks like this now where the first part the hashed server IP.
JSESSIONID: 8a90ee411f256174~602EE52C3C605D45070366D4009EED56
https://www.haproxy.com/blog/whats-new-haproxy-1-8/#dynamic-cookies
You are looking for the dynamic option as part of the cookie directive. You will also want to look into dynamic-cookie-key.

Dynamic routing to backend based on context path in HAProxy

I have specific requirement that depending on my context path I have to redirect my traffic to different server/port though HAProxy. I have already achieved the same with "path_beg" in ACL. Below is the configuration.
use_backend a1 if { path_beg /a1 }
use_backend a2 if { path_beg /a2 }
backend a1
balance roundrobin
server 1-www 172.17.0.1:80 check cookie s2
backend a2
balance roundrobin
server 1-www 172.17.0.3:80 check cookie s2
Now the concern is here every context path I also need to enter a frontend settings like use_backend a1 if { path_beg /a1 } which I would like to avoid. What I want when I need to add a new server I will add the backend as it's necessary but for the front end I am looking for something like this.
use_backend regex
Where regular expression will take the context path from the url and will proceed to the corresponding backend.
Note: backend name will be same as context path. Like if the url is http://example.com/dummy then backend name will be "dummy".
Any suggetion on the same.

How to implement the code which redirect clients request to another node

I'm very curious about how to implement redirect code in a back server node.
For example: Client A request web server C, there is a load balance node B between A and C. So the graph is A=>B=>C=>A (not A=>B=>C=>B=>A). Actually C get requests from B, so I'm wondering how does C create a socket to connect to A and send data to A. I highly appreciate if you would share me some code snippet about this, Thanks!
I think this is the question you are asking:
"I have multiple web servers behind a load balancer, so how can I create a persistent http socket connection to a back end server from a client without it being redirected to another server and therefore breaking connection?"
The answer to that question is through cookie injection. For example, with HAProxy you can set a cookie depending on the server that the request is routed to first, then the load balancer will know to stick that request in future to the specified server.
An example in HAProxy backend configuration:
backend socket-servers
timeout server 120s
balance leastconn
# based on cookie set in header
# haproxy will add the cookies for us
cookie SRVNAME insert
server node-1 127.0.0.1:5000 cookie S1 check
server node-2 127.0.0.1:5001 cookie S2 check
This example was taken from http://toon.io/configuring-haproxy-multiple-engine-io-servers/.
Upon a new request it will see no cookie, and route to the best server based on the server with the least number of connections. As it does so, it sets a cookie SRVNAME=node-1 or SRVNAME=node-2 depending on the server it goes to. Every subsequent request from the client goes to the node specified in the cookie.

haproxy configuration for RESTful loadbalancing - creating resurces

I am trying to come up with a haproxy configuration
for a cluster of rest servers where the creation of a resource
should be sent in round-robin to the servers
POST /somecollection
responds with the created resource uri (eg /collection/instance01 )
but then any further use of the created resources
GET /collection/instance01/blah
PUT /collection/instance01/foo
DELETE /collection/instance01/
must be sticky to the server instance that handled the POST
(where the resource has been created).
And I would like to do that without cookies :-)
Any ideas ?
One way to achieve this is via cookie:
Example:
backend rest_backend
...
cookie __sticky_rest insert indirect nocache
server rest1 x.x.x.1:xxxx cookie 1
server rest2 x.x.x.2:xxxx cookie 2
...

how to balance to a specific server if hostname matches x.domaine.com (Haproxy)

as mentioned in the title, i've set an Haproxy loadbalancer with a basic configuration, what i'd like to do is to always redirect request to the first server if the hostname matches x.domaine.com, but keep the balancing for domaine.com, is it possible with Haproxy, and if so how can i do it.
her's my configuration
listen webcluster *:80
mode http
balance roundrobin
option httpchk HEAD / HTTP/1.0
option forwardfor
cookie LSW_WEB insert
option httpclose
server bigSRV 192.168.1.10:8082 cookie LSW_WEB01 check
server miniSRV 192.168.2.10:8082 cookie LSW_WEB01 check
thanks in advence
after hours of digging i finally got it to work, so i'm going to answer my own question in case if samone have the same issue
generally i created a frontend that listen on port:80 and in which i defined 2 ACLs that uses the "if" statement to check the http header and then redirect to one of the backends defined, if no request matches the conditions, we redirect to default backend, here's how it's done (on haproxy.cfg) :
frontend http-proxy
bind *:80
acl is_www hdr(host) -i www.domain.com
acl is_x hdr(host) -i x.domain.com
use_backend clusterWWW if is_www
use_backend clusterX if is_x
default_backend clusterWWW
backend clusterWWW
server bigSRV 192.168.1.10:8082 cookie LSW_WEB01 check
server miniSRV 192.168.2.10:8082 cookie LSW_WEB01 check
backend clusterX
server bigSRV 192.168.1.10:8082 cookie LSW_WEB01 check