
知识是人生的灯塔,只有不断学习,才能照亮前行的道路
📢 大家好,我是 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_requests 与 proxy_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_requests、proxy_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_requests、proxy_responses 和 proxy_timeout 指令可精确控制 UDP session 的行为,另外可基于 session 状态监控上游服务健康状况。

END
加入:作者【全栈工程师修炼指南】知识星球
『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,持续更新包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。
Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?
✅ 将获得作者最新工作学习实践文章以及网盘资源。
✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买)
✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。
✅ 将获得作者远程支持(在作者能力范围内且合规)。

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

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