TCP services such as databases, message queues, SSH gateways, and custom daemons need HAProxy to forward byte streams without trying to parse HTTP headers. A listener that accidentally inherits HTTP mode can break non-HTTP traffic, while an unchecked backend pool can keep sending clients to a closed port.

TCP mode keeps the frontend and backend at Layer 4. The frontend binds the address and port clients use, the backend lists the service nodes, the balance directive chooses a destination for each connection, and a check argument on each server line removes a failed node from rotation when the TCP check cannot connect.

The example below uses roundrobin so repeated test connections visibly reach more than one backend. For long-lived database or queue sessions, leastconn may fit better because new clients go to the server with fewer active connections. Use the service's native client for final validation when nc cannot complete the protocol handshake.

Steps to configure HAProxy TCP load balancing:

  1. Confirm the listener port, backend server addresses, and protocol-specific client test before editing HAProxy.
  2. Back up the active HAProxy configuration file.
    $ sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.before-tcp-lb
  3. Open the HAProxy configuration file.
    $ sudoedit /etc/haproxy/haproxy.cfg
  4. Add a TCP frontend and backend for the service.
    frontend tcp_service
        bind *:5000
        mode tcp
        timeout client 30s
        default_backend tcp_service_nodes
    
    backend tcp_service_nodes
        mode tcp
        balance roundrobin
        option tcp-check
        tcp-check connect
        timeout connect 5s
        timeout server 30s
        server tcp-a 10.0.10.11:5000 check
        server tcp-b 10.0.10.12:5000 check

    Replace the listener port, backend IP addresses, and backend port with the real service values. Keep mode tcp in both sections when existing defaults use HTTP mode.

  5. Validate the complete HAProxy configuration before applying it.
    $ sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg
    Configuration file is valid

    The -V flag prints the success line. On current Ubuntu packages, sudo haproxy -c -f /etc/haproxy/haproxy.cfg can exit successfully without output.

  6. Reload HAProxy after the configuration validates.
    $ sudo systemctl reload haproxy

    The packaged systemd unit on current Ubuntu systems validates the configured file before sending the reload signal, but running the manual check first keeps failures visible before the service action.

  7. Open two client connections through the HAProxy listener.
    $ nc -w 2 proxy.example.net 5000
    backend=tcp-a
    $ nc -w 2 proxy.example.net 5000
    backend=tcp-b

    A banner or echo-style test service can show the backend name directly. For databases, queues, SSH, or TLS-wrapped TCP services, use the matching client command and confirm the response comes through the proxy address.

  8. Test a planned backend outage during a maintenance window.

    Stop one backend service or block its service port, wait for the configured health check to mark it down, and confirm new client connections continue through the remaining backend.