While HTTP load balancing gets most of the attention, many critical services operate at the TCP layer — databases, message queues, game servers, and custom protocols. When you need to distribute raw TCP traffic across backend servers without inspecting the application payload, three open-source tools stand out: HAProxy TCP mode, Nginx stream module, and Envoy TCP proxy.
This guide compares all three for TCP-only load balancing scenarios, covering performance, configuration, health checking, and Docker deployment to help you build a reliable layer 4 load balancing infrastructure.
Why Layer 4 (TCP) Load Balancing Matters
Layer 4 load balancers operate at the transport layer, forwarding TCP connections without parsing the application protocol. This approach offers several advantages over layer 7 (HTTP) load balancing:
- Protocol agnostic: Works with any TCP-based service — MySQL, Redis, PostgreSQL, gRPC, custom protocols
- Lower latency: No HTTP parsing overhead — direct TCP connection forwarding
- TLS passthrough: Backend servers handle encryption; the load balancer sees only encrypted bytes
- Simpler configuration: No need to understand application-specific headers or routing rules
For self-hosted infrastructure, TCP load balancing is essential for database clusters, cache pools, and any service that uses a custom TCP protocol.
Tool Comparison
| Feature | HAProxy TCP Mode | Nginx Stream | Envoy TCP Proxy |
|---|---|---|---|
| GitHub Stars | 6,553 | Part of Nginx (21,000+) | 24,000+ |
| TCP Proxy Support | Native (primary mode) | Via stream module | Native listener filter |
| Health Checks | TCP check, HTTP check, custom | TCP check | TCP, HTTP, gRPC, Redis, custom |
| Load Algorithms | Round-robin, leastconn, source, uri, hdr | Round-robin, leastconn, ip_hash | Round-robin, least_request, ring_hash, maglev |
| Connection Limits | Per-backend, per-server | Per-server | Per-cluster, per-endpoint |
| Rate Limiting | Stick tables, counters | limit_conn, limit_req | Local rate limit, global rate limit service |
| TLS Passthrough | Yes (SNI-based routing) | Yes (SNI-based routing) | Yes (via filter chain) |
| Observability | Stats page, Prometheus export | stub_status, third-party exporters | Built-in stats, Prometheus, tracing |
| Dynamic Config | Runtime API (HAProxy 2.0+) | Requires reload | xDS API (dynamic, no restart) |
| Configuration Style | Declarative (haproxy.cfg) | Declarative (nginx.conf) | Declarative + API (xDS) |
| License | GPL v2 | BSD 2-Clause | Apache 2.0 |
HAProxy TCP Mode: The Dedicated Load Balancer
HAProxy was built specifically as a load balancer and reverse proxy. Its TCP mode provides mature, battle-tested layer 4 load balancing with extensive configuration options.
Strengths:
- Best-in-class health checking — TCP, HTTP, SMTP, LDAP, MySQL, and custom checks
- Runtime API for dynamic configuration changes without restart
- Stick tables for connection persistence and rate limiting
- Extremely low memory footprint — handles 100K+ concurrent connections
- Mature ecosystem with extensive documentation and community
- Dedicated TCP proxy mode — this is HAProxy’s native strength
Weaknesses:
- Configuration reload requires a brief transition period
- No built-in service discovery (requires external scripts or HAProxy Enterprise)
- Steeper learning curve for advanced features
- Stats interface is functional but dated
Installation:
| |
Docker Compose deployment:
| |
HAProxy TCP configuration:
| |
Nginx Stream Module: The Versatile Proxy
Nginx’s stream module adds layer 4 load balancing capabilities to the already popular web server. If you already run Nginx for HTTP traffic, adding TCP proxying is straightforward.
Strengths:
- Unified configuration with HTTP proxy — one tool for both layers
- Excellent performance — event-driven architecture
- SNI-based TLS routing without decrypting traffic
- IP-based connection limiting
- Familiar configuration syntax for existing Nginx users
Weaknesses:
- Health checks require Nginx Plus (commercial) or third-party modules
- Configuration changes require full reload (not graceful for TCP)
- Less granular TCP control compared to HAProxy
- Fewer load balancing algorithms than HAProxy
Installation:
| |
Docker Compose deployment:
| |
Nginx stream configuration:
| |
Envoy TCP Proxy: The Dynamic Modern Option
Envoy’s TCP proxy filter provides layer 4 load balancing as part of its broader service mesh capabilities. It excels in dynamic environments where backend endpoints change frequently.
Strengths:
- Dynamic configuration via xDS API — no restarts needed for backend changes
- Extensive observability — built-in Prometheus metrics, distributed tracing
- Advanced load balancing — ring hash, maglev, weighted round-robin
- Filter chain architecture — composable TCP processing pipeline
- Native integration with Kubernetes and service mesh ecosystems
- Excellent for multi-tenant environments
Weaknesses:
- Steeper learning curve — xDS API and protobuf configuration
- Higher resource usage than HAProxy or Nginx
- Complex setup for simple use cases
- Configuration can be verbose compared to declarative config files
Installation:
| |
Docker Compose deployment:
| |
Envoy TCP proxy configuration:
| |
Performance and Resource Usage
| Metric | HAProxy | Nginx Stream | Envoy |
|---|---|---|---|
| Memory per 10K connections | ~50 MB | ~40 MB | ~120 MB |
| CPU overhead (idle) | Minimal | Minimal | Moderate |
| Throughput (connections/sec) | 200K+ | 150K+ | 100K+ |
| Config reload time | ~0ms (runtime API) | ~100ms (graceful) | ~0ms (xDS) |
| Startup time | Instant | Instant | ~1-2s |
When to Choose Each Tool
Choose HAProxy TCP mode when:
- You need the most mature and battle-tested TCP load balancer
- Advanced health checks are critical (MySQL, SMTP, LDAP, custom protocols)
- You want runtime configuration changes without restarts
- You need connection persistence via stick tables
- Your primary workload is load balancing (not HTTP serving)
Choose Nginx stream when:
- You already run Nginx and want to add TCP proxying without new infrastructure
- Your TCP load balancing needs are straightforward (round-robin, least connections)
- You want unified HTTP and TCP configuration in a single tool
- You value simplicity and minimal configuration complexity
Choose Envoy TCP proxy when:
- You run Kubernetes or a service mesh and want consistent load balancing
- Backend endpoints change dynamically and you need zero-downtime updates
- You need advanced load balancing algorithms (ring hash, maglev)
- Built-in observability and distributed tracing are important
- You are building a multi-tenant platform with per-tenant TCP routing
Why Self-Host Your TCP Load Balancer?
Running your own layer 4 load balancer gives you complete visibility into connection patterns, latency distributions, and backend health. Commercial load balancers often abstract away these details, making it harder to debug connection issues or optimize traffic distribution.
Self-hosted TCP load balancers integrate seamlessly with self-hosted backend services. Pair HAProxy or Nginx stream with your self-hosted database clusters, message queues, and application servers for a fully self-contained infrastructure stack. For related load balancing guides, see our DNS failover with Keepalived and PowerDNS and bare metal Kubernetes load balancing.
Cost savings are substantial. Hardware load balancers from F5 or Citrix cost $10,000-$50,000 plus annual support contracts. HAProxy, Nginx stream, and Envoy are free and run on commodity hardware. Even for high-traffic deployments, a single commodity server with HAProxy can handle more connections than entry-level hardware appliances.
Self-hosting also eliminates vendor lock-in. Your load balancing configuration is stored in plain text files or version-controlled YAML, making it portable across environments. When you need to replicate your load balancing setup across data centers or cloud providers, the same configuration works everywhere without licensing complications.
If you are also configuring SNI-based TLS routing for your TCP services, our SNI proxy comparison covers tools that route encrypted traffic based on the TLS Server Name Indication extension.
FAQ
What is the difference between layer 4 and layer 7 load balancing?
Layer 4 (TCP) load balancers forward connections based on IP addresses and port numbers without inspecting the application data. Layer 7 (HTTP) load balancers parse HTTP headers and can route based on URL paths, hostnames, cookies, and content. Use layer 4 for database and cache traffic, layer 7 for web applications.
Can HAProxy do both TCP and HTTP load balancing?
Yes. HAProxy supports both modes simultaneously. Use mode tcp for TCP proxying and mode http for HTTP load balancing in the same configuration file. You can even mix modes across different frontend/backend pairs.
Does Nginx stream support health checks?
The open-source version of Nginx has basic passive health checking (marks servers as down after connection failures). Active health checks require Nginx Plus (commercial) or third-party modules like nginx_upstream_check.
Which tool has the best health checking?
HAProxy has the most comprehensive health check options, supporting TCP, HTTP, SMTP, LDAP, MySQL, and custom check scripts. Envoy also supports a wide range including TCP, HTTP, gRPC, and Redis checks. Nginx stream has the most limited options in its open-source version.
Can I use these tools for TLS passthrough?
Yes. All three support TLS passthrough, where encrypted traffic is forwarded to backend servers without decryption. Both HAProxy and Nginx support SNI-based routing even in passthrough mode, allowing you to route to different backends based on the requested hostname.
How do I monitor TCP load balancer performance?
HAProxy provides a built-in stats page (HTTP) and Prometheus export. Nginx stream logs connection metrics that can be parsed with log analyzers. Envoy has the most comprehensive built-in metrics, including connection counts, byte rates, and per-endpoint health status — all exportable to Prometheus.
Can I run multiple TCP load balancers for high availability?
Yes. Deploy two or more load balancer instances with keepalived (VRRP) or a DNS-based failover mechanism. For Kubernetes deployments, use a Service of type LoadBalancer to distribute traffic across Envoy or Nginx pods.