Ensure that HAProxy can assign a non-local IP address.

You can listen on every address, but this is not is always suitable when using VPN, floating ip, dedicated interface, or any combination of these.

By default service cannot bind to a non-local IP address.

$ sudo journalctl --unit haproxy
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 systemd[1]: Starting HAProxy Load Balancer...
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 haproxy[1753889]: [NOTICE]   (1753889) : haproxy version is 2.4.18-0ubuntu1
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 haproxy[1753889]: [NOTICE]   (1753889) : path to executable is /usr/sbin/haproxy
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 haproxy[1753889]: [ALERT]    (1753889) : Starting frontend http_frontend: cannot bind socket (Cannot assign requested address) [192.0.2.100:80]
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 haproxy[1753889]: [ALERT]    (1753889) : [/usr/sbin/haproxy.main()] Some protocols failed to start their listeners! Exiting.
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 systemd[1]: haproxy.service: Main process exited, code=exited, status=1/FAILURE
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 systemd[1]: haproxy.service: Failed with result 'exit-code'.
Oct 03 00:37:10 milosz-IdeaCentre-5-14IOB6 systemd[1]: Failed to start HAProxy Load Balancer.

Sample HAProxy service configuration to illustrate this issue.

$ cat /etc/haproxy/haproxy.cfg 
global
	log /dev/log	local0
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
	stats timeout 30s
	user haproxy
	group haproxy
	daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
	log	global
	mode	http
	option	httplog
	option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http

frontend http_frontend
        mode http
        bind 192.0.2.100:80

        default_backend backend

backend backend
        http-request return status 200 content-type "text/plain" string "OK" 

By default it will not start as it cannot assign requested address, because it is not configured on any interface.

$ sudo haproxy -f /etc/haproxy/haproxy.cfg 
[NOTICE]   (1753706) : haproxy version is 2.4.18-0ubuntu1
[NOTICE]   (1753706) : path to executable is /usr/sbin/haproxy
[ALERT]    (1753706) : Starting frontend http_frontend: cannot bind socket (Cannot assign requested address) [192.0.2.100:80]
[ALERT]    (1753706) : [haproxy.main()] Some protocols failed to start their listeners! Exiting.

Inspect sysctl configuration related to this behavior.

$ sysctl --all --pattern ip_nonlocal_bind
net.ipv4.ip_nonlocal_bind = 0
net.ipv6.ip_nonlocal_bind = 0

Allow processes to bind to a non-local IPv4 and IPv6 addresses.

$ sudo sysctl --write net.ipv4.ip_nonlocal_bind=1 net.ipv6.ip_nonlocal_bind=1
net.ipv4.ip_nonlocal_bind = 1
net.ipv6.ip_nonlocal_bind = 1

Now service will work as expected.

$ sudo systemctl start haproxy
$ sudo systemctl status haproxy
* haproxy.service - HAProxy Load Balancer
     Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2022-10-03 00:41:56 CEST; 4s ago
       Docs: man:haproxy(1)
             file:/usr/share/doc/haproxy/configuration.txt.gz
    Process: 1755313 ExecStartPre=/usr/sbin/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS)
   Main PID: 1755315 (haproxy)
      Tasks: 9 (limit: 38126)
     Memory: 71.1M
        CPU: 115ms
     CGroup: /system.slice/haproxy.service
             |-1755315 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
             `-1755317 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock

Oct 03 00:41:56 milosz-IdeaCentre-5-14IOB6 systemd[1]: Starting HAProxy Load Balancer...
Oct 03 00:41:56 milosz-IdeaCentre-5-14IOB6 haproxy[1755315]: [NOTICE]   (1755315) : New worker #1 (1755317) forked
Oct 03 00:41:56 milosz-IdeaCentre-5-14IOB6 systemd[1]: Started HAProxy Load Balancer.

Ensure that configuration will be applied at boot.

$ echo "net.ipv4.ip_nonlocal_bind = 1 | sudo tee /etc/sysctl.d/90-ipv4_nonlocal_bind.conf
$ echo "net.ipv6.ip_nonlocal_bind = 1 | sudo tee /etc/sysctl.d/90-ipv6_nonlocal_bind.conf

Simple as that.

ko-fi