How to Bind Haproxy to All IPv4 and IPv6 Interfaces: A Complete Configuration Guide


2 views

When configuring Haproxy to listen on all network interfaces, you might encounter some unexpected behavior with IPv4 and IPv6 binding. The standard approach using bind :80 might not always work as intended, especially when dealing with dual-stack environments.

The most straightforward way to bind to both IPv4 and IPv6 is:

listen web
  bind :80 v4v6
  bind :::80 v6only

This configuration explicitly creates two separate listeners:

  • A dual-stack listener for IPv4 (and potentially IPv6)
  • An IPv6-only listener on all IPv6 interfaces

The v4v6 parameter tells Haproxy to create a socket that can accept both IPv4 and IPv6 connections, while v6only ensures pure IPv6 binding. This combination guarantees coverage of all possible incoming connections.

For a slightly more concise configuration, you could use:

frontend http-in
  bind :::80
  bind 0.0.0.0:80

However, this doesn't provide exactly the same behavior as the first solution, as it doesn't explicitly handle the dual-stack case.

After applying your configuration, verify it works with:

ss -tulnp | grep haproxy
netstat -tulnp | grep haproxy

You should see both IPv4 and IPv6 listeners on port 80.

When binding to multiple interfaces:

  • Each additional bind statement creates a separate file descriptor
  • Consider connection handling limits in your system
  • Monitor resource usage under load

Binding to all interfaces means your service is accessible from any network:

  • Always implement proper access control lists
  • Consider using firewall rules for additional protection
  • Regularly audit your exposed services

If you encounter problems:

  1. Verify IPv6 is enabled on your system
  2. Check for port conflicts with netstat or ss
  3. Review Haproxy logs for binding errors
  4. Test connectivity from both IPv4 and IPv6 clients

Many sysadmins need HAProxy to simultaneously listen on both IPv4 (0.0.0.0) and IPv6 (::) addresses for maximum compatibility. The naive approach of simply using bind :80 often doesn't work as expected in modern environments.

On Linux systems, when you specify:

bind :80

This actually creates a dual-stack socket by default. However, the behavior differs across:

  • Kernel versions (pre/post 3.9)
  • HAProxy versions (1.5+ vs older)
  • Presence of net.ipv6.bindv6only sysctl

For explicit control across all environments:

frontend web
  bind 0.0.0.0:80
  bind :::80 v6only
  option socket-stats

Key advantages:

  • Clearly separates IPv4 and IPv6 sockets
  • Works predictably across all kernel versions
  • Allows different settings per protocol if needed

When binding multiple ports, use this pattern:

frontend multi_port
  bind 0.0.0.0:80-85
  bind :::80-85 v6only
  mode http

For high-traffic setups:

global
  tune.bufsize 16384
  tune.maxrewrite 1024

frontend https
  bind 0.0.0.0:443 ssl crt /etc/ssl/certs/
  bind :::443 v6only ssl crt /etc/ssl/certs/
  tcp-request inspect-delay 5s

Verify your bindings with:

ss -tulnp | grep haproxy
netstat -tulnp | grep haproxy # on older systems

Expected output should show both:

tcp   0   0 0.0.0.0:80    0.0.0.0:*    LISTEN
tcp   0   0 :::80         :::*         LISTEN