Nginx Tcp Stream

Published
Length
3 min read

Luis Felipe Dias

All posts

You set up an nginx tcp stream by adding a stream block to your main settings file. This block tells the server to forward raw network packets to an upstream backend group. Engineering teams use this method to route database traffic through a single network entry point. Still, network routing alone gives everyone on that network path full reach to the database port. If an engineer holds broad database roles, the network router will not stop a bad query. How an nginx tcp stream routes network t

NGINX Security Configuration: the complete guide

Architecture patterns, implementation strategies, and security best practices. Delivered to your inbox.

Free white paper. No spam. Unsubscribe anytime.

You set up an nginx tcp stream by adding a stream block to your main settings file. This block tells the server to forward raw network packets to an upstream backend group. Engineering teams use this method to route database traffic through a single network entry point. Still, network routing alone gives everyone on that network path full reach to the database port. If an engineer holds broad database roles, the network router will not stop a bad query.

How an nginx tcp stream routes network traffic

Standard web routing looks at web headers, paths, and cookies at the app layer. Raw stream routing works lower down at the transport layer. When a client opens a socket, the server accepts the link on a set port. It then opens a matching link to one of your backend servers.

You define an upstream group that lists the private IP addresses of your internal servers. You also pick a load balancing rule, such as round robin or least active links. The server then copies bytes back and forth between the client and the chosen backend. It does not read the database wire format or the commands inside the packets.

Teams also use the stream module to handle TLS handshakes at the network edge. The server can read a client certificate or pass encrypted bytes straight through using server name data. You can also set basic IP allow rules to block unknown outside networks. Once the network check passes, the stream keeps the session active until the client or server closes it.

What transport routing solves and what it misses

A transport router solves a core network problem for platform teams. It hides private server IP addresses behind a single stable address and port. It spreads network load across read replicas and drops dead nodes when health checks fail. Network logs also record the client IP, the byte count, and how long the link lasted.

Yet transport routing knows nothing about who the user is or what they run. Because the router only moves raw bytes, all users share the same network path. Once a developer logs in with a shared database user, the router cannot inspect their commands. It cannot tell a safe read query from a command that drops a table.

NGINX Security Configuration: architecture patterns and best practices

Continue reading? Get the full guide.

Free. No spam. Unsubscribe anytime.

This leaves a wide gap during daily work and live incident fixes. Network logs show that an IP sent ten kilobytes of data over five minutes. They do not show which engineer ran a query or what rows returned. Also, raw byte forwarding cannot rewrite sensitive fields like emails, phone numbers, or card numbers in results.

Why network rules and database roles fall short

Teams often try to close this gap by mixing IP allow lists with database roles. They lock the stream port to a VPN address and create read or write accounts. In practice, VPN users all share the same source IP range when they reach the server. That makes IP rules useless for telling one engineer apart from another.

Database roles are also hard to keep tight across dozens of backend instances. Engineers often need temporary write rights to fix a broken record in production. Granting a broad role for an hour often turns into permanent standing permissions. Meanwhile, the transport layer keeps passing every packet without checking the actual command inside.

Govern statements and responses across databases and APIs

Good config and scoped roles are needed setup. They do not check single queries in flight or mask sensitive fields in returned rows. Across Postgres, MySQL, SQL Server, MongoDB, ClickHouse, Kubernetes APIs, SSH, and internal HTTP endpoints, hoop.dev runs beside each supported service as an open-source proxy, a sidecar for your database or API.

First, hoop.dev guardrails block banned queries before they run. Then hoop.dev data masking rewrites matched sensitive values in responses in memory. The audit trail records every statement and verdict per resource. Furthermore, hoop.dev holds SOC 2 Type II and is open source on GitHub.

Frequently asked questions

Where does the stream block go in the settings file?

Place the stream block at the top level of your main settings file. It sits alongside the main web block, never inside it, because they handle different network layers.

Can a stream server route multiple databases on one port?

Yes, if the traffic uses TLS and sends a server name during the handshake. The router reads that server name without decrypting the traffic and picks the right backend.

Does a transport stream log the SQL queries that users run?

No, a transport stream only logs network metadata like IP addresses, timestamps, and byte counts. It does not parse database wire protocols, so individual SQL statements never appear in stream logs.

Save the open-source gateway.

hoop is MIT-licensed infrastructure for controlling how AI agents reach production data. Star hoophq/hoop so you can inspect it, deploy it, or share it when your team starts governing agent access.