# TCP and UDP Load Balancing with the stream Module — Nginx

Source: https://www.skillbyai.com/en/nginx/l-stream

> Proxy databases, DNS and other non-HTTP protocols.

## Beyond HTTP

The **`stream`** module (included in the official packages) proxies and balances **TCP** and **UDP** traffic: databases (PostgreSQL, MySQL), message brokers, DNS, syslog, game servers, or TLS passthrough to backends that terminate TLS themselves. It lives in its own top-level `stream { }` context, parallel to `http`, with `upstream` and `server` blocks similar to HTTP, but without HTTP features such as locations, headers or caching. It supports round robin, `least_conn`, `hash` and `random` balancing, passive health checks, `proxy_timeout`, connection limits and TLS termination for TCP. With **`ssl_preread`**, NGINX can read the SNI host name from a TLS ClientHello without decrypting it and route connections to different backends by host name. Because stream proxying works at layer 4, the backend sees NGINX's address unless you enable the **PROXY protocol** (`proxy_protocol on;`) and configure the backend to read it.

## Balancing PostgreSQL replicas and routing TLS by SNI

Layer-4 proxying with the stream module.

```nginx
stream {
    upstream pg_replicas {
        least_conn;
        server 10.0.3.11:5432 max_fails=2 fail_timeout=10s;
        server 10.0.3.12:5432 max_fails=2 fail_timeout=10s;
    }
    server {
        listen 5433;                     # read-only traffic
        proxy_pass pg_replicas;
        proxy_connect_timeout 2s;
        proxy_timeout 30m;
    }

    map $ssl_preread_server_name $tls_backend {
        api.example.com   10.0.4.10:443;
        mail.example.com  10.0.4.20:443;
        default           10.0.4.30:443;
    }
    server {
        listen 443;
        ssl_preread on;                  # read SNI without decrypting
        proxy_pass $tls_backend;
    }
}
```

## Long-lived connections need long timeouts

Database and message-broker connections stay open for a long time. The stream `proxy_timeout` (default 10 minutes of inactivity) may cut idle pooled connections; align it with your clients' pool settings.

**Quiz:** Which NGINX context is used to load balance a PostgreSQL TCP service?

- [x] stream
- [ ] http
- [ ] location
- [ ] events

*Answer:* stream. The stream module handles raw TCP and UDP proxying, outside the http context.
