Web server cannot contact backend server when using CARP

Hi, I have a website running HTTPD and node.js behind a pfSense box and I configured HAProxy to enable high availability on these servers and everything is running fine. I need now to duplicate the pfSense box and enable a sync between the two boxes. One of the steps requires the IP alias to be turned into CARP for the synchronization to work but as soon as I change the type of the virtual IP address and reload the configuration the connection to the node.js backend server timeouts with the error below. Reverting the changes to an IP alias works fine. Any suggestion on how to determine where the issue is ?

[Wed Oct 21 11:35:04.333690 2020] [proxy_http:error] [pid 1385] [client 192.168.0.1:54640] AH01114: HTTP: failed to make connection to backend: node.mysite.net

Hosts file on all servers

192.168.0.100 web.mysite.com
192.168.0.101 node.mysite.com

  • Frontend web.mysite.com

    • Virtual IP: 192.168.0.100/24
    • Backend servers:
    • 192.168.0.10 with HTTPD
    • 192.168.0.11 with HTTPD
  • Frontend node.mysite.com

    • Virtual IP: 192.168.0.101/24
    • Backend servers:
    • 192.168.0.12 with node.js listening on port 3000
    • 192.168.0.13 with node.js listening on port 3000

HTTPD call to node.js. The return is supposed to be a HTTP 200

<Location /node/>
Require all granted
RequestHeader unset Origin
ProxyPreserveHost On
ProxyPass http://node.mysite.net:3000/node/

Share the entire configuration in working and non-working situations as well as the output of haproxy -vv please.

Sure, here is the configuration. Sorry I wasn’t sure how to extract it from the pfSense box. We have 3 environments DEV, PREPROD and PROD but I kept only the common and production settings. The other two environments have a similar configuration but with different virtual and physical IP addresses.

global
	maxconn			2000
	stats socket /tmp/haproxy.socket level admin  expose-fd listeners
	uid			    80
	gid			    80
	nbproc			1
	nbthread		1
	hard-stop-after	15m
	chroot			/tmp/haproxy_chroot
	daemon
	tune.ssl.default-dh-param	2048
	server-state-file /tmp/haproxy_server_state

listen HAProxyLocalStats
	bind 127.0.0.1:2200 name localstats
	mode http
	stats enable
	stats admin if TRUE
	stats show-legends
	stats uri /haproxy/haproxy_stats.php?haproxystats=1
	timeout client 5000
	timeout connect 5000
	timeout server 5000

frontend PRODWebServerHTTP
	bind			192.168.0.100:7776 name 192.168.0.100:7776   
	mode			http
	log			    global
	option			http-keep-alive
	option			forwardfor
	acl https ssl_fc
	http-request set-header		X-Forwarded-Proto http if !https
	http-request set-header		X-Forwarded-Proto https if https
	timeout client	30000
	default_backend PRODLBWebServerHTTP_ipvANY

frontend PRODWebServerHTTPS
	bind			192.168.0.100:4443 name 192.168.0.100:4443   
	mode			tcp
	log			    global
	timeout client	30000
	default_backend PRODLBWebServerHTTPS_ipvANY

frontend PRODNodeWS
	bind			192.168.0.101:8080 name 192.168.0.101:8080   
	mode			tcp
	log			    global
	timeout client	30000
	default_backend PRODLBNodeWS_ipvANY

frontend PRODNodeEmail
	bind			192.168.0.101:3000 name 192.168.0.101:3000   
	mode			http
	log			    global
	option			http-keep-alive
	option			forwardfor
	acl https ssl_fc
	http-request set-header		X-Forwarded-Proto http if !https
	http-request set-header		X-Forwarded-Proto https if https
	timeout client	30000
	default_backend PRODLBNodeEmail_ipvANY

frontend PRODExtWebServerHTTP
	bind			111.22.333.4:80 name 111.22.333.4:80   
	mode			http
	log			    global
	option			http-keep-alive
	option			forwardfor
	acl https ssl_fc
	http-request set-header		X-Forwarded-Proto http if !https
	http-request set-header		X-Forwarded-Proto https if https
	timeout client	30000
	default_backend PRODLBWebServerHTTP_ipvANY

frontend PRODExtWebServerHTTPS
	bind			111.22.333.4:443 name 111.22.333.4:443   
	mode			tcp
	log			    global
	timeout client	30000
	default_backend PRODLBWebServerHTTPS_ipvANY

backend PRODLBWebServerHTTP_ipvANY
	mode			http
	id			    110
	log			    global
	balance			leastconn
	timeout connect	30000
	timeout server	30000
	retries			3
	server			websrv1 192.168.0.10:7776 id 101 check inter 1000  
	server			websrv2 192.168.0.11:7776 id 101 check inter 1000  

backend PRODLBWebServerHTTPS_ipvANY
	mode			tcp
	id			    111
	log			    global
	tcp-request inspect-delay 5s
	stick-table type binary len 32 size 10m expire 10m
	acl clienthello req.ssl_hello_type 1
	acl serverhello res.ssl_hello_type 2
	tcp-request content accept if clienthello
	tcp-response content accept if serverhello
	stick on payload_lv(43,1) if clienthello
	stick store-response payload_lv(43,1) if serverhello
	balance			leastconn
	timeout connect	30000
	timeout server	30000
	retries			3
	server			websrv1 192.168.0.10:4443 id 101 check inter 1000  
	server			websrv2 192.168.0.11:4443 id 101 check inter 1000  

backend PRODLBNodeWS_ipvANY
	mode			tcp
	id			    112
	log		     	global
	balance			leastconn
	timeout connect	30000
	timeout server	30000
	retries			3
	server			nodesrv1 192.168.0.12:8080 id 101 check inter 1000  
	server			nodesrv2 192.168.0.13:8080 id 102 check inter 1000  

backend PRODLBNodeEmail_ipvANY
	mode			http
	id			    113
	log			    global
	balance			leastconn
	timeout connect	30000
	timeout server	30000
	retries			3
	server			nodesrv1 192.168.0.12:3000 id 101 check inter 1000  
	server			nodesrv2 192.168.0.13:3000 id 102 check inter 1000

Hi again,

One thing maybe worth nothing is that all machines including the pfSense boxes are VirtualBox machines but most of the machines denied promiscuous mode. I set them all to “allow-all” but I am not sure if I should reboot the machines, including the master pfsense or not.

So what exactly is the difference between a working and non-working configuration on haproxy?

The different is the virtual IP being an IP alias (working) or a CARP (not working). Unfortunately I need to enable CARP for the virtual IP addresses to be synchronized with the second pfSense.

So in other words, nothing in the haproxy config changes. 192.168.0.101 would move from an interface alias to a CARP IP.

I would suggest you stop binding to IP addresses, and just bind to the ports instead.

OK. I have 3 external IPs listening on ports 443 and 80 redirecting to 3 sets of backend servers with HTTPD and Node.js. So if I understand correctly you suggest that the HAProxy frontend servers listens on different ports (e.g. 8080, 8081, 8082 for Node.js and another range for HTTPD) and then redirects to the proper ports on the backend servers? I would still need the bind on the external IP:port, correct ?

Something like this perhaps ?!

frontend PRODExtWebServerHTTPS
	bind			111.22.333.4:443 name 111.22.333.4:443   
	mode			tcp
	log			    global
	timeout client	30000
	default_backend PRODLBWebServerHTTPS_ipvANY

frontend PRODNodeWS
    	bind			*:8080 
    	mode			tcp
    	log			    global
    	timeout client	30000
    	default_backend PRODLBNodeWS_ipvANY

frontend DEVNodeWS
    	bind			*:8081
    	mode			tcp
    	log			    global
    	timeout client	30000
    	default_backend PRODLBNodeWS_ipvANY

backend PRODLBNodeWS_ipvANY
    	mode			tcp
    	id			    112
    	log		     	global
    	balance			leastconn
    	timeout connect	30000
    	timeout server	30000
    	retries			3
    	server			nodesrv1 192.168.0.16:8080 id 101 check inter 1000  
    	server			nodesrv2 192.168.0.17:8080 id 102 check inter 1000  
        ...