nginx stream 模块代理 udp 必须显式声明 udp 协议,如 listen 53 udp;需指定监听地址避免绑定错误;不可混用 tcp/udp 同端口、不可用 http/tls 指令;最小配置需含 proxy_pass、proxy_timeout 和 proxy_responses。

要让 Nginx 的 stream 模块真正支持 UDP 反向代理,listen 指令不是“加上端口就行”,必须显式声明协议类型,否则默认走 TCP,UDP 流量根本不会被接收。
listen 必须带 udp 标识
这是最核心、最容易忽略的一点。正确写法是:
-
listen 53 udp;✅ 明确启用 UDP 协议监听 -
listen 53;❌ 默认为 TCP,UDP 包直接被丢弃 -
listen 53 so_keepalive=on udp;✅ 支持附加 socket 选项,udp 不可省略
即使你只代理 DNS(标准 UDP 53),也必须写全 udp。Nginx 不会自动推断协议类型。
端口与地址绑定需匹配实际网络环境
如果服务器有多个网卡或 IPv4/IPv6 双栈,建议显式指定监听地址,避免仅监听 localhost 或 IPv6 导致客户端连不上:
-
listen 192.168.1.10:53 udp;—— 绑定到内网 IP -
listen [::1]:53 udp;—— 仅本地 IPv6(调试用) -
listen *:53 udp;—— 监听所有 IPv4 接口(生产慎用,配合防火墙) -
listen [::]:53 udp;—— 监听所有 IPv6 接口
混合监听 IPv4/IPv6 需分别写两行,Nginx stream 不支持单行通配双协议。
避免常见 listen 冲突和限制
UDP 是无连接协议,Nginx 的 stream 层不维护会话状态,因此这些配置项不生效,写了反而报错或被忽略:
- 不能用
ssl on、ssl_certificate等 TLS 相关指令(UDP 本身无 TLS 握手概念) - 不能搭配
location、rewrite、if等 HTTP 层指令(stream 层无 request body、header、URI) - 不能复用同一端口同时监听 TCP 和 UDP(如
listen 53+listen 53 udp会冲突),需分开定义两个server块
配合 proxy_* 参数才能真正工作
listen 只是“开门”,转发逻辑靠后续指令驱动。一个可用的最小完整 UDP server 块应包含:
-
listen 53 udp;—— 开门 -
proxy_pass udp_backend;—— 指向 upstream -
proxy_timeout 1s;—— 防止无响应挂起(DNS 典型值) -
proxy_responses 1;—— 控制最多接收几个响应包(对 DNS 查询很关键)
缺少 proxy_timeout 或 proxy_responses,可能导致超时未释放连接资源,或收到多个响应时行为不可控。











