Enabling and Configuring TCP/UDP Proxying with the Nginx Stream Module

Verifying Stream Module Support

The Nginx Stream module operates at Layer 4 (TCP/UDP), allowing for efficient traffic forwarding and load balancing outside of the standard HTTP context. Before attempting configuration, verify if your Nginx binary includes the module by executing the following command:

nginx -V 2>&1 | grep --color -- '--with-stream'

If the output does not contain --with-stream, the module is not active. For users managing Nginx via source compilation, you must include the flag during the configuration stage:

./configure --prefix=/usr/local/nginx --with-stream
make
sudo make install

For users on modern Linux distributions (like Ubuntu or CentOS), the Stream module is often provided as a dynamic module. You may need to install a package like nginx-mod-stream and ensure the module is loaded at the top of you're nginx.conf file:

load_module /usr/lib/nginx/modules/ngx_stream_module.so;

Core Configuration Structure

The stream block resides at the top level of the Nginx configuration, parallel to the http block. It does not support HTTP-specific directives like location or proxy_set_header because it operates on raw data streams.

# Basic structure in nginx.conf
events {
    worker_connections 1024;
}

stream {
    # Define logging for TCP/UDP traffic
    log_format basic_stream '$remote_addr [$time_local] '
                            '$protocol $status $bytes_sent $bytes_received '
                            '$session_time';

    access_log /var/log/nginx/stream_access.log basic_stream;

    # Include external configuration files
    include /etc/nginx/stream.d/*.conf;
}

http {
    # Standard web configuration
}

Implementation Examples

1. Simple TCP Port Forwarding

This configuration maps a local port to a remote database server, such as a MySQL instance. This is useful for creating a gateway into a private network.

# /etc/nginx/stream.d/mysql_proxy.conf
server {
    listen 33060; 
    proxy_connect_timeout 10s;
    proxy_timeout 1m;
    proxy_pass 10.0.5.15:3306;
}

2. UDP Load Balencing with Persistence

UDP services like DNS require specific handling. The reuseport parameter allows multiple worker processes to listen on the same port, improving performance for high-concurrency UDP traffic.

# /etc/nginx/stream.d/dns_lb.conf
upstream dns_resolvers {
    hash $remote_addr consistent;
    server 192.168.1.10:53;
    server 192.168.1.11:53;
}

server {
    listen 53 udp reuseport;
    proxy_pass dns_resolvers;
    proxy_timeout 10s;
    proxy_responses 1;
}

3. High-Availability TCP Cluster

For enterprise applications like Oracle DB or generic TCP socket services, you can define multiple backends with health management.

# /etc/nginx/stream.d/db_cluster.conf
upstream db_backend_pool {
    server node_01.internal:1521 max_fails=3 fail_timeout=30s;
    server node_02.internal:1521 max_fails=3 fail_timeout=30s;
    server backup_node.internal:1521 backup;
}

server {
    listen 1521;
    proxy_pass db_backend_pool;
    proxy_buffer_size 16k;
}

Applying Changes

After modifying the configuration, validate the syntax before reloading the service to ensure no downtime occurs due to configuration errors:

nginx -t
nginx -s reload

Best Practices

  • Timeout Tuning: Unlike HTTP, TCP connections can stay open indefinitely. Explicit define proxy_timeout and proxy_connect_timeout to prevent hung sessions from exhausting worker connections.
  • Security: Since the Stream module exposes raw ports, implement firewall rules (iptables/nftables) to restrict which IP addresses can access these proxy ports.
  • Resource Management: Monitor the worker_connections limit in the events block, as each stream session consumes a connection slot.

Tags: nginx load-balancing tcp-proxy udp-proxy network-administration

Posted on Thu, 06 Aug 2026 16:40:34 +0000 by jbingman