This episode takes HAProxy down to layer 4: TCP mode for proxying raw protocols like databases and gRPC, the fundamental differences from HTTP mode, and SNI inspection and TLS passthrough for routing without reading traffic contents.

Not every service speaks HTTP. Databases, Redis, memcached, and many legacy protocols need a proxy that doesn't interfere with the byte contents. That's what HAProxy's very capable TCP mode is for.
Episode 12 dissects TCP mode: how it differs from HTTP, how to proxy raw services, and how SNI inspection enables domain-name-based routing without opening encrypted data. These capabilities let HAProxy serve almost any protocol.
A quick comparison to remember:
The main decision is simple: if you don't need to see the protocol contents, use TCP. It's faster and safer because it doesn't interpret data.
In TCP mode, HTTP-dependent features aren't available:
http-request, no path-based use_backend, no header rewriting.src, not cookies.frontend redis_front
bind *:6379
mode tcp
default_backend redis_back
backend redis_back
balance leastconn
server redis1 10.0.0.21:6379 check
server redis2 10.0.0.22:6379 checkThe mode tcp directive in both sections indicates raw byte forwarding. The default TCP health check just opens a connection and closes it again.
Databases are the most common example. Client applications connect to HAProxy, then the connection is forwarded to the primary and replicas:
frontend pg_front
bind *:5432
mode tcp
default_backend pg_back
backend pg_back
balance source
option tcp-check
tcp-check connect
tcp-check send "select 1;\n"
tcp-check expect string "1"
server pg1 10.0.0.31:5432 check
server pg2 10.0.0.32:5432 checkoption tcp-check enables layered TCP health checks: HAProxy sends select 1; and expects an answer containing 1. This is a much more meaningful health check than merely opening a connection.
For Redis, use leastconn so long-held connections don't pile up on one server:
backend redis_back
balance leastconn
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
server redis1 10.0.0.41:6379 check
server redis2 10.0.0.42:6379 checktcp-check send PING\r\n and tcp-check expect string +PONG verify that Redis really responds before it's considered healthy.
If you don't need service-method-based routing, gRPC can be proxied purely at layer 4 with HTTP/2 multiplexing forwarded as-is:
frontend grpc_front
bind *:8443
mode tcp
default_backend grpc_back
backend grpc_back
balance leastconn
server grpc1 10.0.0.51:8443 check
server grpc2 10.0.0.52:8443 checkTCP mode keeps the HTTP/2 connection intact from client to server. There's no buffering or interpretation that could interfere with the streams.
TLS passthrough means HAProxy doesn't terminate encryption: the TLS handshake happens directly between the client and the backend. HAProxy only sees the unencrypted part, namely the server name in the handshake (SNI).
The benefits: private keys never live on HAProxy, and traffic stays encrypted end-to-end.
SNI is inspected in TCP mode to choose the backend:
frontend tls_front
bind *:443
mode tcp
acl sni_db req.ssl_sni -i db.example.com
acl sni_app req.ssl_sni -i app.example.com
use_backend db_back if sni_db
use_backend app_back if sni_app
default_backend app_back
backend db_back
server db1 10.0.0.61:443 check
backend app_back
server app1 10.0.0.62:443 checkacl sni_db req.ssl_sni -i db.example.com matches the server name requested by the client. Make sure the frontend enables SNI parsing with accept-proxy or simply in TCP mode, then use_backend db_back if sni_db routes the traffic.
openssl s_client -connect localhost:443 -servername db.example.com \
</dev/null 2>/dev/null | openssl x509 -noout -subjectopenssl s_client -connect localhost:443 -servername db.example.com opens a TLS handshake with a specific SNI. If routing is correct, the certificate returned should belong to the database backend.
A practical guide:
Many architectures mix both: termination at the edge for the web, passthrough for internal services.
nc -zv localhost 6379nc -zv localhost 6379 tests whether the TCP port is open. If the connection succeeds, TCP mode is working; then test the protocol directly with the respective clients.
Episode 12 opens the world of layer 4: TCP mode for raw protocols, protocol-based health checks with tcp-check, and SNI and TLS passthrough for secure, efficient routing.
Key takeaways:
mode tcp forwards bytes; mode http understands protocol contents.option tcp-check for meaningful health checks.balance leastconn for long-lived connections like Redis and gRPC.req.ssl_sni enables domain-name-based routing without opening contents.In the next episode we'll cover high availability & clustering — active/passive setups with VRRP and Keepalived, service discovery integration like Consul and DNS, and testing failover and recovery.