From 9c2c01f2029fdf1c95c4782eff440c08c1e2b057 Mon Sep 17 00:00:00 2001 From: Sebastian Heid <8442432+s4heid@users.noreply.github.com> Date: Thu, 23 Apr 2026 14:32:14 +0200 Subject: [PATCH] feat: bind health-check listeners on `binding_ip` and `v4v6` The four health-check listeners (`health_check_http_url`, its PROXY protocol variant, and the per-tcp-proxy `health_check_http_tcp-` pair) previously bound on `:`, which is IPv4-wildcard only. On IPv6-only deployments (`binding_ip: "::"`) the listeners were unreachable, causing monit host checks against `localhost` (IPv4) to fail and restart HAProxy. Bind them on `ha_proxy.binding_ip` and append `v4v6` like the other frontends so dual-stack works when `ha_proxy.v4v6` is enabled. Behavior change: when `binding_ip` is set to a specific IPv4 address, the health-check listeners now bind only on that address instead of all IPv4 interfaces. Operators probing health via a different NIC must update their probe targets accordingly. Co-authored-by: jakobve <36446012+jakobve@users.noreply.github.com> --- jobs/haproxy/templates/haproxy.config.erb | 8 +-- .../haproxy_config/frontend_tcp_spec.rb | 50 +++++++++++++++++++ .../healthcheck_listener_spec.rb | 31 ++++++++++++ 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/jobs/haproxy/templates/haproxy.config.erb b/jobs/haproxy/templates/haproxy.config.erb index 07c14cf5..a7f1a566 100644 --- a/jobs/haproxy/templates/haproxy.config.erb +++ b/jobs/haproxy/templates/haproxy.config.erb @@ -378,7 +378,7 @@ listen stats <% if p("ha_proxy.enable_health_check_http") %> listen health_check_http_url - bind :<%= p("ha_proxy.health_check_port") %> + bind <%= p("ha_proxy.binding_ip") %>:<%= p("ha_proxy.health_check_port") %> <%= v4v6 %> mode http option httpclose monitor-uri /health @@ -391,7 +391,7 @@ listen health_check_http_url <%- if enable_additional_health_check_proxy -%> listen health_check_http_url_proxy_protocol - bind :<%= p("ha_proxy.health_check_port") + 1 %> accept-proxy + bind <%= p("ha_proxy.binding_ip") %>:<%= p("ha_proxy.health_check_port") + 1 %> accept-proxy <%= v4v6 %> mode http option httpclose monitor-uri /health @@ -1100,7 +1100,7 @@ backend tcp-<%= tcp_proxy["name"] %> <%- if tcp_proxy["health_check_http"] -%> listen health_check_http_tcp-<%= tcp_proxy["name"] %> - bind :<%= tcp_proxy["health_check_http"] %> + bind <%= p("ha_proxy.binding_ip") %>:<%= tcp_proxy["health_check_http"] %> <%= v4v6 %> mode http monitor-uri /health <%- if p("ha_proxy.accept_proxy") && !p("ha_proxy.disable_health_check_proxy") -%> @@ -1111,7 +1111,7 @@ listen health_check_http_tcp-<%= tcp_proxy["name"] %> <%- if enable_additional_health_check_proxy -%> listen health_check_http_tcp-<%= tcp_proxy["name"] %>_proxy_protocol - bind :<%= tcp_proxy["health_check_http"] + 1 %> accept-proxy + bind <%= p("ha_proxy.binding_ip") %>:<%= tcp_proxy["health_check_http"] + 1 %> accept-proxy <%= v4v6 %> mode http monitor-uri /health acl tcp-<%= tcp_proxy["name"] %>-routers_down nbsrv(tcp-<%= tcp_proxy["name"] %>) eq 0 diff --git a/spec/haproxy/templates/haproxy_config/frontend_tcp_spec.rb b/spec/haproxy/templates/haproxy_config/frontend_tcp_spec.rb index ab995fbf..6e91d330 100644 --- a/spec/haproxy/templates/haproxy_config/frontend_tcp_spec.rb +++ b/spec/haproxy/templates/haproxy_config/frontend_tcp_spec.rb @@ -152,4 +152,54 @@ expect(haproxy_conf).not_to have_key(/frontend tcp/) end end + + context 'when a tcp proxy has health_check_http configured' do + let(:default_properties) do + { + 'tcp_link_port' => 5432, + 'tcp' => [{ + 'name' => 'potatoedb', + 'port' => 6379, + 'backend_servers' => ['10.0.0.1', '10.0.0.2'], + 'health_check_http' => 9095 + }] + } + end + + let(:healthcheck_listener) { haproxy_conf['listen health_check_http_tcp-potatoedb'] } + let(:healthcheck_listener_proxy_protocol) { haproxy_conf['listen health_check_http_tcp-potatoedb_proxy_protocol'] } + + it 'binds the tcp health check listener to all interfaces by default' do + expect(healthcheck_listener).to include('bind :9095') + end + + context 'when ha_proxy.binding_ip is provided' do + let(:properties) do + default_properties.merge({ + 'binding_ip' => '1.2.3.4', + 'enable_additional_health_check_proxy' => true + }) + end + + it 'binds the tcp health check listeners to the provided ip' do + expect(healthcheck_listener).to include('bind 1.2.3.4:9095') + expect(healthcheck_listener_proxy_protocol).to include('bind 1.2.3.4:9096 accept-proxy') + end + + context 'when ha_proxy.v4v6 is true and binding_ip is ::' do + let(:properties) do + default_properties.merge({ + 'v4v6' => true, + 'binding_ip' => '::', + 'enable_additional_health_check_proxy' => true + }) + end + + it 'enables ipv6 dual-stack on the tcp health check listeners' do + expect(healthcheck_listener).to include('bind :::9095 v4v6') + expect(healthcheck_listener_proxy_protocol).to include('bind :::9096 accept-proxy v4v6') + end + end + end + end end diff --git a/spec/haproxy/templates/haproxy_config/healthcheck_listener_spec.rb b/spec/haproxy/templates/haproxy_config/healthcheck_listener_spec.rb index aac47595..33c1e8b5 100644 --- a/spec/haproxy/templates/haproxy_config/healthcheck_listener_spec.rb +++ b/spec/haproxy/templates/haproxy_config/healthcheck_listener_spec.rb @@ -130,5 +130,36 @@ end end end + + context 'when ha_proxy.binding_ip is provided' do + let(:properties) do + { + 'enable_health_check_http' => true, + 'enable_additional_health_check_proxy' => true, + 'binding_ip' => '1.2.3.4' + } + end + + it 'binds the health check listeners to the provided ip' do + expect(healthcheck_listener).to include('bind 1.2.3.4:8080') + expect(healthcheck_listener_proxy_protocol).to include('bind 1.2.3.4:8081 accept-proxy') + end + + context 'when ha_proxy.v4v6 is true and binding_ip is ::' do + let(:properties) do + { + 'enable_health_check_http' => true, + 'enable_additional_health_check_proxy' => true, + 'v4v6' => true, + 'binding_ip' => '::' + } + end + + it 'enables ipv6 dual-stack on the health check listeners' do + expect(healthcheck_listener).to include('bind :::8080 v4v6') + expect(healthcheck_listener_proxy_protocol).to include('bind :::8081 accept-proxy v4v6') + end + end + end end end