news 2026/9/10 17:01:43

Nginx Proxy Manager 端口转发(Streams)完全指南:TCP/UDP 流代理原理与配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Nginx Proxy Manager 端口转发(Streams)完全指南:TCP/UDP 流代理原理与配置实战

Nginx Proxy Manager 端口转发(Streams)完全指南:TCP/UDP 流代理原理与配置实战

【免费下载链接】nginx-proxy-managerDocker container for managing Nginx proxy hosts with a simple, powerful interface项目地址: https://gitcode.com/GitHub_Trending/ng/nginx-proxy-manager

端口转发(Stream)是 Nginx Proxy Manager(NPM)中基于 Nginx stream 模块实现的核心能力之一,用于将 TCP/UDP 流量直接转发到网络中的另一台主机,适合游戏服务器、FTP、SSH 等非 HTTP 服务。本文以 Streams 帮助文档 为骨架,结合 stream.conf 模板、internal/stream.js、stream 数据模型 与前端 StreamModal 等仓库源码,系统讲解 Stream 的适用场景、配置字段、前端操作、后端生命周期与最终生成的 Nginx 配置,帮助读者在 NPM 中正确、安全地搭建 TCP/UDP 转发规则。

什么是 Stream:Nginx 的传输层流代理

按照官方帮助文档的定义:Stream 是 Nginx 的一项相对较新的功能,它可以把 TCP/UDP 流量直接转发到网络中的另一台计算机(对应俄语文档原文 "поток позволяет напрямую проксировать TCP/UDP‑трафик на другой компьютер в сети")。

与 Proxy Host(HTTP/HTTPS 反向代理)不同,Stream 工作在传输层(L4),不关心上层协议内容,只负责把原始字节流在端口之间搬运。因此它非常适合承载那些不是 Web 服务的网络应用。

NPM 中 Stream 的核心特征可以从源码中得到印证:

  • 在 internal/stream.js 中有一句关键注释:streams aren't routed by domain name so don't store domain names in the DB(Stream 不按域名路由,因此数据库中不存储域名)。这正是它区别于 Proxy Host 的本质——Stream 只按"端口"寻址,不按"域名"寻址
  • stream 列表接口 按incoming_port升序排序,并支持按incoming_port模糊搜索,再次印证端口是 Stream 的唯一标识维度。

典型使用场景:游戏服务器、FTP 与 SSH

官方帮助文档明确指出:如果你在运行游戏服务器、FTP 或 SSH 服务器,这个功能就会很有用

从技术角度看,这些场景的共性在于:

场景协议为什么需要 Stream
游戏服务器TCP/UDP游戏流量通常是非 HTTP 的自定义协议,且需要 UDP 支持
FTP 服务器TCP控制连接与数据连接均为 TCP,且可能占用多个端口
SSH 服务器TCP需要把外部某个端口安全地透传到内网 SSH 服务

其典型部署形态是:Nginx Proxy Manager 运行在公网入口主机上,监听一个公网端口,把流量转发到内网某台机器(或同一内网中的另一台服务器)的对应端口,实现无需暴露整台内网机器即可对外提供 TCP/UDP 服务。

Stream 配置字段全解

创建或编辑 Stream 时涉及的核心字段,在 stream-object.json 接口定义 中有完整的类型约束,同时 StreamModal.tsx 展示了前端表单的输入规则。汇总如下:

字段类型取值范围/说明来源
incoming_portinteger1~65535,NPM 监听的外部端口,必填stream-object.json、StreamModal
forwarding_hoststring目标主机,支持域名、IPv4、IPv6 三种格式stream-object.json
forwarding_portinteger1~65535,目标端口,必填stream-object.json
tcp_forwardingboolean是否启用 TCP 转发stream-object.json
udp_forwardingboolean是否启用 UDP 转发stream-object.json
enabledboolean是否启用该 Streamstream-object.json
certificate_idinteger关联的 SSL 证书 ID(0 表示无证书)stream-object.json
metaobject附加元数据(默认{}stream-object.json

前端表单 StreamModal.tsx 中对应的输入校验逻辑也完全一致:

  • Incoming Porttype="number"min=1max=65535,校验函数validateNumber(1, 65535),占位符示例8080
  • Forward HostvalidateString(1, 255),支持填域名或 IP;
  • Forward Port:同样限定 1~65535;
  • TCP/UDP 转发开关:通过tcpForwardingudpForwarding两个布尔字段控制。

值得注意的是,tcp_forwardingudp_forwarding可以同时开启——模板会为同一incoming_port分别生成 TCP 与 UDP 两个server块,实现"同一端口同时支持 TCP 和 UDP"的效果(详见下文模板分析)。

前端操作:创建与编辑 Stream

在 NPM 管理界面中,Streams 的入口位于左侧菜单的Streams页面(页面组件见 Streams/TableWrapper.tsx)。页面顶部提供了:

  • 新增按钮:调用showStreamModal("new")打开新建弹窗;
  • 帮助按钮:调用showHelpModal("Streams", ...)打开本文对应的帮助文档;
  • 每行的编辑/删除/启停操作:删除与启停分别调用 deleteStream / toggleStream 对应接口。

弹窗内部(StreamModal.tsx)分为两个标签页:

  1. Details(详情):填写 Incoming Port、Forward Host、Forward Port,以及 TCP/UDP 转发开关;
  2. SSL:通过 SSLCertificateField 选择证书、SSLOptionsFields 配置 SSL 选项。

提交后前端调用useSetStream()(对应 useStream.ts hook),最终命中后端的创建/更新接口。列表页在操作成功后还会失效["streams"]["stream", id]查询缓存,保证界面即时刷新(见 TableWrapper.tsx)。

后端生命周期:从接口到 Nginx 配置

Stream 的所有后端逻辑集中在 internal/stream.js,其完整生命周期如下:

创建(create)

流程为:权限校验streams:create→ 设置owner_user_id→ 初始化meta→ 写入数据库(此时特意剥离domain_names字段)→ 若certificate_id === "new"则先走createQuickCertificate快速签发证书并回填 → 调用internalNginx.configure(streamModel, "stream", row)生成 Nginx 配置 → 写入审计日志(action 为created)。

更新(update)

先读取现有记录做一致性校验,更新数据库后再次get并重新configure,同时把变更写入审计日志(action 为updated)。

启停(enable / disable)

  • enable:把enabled置 1,重新调用configure生成配置;
  • disable:把enabled置 0,调用internalNginx.deleteConfig("stream", row)删除配置并reload()

两者都会在审计日志中记录enabled/disabled动作。

删除(delete)

采用软删除策略:仅将is_deleted置 1,然后删除 Nginx 配置并 reload,审计日志记录deleted

整个链路表明:NPM 对 Stream 的每一次增删改都会即时重写并重载 Nginx 配置,这也是管理界面操作能够"所见即所得"的底层保证。

模板解析:生成的 Nginx 配置长什么样

NPM 使用 Nunjucks 模板引擎渲染 Stream 配置,核心模板是 backend/templates/stream.conf。渲染后 TCP 转发块大致如下:

# ------------------------------------------------------------ # 8080 TCP: 1 UDP: 0 # ------------------------------------------------------------ server { listen 8080 reuseport ssl; listen [::]:8080 reuseport ssl; # Let's Encrypt SSL include conf.d/include/ssl-cache-stream.conf; include conf.d/include/ssl-ciphers.conf; ssl_certificate /etc/letsencrypt/live/npm-3/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/npm-3/privkey.pem; proxy_pass 192.168.1.10:22; access_log /data/logs/stream-3_access.log stream; error_log /data/logs/stream-3_error.log warn; # Custom include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream_tcp[.]conf; }

模板的关键设计点(全部有源码依据):

  • listen {{ incoming_port }} reuseport:使用reuseport提升多 worker 下的端口分发性能;当绑定了证书时追加ssl关键字;
  • IPv6 支持{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }}...——只有当ipv6开关开启时才会启用 IPv6 监听,否则整行被注释;
  • proxy_pass {{ forwarding_host }}:{{ forwarding_port }}:即目标主机与端口;
  • 独立日志access_log /data/logs/stream-{{ id }}_access.log stream;error_log /data/logs/stream-{{ id }}_error.log warn;,每个 Stream 拥有独立的访问/错误日志,便于排查;
  • 自定义配置挂载点:模板末尾会 include/data/nginx/custom/server_stream[.]confserver_stream_tcp[.]conf(UDP 块则 includeserver_stream_udp[.]conf),用户可以在不修改核心配置的前提下追加自定义指令(如proxy_timeoutproxy_buffer_size等)。注意这里的[.]写法是 Nginx 的 glob 语法,用于避免与点号通配冲突。

当 UDP 转发也开启时,模板会再生成一个listen {{ incoming_port }} udp reuseportserver块,逻辑与 TCP 块平行,但监听的是 UDP 流量。

SSL/TLS:为 TCP 流加密

Stream 同样支持 SSL 终止。SSL 配置由 _certificates_stream.conf 模板渲染:

  • 若证书来自 Let's Encrypt(provider == "letsencrypt"),证书路径为/etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem与对应的privkey.pem,并 includessl-cache-stream.conf(SSL 会话缓存)与ssl-ciphers.conf(密码套件);
  • 若是自定义证书,则从/data/custom_ssl/npm-{{ certificate_id }}/目录读取。

值得说明的是,Stream 的证书支持是后来加入的能力:数据库迁移 20240427161436_stream_ssl.js 为stream表新增了certificate_id列(默认 0,即无证书)。因此在创建 Stream 时,SSL 标签页中的证书是可选的。

数据模型与权限控制

数据模型

models/stream.js 定义了stream表的 ORM 模型,要点如下:

  • 布尔字段is_deletedenabledtcp_forwardingudp_forwarding在数据库中以 0/1 存储、在 API 层转换为 true/false;
  • user(owner 所有者)和certificate(证书)建立关系映射(defaultAllowGraph = "[owner,certificate]");
  • 默认排序为incoming_port ASC

权限

访问 Stream 相关接口需要对应权限:从 streams-create.json 可见,创建 Stream 需要管理员角色,或拥有permission_streams管理权限的user角色;其余操作(streams:getstreams:updatestreams:deletestreams:list)在 internal/stream.js 中均通过access.can(...)校验。此外,当权限可见性不是all时,查询会自动加上owner_user_id过滤(internal/stream.js),即普通用户只能看到自己创建的 Stream。

实战注意事项与排查建议

  1. 端口冲突:NPM 会在同一主机上为所有 Stream 分配监听端口,如果两个 Stream 使用相同incoming_port会导致 Nginx 启动失败。从 internal/stream.js 的 TODO 注释("At this point the existing ports should have been checked")可以看出,当前版本在创建阶段尚未对端口占用做强制校验,因此配置前应先确认端口未被其他服务或 Stream 占用
  2. TCP 与 UDP 可并行:同一个incoming_port可以同时勾选 TCP 与 UDP,模板会分别生成两个server块,互不冲突;但也意味着该端口上的 TCP 和 UDP 流量都会被接管,请确认没有其他服务依赖该端口。
  3. 查看日志:每个 Stream 的日志独立存放在/data/logs/stream-{{ id }}_access.logstream-{{ id }}_error.log,排查连接失败问题时优先查看对应 ID 的错误日志。
  4. 自定义配置:需要调优(如超时、缓冲区、proxy_protocol等)时,可在容器的/data/nginx/custom/目录放置server_stream_tcp[.]confserver_stream_udp[.]conf文件,模板会自动 include。
  5. 域名不参与路由:Stream 不按域名匹配,domain_names不会被写入数据库(internal/stream.js),因此一个端口只能服务一个转发目标,多目标分流需要占用多个端口。

小结

Nginx Proxy Manager 的 Stream 功能,本质上是把 Nginx 的 stream 模块能力封装成了可视化的"端口转发"管理入口:你在界面上填写监听端口、目标主机与端口、选择 TCP/UDP 与可选证书,后端随即渲染出标准 Nginx stream 配置并热加载。对于游戏服务器、FTP、SSH 这类非 HTTP 服务,它提供了一条比手动维护 Nginx 配置更直观、更可控的运维路径。理解 stream.conf 模板与 internal/stream.js 的生命周期逻辑,是在生产环境中排障与深度定制的关键。

【免费下载链接】nginx-proxy-managerDocker container for managing Nginx proxy hosts with a simple, powerful interface项目地址: https://gitcode.com/GitHub_Trending/ng/nginx-proxy-manager

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 16:56:21

使用统计功能测试报告

使用统计功能测试报告 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 测试环境 操作系统: Windows 11浏览器: Chrome 120后端版本: [按实际填写…

作者头像 李华
网站建设 2026/9/10 16:55:56

MATLAB实现随机游走改进谱聚类算法

1. 项目概述:当随机游走遇见谱聚类在数据科学领域,聚类分析一直是探索性数据分析的利器。传统k-means算法在处理非凸分布数据时往往力不从心,这正是谱聚类大显身手的场景。最近我在MATLAB R2018A环境下实现了一种基于随机游走拉普拉斯算子的改…

作者头像 李华
网站建设 2026/9/10 16:53:34

K8s集群部署Jenkins流水线Pip缓存排查实操

K8s集群部署Jenkins流水线Pip缓存排查实操技术栈:Jenkins 2.440.x Kubernetes v1.32.13 Rocky Linux 8.6 Kubernetes Plugin Kaniko Helm 3.14.x操作环境 / 对接原理 / 详细步骤 / 完整命令 / 配置文件 / 验证流程 / 排错方案K8s集群部署Jenkins流水线Pip缓存排…

作者头像 李华
网站建设 2026/9/10 16:53:04

VMware虚拟机安装Ubuntu Server 22.04最小版完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华