When working with NGINX's stream module for UDP load balancing, many administrators encounter this configuration error. The message indicates a fundamental misunderstanding about where the stream
directive can be placed in NGINX's configuration hierarchy.
The stream
block must be placed in the main configuration context, not inside http
, server
, or location
blocks. Here's the correct structure:
# Main nginx.conf file should include this at root level
stream {
upstream dns_backend {
server 172.31.9.51:53;
server 172.31.20.140:53;
}
server {
listen 53 udp;
proxy_pass dns_backend;
proxy_timeout 1s;
proxy_responses 1;
}
}
For NGINX versions prior to 1.9.0, you needed to explicitly compile with --with-stream
and --with-stream_udp_module
. Modern versions (including your 1.12.1) include these by default, but it's worth verifying:
nginx -V 2>&1 | grep -o with-stream
Many users make these mistakes:
- Placing stream configuration in
conf.d/
without proper inclusion - Forgetting to specify
udp
in listen directives - Mixing HTTP and stream protocols in the same upstream
Here's a fully functional configuration for UDP load balancing:
# In /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
events {
worker_connections 1024;
}
stream {
log_format basic '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';
access_log /var/log/nginx/stream-access.log basic;
error_log /var/log/nginx/stream-error.log;
upstream game_servers {
hash $remote_addr consistent;
server 10.0.1.1:7777;
server 10.0.1.2:7777;
}
server {
listen 7777 udp;
proxy_pass game_servers;
proxy_timeout 5s;
proxy_responses 1;
}
}
If you still encounter issues:
- Check that the stream module is loaded with
nginx -T | grep stream
- Verify no conflicting directives in included files
- Test configuration with
nginx -t
before restarting
The error message indicates that NGINX is rejecting your stream configuration because it's placed in the wrong context. The stream
block needs to be at the main configuration level, not nested inside other blocks like http
.
For UDP load balancing (like DNS, VoIP, or gaming servers), you need to separate your stream configuration from HTTP configurations:
# In /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
# This is where stream should be declared - at main config level
stream {
include /etc/nginx/conf.d/stream/*.conf;
}
http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Best practice is to create a dedicated directory for stream configurations:
mkdir -p /etc/nginx/conf.d/stream/
mv /etc/nginx/conf.d/load-balancer.conf /etc/nginx/conf.d/stream/
Here's a properly structured configuration for UDP load balancing (example for OpenVPN servers):
# /etc/nginx/conf.d/stream/vpn-balancer.conf
upstream vpn_backend {
hash $remote_addr consistent;
server 172.31.9.51:1194 weight=5;
server 172.31.20.140:1194;
server backup.vpn.example.com:1194 backup;
}
server {
listen 1194 udp reuseport;
proxy_pass vpn_backend;
proxy_timeout 3s;
proxy_responses 0; # For UDP, typically you want 0 responses
}
After making changes, always test:
sudo nginx -t
sudo systemctl restart nginx
netstat -tulnp | grep nginx
- Ensure you have NGINX compiled with stream module (
nginx -V | grep stream
) - Docker users: Need to expose UDP ports explicitly with
-p 1194:1194/udp
- Firewall rules must allow UDP traffic
For high-traffic UDP services:
stream {
proxy_buffer_size 16k;
proxy_udp_buffer_size 16k;
proxy_socket_keepalive on;
server {
listen 53 udp reuseport;
# ...
}
}