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,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!

知识推荐 往期文章

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

相关推荐
Lsir10110_5 小时前
【Linux】进程信号(上半)
linux·运维·服务器
cur1es5 小时前
【UDP的报文结构】
网络·网络协议·udp·md5
开开心心就好5 小时前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
闲人编程5 小时前
使用FastAPI和WebSocket构建高性能实时聊天系统
websocket·网络协议·网络编程·fastapi·持久化·实时聊天·codecapsule
惊讶的猫5 小时前
OpenFeign(声明式HTTP客户端)
网络·网络协议·http·微服务·openfeign
火车叼位6 小时前
脚本伪装:让 Python 与 Node.js 像原生 Shell 命令一样运行
运维·javascript·python
鹏北海6 小时前
micro-app 微前端项目部署指南
前端·nginx·微服务
迎仔6 小时前
06-存储设备运维进阶:算力中心的存储管家
运维
心.c6 小时前
TCP协议深入解析
网络·网络协议·tcp/ip