Nginx | stream content 阶段:UDP 协议四层反向代理浅析与实践

知识是人生的灯塔,只有不断学习,才能照亮前行的道路

📢 大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 🚀,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路 😋 。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_t5z28zcqv7us.html

实践:使用 Proxy 模块进行 UDP 四层反向代理

描述:上文介绍了 TCP 四层反向代理,虽然 TCP 提供可靠传输,适用于数据完整性要求高的场景,但在某些特定情况下,UDP协议可能更适合。例如,在某些实时通信应用中(如音视频会议、在线游戏等)等对数据完整性要求不高,因为 UDP 协议头部开销小,无需重传机制、延迟更低等特点,在以及高吞吐量场景下非常有用。

◆ UDP 反向代理原理

它使用 session 机制,当客户端发送报文时使用源端口 (Source Port),该端口用于接收服务器响应,源端口与目标端口构成一个会话,而 Nginx 作为反向代理需维护此 session 信息以正确转发响应,另外同一 session 中 Nginx 始终使用同一个端口(如 C)连接到上游服务,大致流程如下:

  • • 1.客户端从端口 A 向服务器端口 B 发送请求。

  • • 2.Nginx 接收到请求后,根据 proxy_pass 指令选择上游服务,进行转发。

  • • 3.Nginx 为此次转发选择随机端口 C,并将请求转发至上游服务 D 端口。

  • • 4.上游服务响应时,目标地址为 Nginx 的 C 端口。

  • • 5.Nginx 收到响应后,将其转发回客户端的 A 端口。

weiyigeek.top-UDP反向代理流程图

◆ 指令参数

在 stream proxy 模块中,有如下两个指令参数,主要应用在 UDP 协议用于控制 session 的行为,另外由 proxy_timeout 参数控制超时时间,在有效期内若上游服务未正常响应,可判定其不可用并剔除。

  • proxy_requests 定义在一个 session 中从客户端接收多少个请求报文后视为 session 结束。
go 复制代码
Syntax: proxy_requests number;
Default: proxy_requests 0;
Context: stream, server
  • proxy_responses 定义每个请求期望上游返回的响应数量。
go 复制代码
Syntax: proxy_responses number;
Default: ---
Context: stream, server

温馨提示:只要在 session 结束后才记录一条 access 日志,因此,在 UDP 反向代理中,access 日志记录的请求数量可能与实际接收到的报文数量不一致。

◆ 示例演示

目的:使用 Stream Proxy 模块进行 UDP 四层反向代理,演示 proxy_requestsproxy_responses 指令的使用过程,以及反向代理内部 DNS s上游服务器的配置。

步骤 01.使用 Python3 分别在 213、214 主机上,运行 UDP 服务以及客户端,客户端发送什么数据,服务端就返回什么数据,并按照请求次序返回其序号。

go 复制代码
# 脚本示例
tee udp_tool.py  << 'EOF'
#!/usr/bin/env python3
"""
UDP 工具: udp_tool.py
使用方式:
  作为服务器: python3 udp_tool.py server <IP> <端口>
  作为客户端: python3 udp_tool.py client <IP> <端口>
"""
import socket
import sys
import threading

# 全局请求计数器
request_count = 0

def run_server(host, port):
"""运行服务器"""
    global request_count

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((host, port))

print(f"服务器启动在 {host}:{port}")
print("等待客户端数据...")

    try:
while True:
            data, addr = sock.recvfrom(1024)
            request_count += 1

            message = data.decode('utf-8', errors='ignore')
print(f"请求#{request_count} 来自 {addr}: {message}")

            response = f"[请求#{request_count}] {message}"
            sock.sendto(response.encode('utf-8'), addr)
    except KeyboardInterrupt:
print("\n服务器停止")
    finally:
        sock.close()

def run_client(server_ip, server_port):
"""运行客户端"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

print(f"连接到服务器 {server_ip}:{server_port}")
print("输入消息(输入 'exit' 退出):")

    try:
while True:
            message = input("> ")
if message.lower() == 'exit':
break

            sock.sendto(message.encode('utf-8'), (server_ip, server_port))
            sock.settimeout(2.0)

            try:
                data, _ = sock.recvfrom(1024)
print(f"服务器响应: {data.decode('utf-8')}")
            except socket.timeout:
print("超时: 无响应")
    except KeyboardInterrupt:
print("\n客户端停止")
    finally:
        sock.close()

def main():
if len(sys.argv) < 4:
print("UDP 工具")
print("用法:")
print("  作为服务器: python3 udp_tool.py server <IP> <端口>")
print("  作为客户端: python3 udp_tool.py client <服务器IP> <端口>")
print("\n示例:")
print("  启动服务器: python3 udp_tool.py server 0.0.0.0 9999")
print("  启动客户端: python3 udp_tool.py client 127.0.0.1 9999")
        sys.exit(1)

    mode = sys.argv[1].lower()
    ip = sys.argv[2]
    port = int(sys.argv[3])

if mode == 'server':
        run_server(ip, port)
elif mode == 'client':
        run_client(ip, port)
else:
print("错误: 模式必须是 'server' 或 'client'")
        sys.exit(1)

if __name__ == "__main__":
    main()
EOF

步骤 02.在 213 主机中执行 python3 udp_tool.py server 0.0.0.0 9999,在 214 主机(Nginx 代理服务器)上执行 python3 udp_tool.py client 10.20.172.213 9999,测试脚本,运行效果如图下所示。

go 复制代码
# Server
$ python3 udp_tool.py server 0.0.0.0 9999

# Client
$ python3 udp_tool.py client 10.20.172.213 9999
连接到服务器 10.20.172.213:9999
输入消息(输入 'exit' 退出):
> WeiyiGeek
服务器响应: [请求#1] WeiyiGeek
> 公众号:全栈工程师修炼指南
服务器响应: [请求#2] 公众号:全栈工程师修炼指南
> blog.weiyigeek.top
服务器响应: [请求#3] blog.weiyigeek.top

weiyigeek.top-验证udp_tool.py脚本图

步骤 03.在 Nginx 中配置 UDP 四层反向代理,并测试 proxy_requestsproxy_responses 效果。

go 复制代码
tee /usr/local/nginx/conf/nginx.conf << 'EOF'
worker_processes auto;
events {
  worker_connections  1024;
}

# stream 模块配置块
stream {
# 定义一个日志模式格式。
  log_format basic '$remote_addr:$remote_port "$realip_remote_addr:$realip_remote_port" [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';

# 开启日志文件描述符缓存,减少打开和关闭文件的开销
# open_log_file_cache max=1000 inactive=60s min_uses=2 valid=1m;

# 开启访问日志记录,注意这里为了测试未启用缓存,生产环境中推荐使用缓存。
  error_log  /var/log/nginx/logs/stream_error.log debug;
  access_log /var/log/nginx/logs/stream_access.log basic;

# 定义一个四层UDP服务
  server {
# 监听 5353 端口
    listen 5353 udp;

# 设置可信客户端IP地址,即真实地址将排除下述IP或IP段的地址。
    set_real_ip_from 127.0.0.1;

# 设置 proxy_timeout 指令,设置代理超时时间。
    proxy_timeout 10s;

# 设置期望上游处理的请求数量,此处设置为1。
    proxy_requests 1;

# 设置期望上游返回的响应数量,此处设置为1。
    proxy_responses 1;

# 设置反向代理上游服务器
    proxy_pass 10.20.172.213:9999;
  }
}
EOF

步骤 04.重启 Nginx 服务,使用 214 主机 5353 端口,测试 UDP 反向代理效果。

go 复制代码
# 重启 Nginx 服务
nginx -s reload

# 测试反向代理
python3 udp_tool.py client 10.20.172.214 5353
Stream Proxy UDP
全栈工程师修炼指南
https://blog.weiyigeek.top

# Nginx 访问日志记录
$ tail -f stream_access.log
10.20.172.214:36869 "10.20.172.214:36869" [31/Jan/2026:15:07:30 +0800] UDP 200 27 16 0.001
10.20.172.214:36869 "10.20.172.214:36869" [31/Jan/2026:15:07:33 +0800] UDP 200 38 27 0.001
10.20.172.214:36869 "10.20.172.214:36869" [31/Jan/2026:15:07:35 +0800] UDP 200 37 26 0.001

weiyigeek.top-UDP反向代理测试图

步骤 05.作者在内网中使用 coredns 搭建了一个 DNS 服务,现通过 Nginx 反向代理该域名解析服务器,测试 DNS 服务是否正常。

go 复制代码
tee /usr/local/nginx/conf/nginx.conf << 'EOF'
worker_processes auto;
events {
  worker_connections  1024;
}

# stream 模块配置块
stream {
# 定义一个日志模式格式。
  log_format basic '$remote_addr:$remote_port "$realip_remote_addr:$realip_remote_port" [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';

# 开启日志文件描述符缓存,减少打开和关闭文件的开销
# open_log_file_cache max=1000 inactive=60s min_uses=2 valid=1m;

# 开启访问日志记录,注意这里为了测试未启用缓存,生产环境中推荐使用缓存。
  error_log  /var/log/nginx/logs/stream_error.log debug;
  access_log /var/log/nginx/logs/stream_access.log basic;

# 定义一个四层UDP服务
  server {
# 监听 5353 端口
    listen 5353 udp;

# 设置可信客户端IP地址,即真实地址将排除下述IP或IP段的地址。
    set_real_ip_from 127.0.0.1;

# 设置 proxy_timeout 指令,设置代理超时时间,超过此时间则断开连接。
    proxy_timeout 2s;

# 设置期望上游处理的请求数量,此处设置为1。
    proxy_requests 1;

# 设置期望上游返回的响应数量,若此处设置为2则待响应数量为2时再将其写入到日志文件中,公用一个session
    proxy_responses 2;

# 设置反向代理上游服务器
    proxy_pass 192.168.10.254:53;
  }
}
EOF

步骤 06.重启 Nginx 服务,使用 dig 工具测试反向代理的 DNS 服务是否正常,由图可知代理的 DNS 服务是正常的,能够解析到作者的博客站点,以及邮箱 mx 等记录

go 复制代码
# 重启 Nginx 服务
nginx -s reload

# 测试反向代理
dig @10.20.172.214 -p 5353 -t a www.weiyigeek.top
dig @10.20.172.214 -p 5353 -t mx weiyigeek.top
dig @10.20.172.214 -p 5353 -t a blog.weiyigeek.top

weiyigeek.top-使用 Nginx 反向代理 DNS 域名服务器图

至此,作者讲解了 Stream Proxy 模块进行 UDP 四层反向代理的原理,实践中利用 proxy_requestsproxy_responsesproxy_timeout 指令可精确控制 UDP session 的行为,另外可基于 session 状态监控上游服务健康状况。

END

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,持续更新包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。

Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?

✅ 将获得作者最新工作学习实践文章以及网盘资源。

✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买)

✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。

✅ 将获得作者远程支持(在作者能力范围内且合规)。

获取:作者工作学习全栈笔记

作者整理了10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者微信或者回复【工作学习实践笔记】,当前价格¥299,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!

知识推荐 往期文章

若文章对你有帮助,请将它转发给更多的看友,若有疑问的小伙伴,可在评论区留言你想法哟 💬!

相关推荐
Leinwin9 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
2401_865382509 小时前
信息化项目运维与运营的区别
运维·运营·信息化项目·政务信息化
漠北的哈士奇9 小时前
VMware Workstation导入ova文件时出现闪退但是没有报错信息
运维·vmware·虚拟机·闪退·ova
如意.7599 小时前
【Linux开发工具实战】Git、GDB与CGDB从入门到精通
linux·运维·git
运维小欣10 小时前
智能体选型实战指南
运维·人工智能
yy552710 小时前
Nginx 性能优化与监控
运维·nginx·性能优化
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ11 小时前
Linux 查询某进程文件所在路径 命令
linux·运维·服务器
05大叔12 小时前
网络基础知识 域名,JSON格式,AI基础
运维·服务器·网络
安当加密12 小时前
无需改 PAM!轻量级 RADIUS + ASP身份认证系统 实现 Linux 登录双因子认证
linux·运维·服务器
我想走路带风12 小时前
c++工具转向网络底层工具
网络