Turning Off Failover in HAProxy

I’m using cookie + IP-based sticky sessions.

When a user accesses the backend with an assigned cookie, we want to display a 503 error instead of failing over if the corresponding backend server is down.

Currently, we retrieve the cookie and apply filtering using an ACL. However, in the HAProxy logs, we see:

“https_front~” “servers1” “apache01” 0 0 1 1 2 --DN 2 1 0 0 0 0 0

The D flag is recorded, indicating that failover is still occurring.
How can we prevent failover in this case? Any help would be appreciated!

Best regards

The default behavior is to respect the session cookie and stick the user to the broken server.

Perhaps you are overwriten this behaviour with the option redispatch configuration, somewhere in your config?

Thank you for your response.
Could you tell me if there are any other settings that might override haproxy.cfg?
I have specified no option redispatch in both the defaults and backend sections.

However, redispatch is still occurring
Below is my backend configuration.
There are some extra settings, but since redispatch is not being disabled, I tried handling it with an ACL, but it does not work as expected.


backend servers1
balance leastconn
#option redispatch 0
no option redispatch
option httpchk
option prefer-last-server
mode http
http-check disable-on-404
option http-server-close
http-check send meth GET uri / ver HTTP/1.1 hdr Host xxxxxx.net
http-check expect status 200
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-By %[hostname]
cookie SERVERID insert indirect nocache
stick-table type ip size 1m expire 30m peers haproxy-peers-backend
"# stick on src
stick on req.cook(SERVERID)
acl has_cookie req.cook(SERVERID) -m found
acl cookie_apache01 req.cook(SERVERID) -m str “SERVERID=aaaaa”
acl cookie_apache02 req.cook(SERVERID) -m str “SERVERID=bbbbb”
acl apache01_down srv_is_up(apache01) eq 0
acl apache02_down srv_is_up(apache02) eq 0
http-request set-log-level info if cookie_apache01
http-request set-log-level info if cookie_apache02
http-request set-log-level alert if apache01_down
http-request set-log-level alert if apache02_down
http-request deny if cookie_apache01 apache01_down
http-request deny if cookie_apache02 apache02_down
force-persist if cookie_apache01
force-persist if cookie_apache02
use-server apache01 if cookie_apache01
use-server apache02 if cookie_apache02
default-server maxconn 5000 on-marked-down shutdown-sessions
server apache01 192.168.0.2:80 cookie aaaaa check inter 2000 fall 3 rise 2 maxconn 5000
server apache02 192.168.0.3:80 cookie bbbbb check inter 2000 fall 3 rise 2 maxconn 5000

No, this should do the job just fine.

If can’t get it to work, the only way to help you is if you provide the entire configuration as well as complete log line in httplog format.

Thank you

harpoxy.cfg body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 20px; padding: 20px; } pre { background-color: #2d2d2d; color: #ffffff; padding: 15px; border-radius: 5px; overflow-x: auto; font-size: 14px; line-height: 1.5; }
<h2>haproxy.cfg</h2>

<pre>

global
log 127.0.0.1 local0 debug
log stdout format raw local0 debug
maxconn 20480
daemon
nbthread 4
master-worker
stats socket /var/run/haproxy.sock mode 600 level admin
defaults
log global
mode http
no option redispatch
option log-separate-errors
log-format “%ci:%cp [%t] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%r/%r %hrl %hsl %hs %rt”
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
errorfile 503 /etc/haproxy/errorfiles/503.http
errorfile 403 /etc/haproxy/errorfiles/403.http
peers haproxy-peers-f
peer haproxy01 192.168.11.231:1024
’ # peer haproxy02 192.168.11.232:1024
peers haproxy-peers-backend
peer haproxy01 192.168.11.231:1025
’ peer haproxy02 192.168.11.232:1025

frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem
mode http
option httplog clf
default_backend servers1
capture request header Cookie len 128
capture request header User-Agent len 64
acl domain1 req_ssl_sni -i xxxxx.net
’ # acl domain2 req_ssl_sni -i yyyyyy.net
use_backend servers1 if domain1
’ # use_backend servers2 if domain2
stick-table type ip size 20k expire 10s store http_req_rate(10s) peers haproxy-peers-f
http-request track-sc0 src
acl exceeds_rate_limit sc_http_req_rate(0) gt 20
http-request set-log-level alert if exceeds_rate_limit
http-request deny if exceeds_rate_limit

capture request header Cookie len 128
capture request header Host len 64
capture request header User-Agent len 128

frontend http_front
bind *:80
mode http
stick-table type ip size 1m expire 10s store http_req_rate(10s)
acl exceeds_rate_limit sc_http_req_rate(0) gt 20
http-request set-log-level alert if exceeds_rate_limit
http-request deny if exceeds_rate_limit
redirect scheme https if !{ ssl_fc }

backend servers1
balance leastconn
#option redispatch 0
no option redispatch
option httpchk
option prefer-last-server
mode http
http-check disable-on-404
option http-server-close
http-check send meth GET uri / ver HTTP/1.1 hdr Host xxxxxx.net
http-check expect status 200
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-By %[hostname]
cookie SERVERID insert indirect nocache
stick-table type ip size 1m expire 30m peers haproxy-peers-backend
'# stick on src
stick on req.cook(SERVERID)
acl has_cookie req.cook(SERVERID) -m found
acl cookie_apache01 req.cook(SERVERID) -m str “SERVERID=aaaaa”
acl cookie_apache02 req.cook(SERVERID) -m str “SERVERID=bbbbb”
acl apache01_down srv_is_up(apache01) eq 0
acl apache02_down srv_is_up(apache02) eq 0

http-request set-log-level info if cookie_apache01
http-request set-log-level info if cookie_apache02
http-request set-log-level alert if apache01_down
http-request set-log-level alert if apache02_down

http-request deny if cookie_apache01 apache01_down
http-request deny if cookie_apache02 apache02_down

force-persist if cookie_apache01
force-persist if cookie_apache02
use-server apache01 if cookie_apache01
use-server apache02 if cookie_apache02

default-server maxconn 5000 on-marked-down shutdown-sessions
server apache01 192.168.0.2:80 cookie aaaaa check inter 2000 fall 3 rise 2 maxconn 5000
server apache02 192.168.0.3:80 cookie bbbbb check inter 2000 fall 3 rise 2 maxconn 5000
</pre>

log

Feb 5 00:01:50 localhost haproxy[1756255]: xxx.xxx.xxx.xxx - - [04/Feb/2025:15:01:50 +0000] "GET https://xxxxx.net/ HTTP/2.0" 200 319 "" "" 50838 393 "https_front~" "servers1" "apache01" 0 0 0 0 0 --DI 1 1 0 0 0 0 0 "" "" "SERVERID=bbbbb" "curl/8.7.1" "SERVERID=bbbbb" "xxxxx.net" "curl/8.7.1"




Feb 5 00:02:00 localhost haproxy[1756255]: xxx.xxxx.xxx.xxx - - [04/Feb/2025:15:02:00 +0000] “GET https://xxxxx.net/ HTTP/2.0” 200 319 “” “” 50901 559 “https_front~” “servers1” “apache01” 0 0 0 1 1 --VN 1 1 0 0 0 0 0 “” “” “SERVERID=aaaaaa” “curl/8.7.1” “SERVERID=aaaaa” “xxxxx.net” “curl/8.7.1”

You need to remove your custom configuration options like “use-server”. This does not belong here.

Also remove all those acl cookie_apache0X and apache0X_down, http-request set-log-Level and http-request deny statements.

Stop haproxy, make sure nothing is listening anymore on the port, otherwise kill remaining haproxy instances, and then try again.

You need clean, straightforward configuration.

I had added extra configurations as a result of various adjustments.
I have now made the cfg very simple.
However, even with this, failover still occurs…

global
log 127.0.0.1 local0 debug
log stdout format raw local0 debug
maxconn 20480
daemon
nbthread 4
master-worker
stats socket /var/run/haproxy.sock mode 660 level admin

defaults
log global
mode http
option log-separate-errors
log-format “%ci:%cp [%t] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%r/%r %hrl %hsl %hs %rt”
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
errorfile 503 /etc/haproxy/errorfiles/503.http
errorfile 403 /etc/haproxy/errorfiles/403.http

peers haproxy-peers-backend
peer haproxy01 192.168.11.231:1025

frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem
mode http
option httplog clf
default_backend servers1
capture request header Cookie len 128
capture request header Host len 64
capture request header User-Agent len 128

frontend http_front
bind *:80
mode http
redirect scheme https if !{ ssl_fc }

backend servers1
balance leastconn
no option redispatch
option httpchk
option prefer-last-server
mode http
http-check disable-on-404
option http-server-close
http-check send meth GET uri / ver HTTP/1.1 hdr Host xxxxx.net
http-check expect status 200
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-By %[hostname]
cookie SERVERID insert indirect nocache
stick-table type ip size 1m expire 30m peers haproxy-peers-backend
stick on req.cook(SERVERID)
default-server maxconn 5000 on-marked-down shutdown-sessions
server apache01 192.168.11.234:80 cookie aaaaa check
server apache02 192.168.11.235:80 cookie bbbbb check

option persist is also necessary in the backend.

This is not obvious from the option redispatch documentation so I will send a documentation change.

1 Like

Resolved!
I’m impressed.
I finally achieved the intended behavior.
Thank you so much for your help.
Here is my final configuration.

global
log 127.0.0.1 local0 debug
tune.bufsize 65536
maxconn 20480
daemon
nbthread 4
stats socket /var/run/haproxy.sock mode 660 level admin

defaults
log global
mode http
option log-separate-errors
no option redispatch
log-format “%ci:%cp [%t] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%r/%r %hrl %hsl %hs %rt”
timeout connect 5000ms
timeout client 30000ms
timeout server 30000ms
errorfile 503 /etc/haproxy/errorfiles/503.http
errorfile 403 /etc/haproxy/errorfiles/403.http

peers haproxy-peers-frontend
peer haproxy01 192.168.11.231:1025
peer haproxy02 192.168.11.232:1025

frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem alpn h2,http/1.1
mode http
option httplog clf
default_backend servers1
compression algo gzip
compression type text/html text/plain text/css text/javascript application/javascript
capture request header Cookie len 128
capture request header Host len 64
capture request header User-Agent len 128
stick-table type ip size 20k expire 10s store http_req_rate(10s) peers haproxy-peers-frontend
http-request track-sc0 src
acl exceeds_rate_limit sc_http_req_rate(0) gt 20
http-request set-log-level alert if exceeds_rate_limit
http-request deny if exceeds_rate_limit
frontend http_front
bind *:80
mode http
redirect scheme https if !{ ssl_fc }
backend servers1
balance leastconn
no option redispatch
option prefer-last-server
option persist
mode http
http-check disable-on-404
option http-server-close
http-request set-header X-Forwarded-For %[src]
http-request set-header X-Forwarded-By %[hostname]
cookie SERVERID insert indirect nocache secure httponly
server apache01 xxx.xxx.xxx.xxx:80 cookie aaaaa check check inter 5s fall 3 rise 2
server apache02 xxx.xxxx.xxxx.xxx:80 cookie bbbbb check check inter 5s fall 3 rise 2

1 Like