Nginx Proxy Manager 端口转发(Stream)功能详解:TCP/UDP 流量转发实战
2026/9/11 9:31:59 网站建设 项目流程

Nginx Proxy Manager 端口转发(Stream)功能详解: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

导读

本文围绕 Nginx Proxy Manager 的Stream(端口转发)功能展开。Stream 基于 Nginx 的流模块,能够将 TCP/UDP 流量直接转发到网络上的另一台计算机,适用于游戏服务器、FTP、SSH 等非 HTTP 协议的代理场景。读完本文,你将掌握端口转发的适用场景、配置字段含义、SSL 终止支持、底层 Nginx 配置生成原理,以及如何通过 API 或源码理解其完整工作链路。

什么是端口转发(Stream)?

在 Nginx Proxy Manager 中,Stream(端口转发)是一个相对较新的功能,它的核心作用是把 TCP/UDP 流量直接转发到网络中的另一台计算机

与 HTTP/HTTPS 反向代理(Proxy Host)不同,Stream 不关心应用层协议,而是在**传输层(Layer 4)**按 IP 和端口转发原始数据流。因此,凡是基于 TCP 或 UDP 的协议,都可以通过 Stream 暴露到公网:

  • 游戏服务器:如 Minecraft、CS 等需要固定端口直连的游戏服务;
  • FTP 服务:传统 FTP 使用 21 端口控制连接,主动/被动模式下还需要转发数据端口;
  • SSH 服务:将内网主机的 SSH 端口映射到公网,方便远程管理;
  • 数据库连接:MySQL(3306)、PostgreSQL(5432)等;
  • 其他自定义 TCP/UDP 服务

如果你正在运行上述服务,端口转发功能就能派上用场。它的价值在于:你可以用一台部署了 Nginx Proxy Manager 的公网主机统一收口所有内网服务的入站流量,无需为每个服务单独购买公网 IP 或调整路由器端口映射。

端口转发与 HTTP 代理的区别

在 Nginx Proxy Manager 的管理界面中,Stream 与 Proxy Host(HTTP 代理)是两类独立的资源,理解它们的差异有助于选对功能:

维度Proxy Host(HTTP 代理)Stream(端口转发)
工作层级应用层(HTTP/HTTPS)传输层(TCP/UDP)
路由依据域名 + Host 头IP + 端口
典型协议HTTP、HTTPS、WebSocketSSH、FTP、游戏协议、数据库
是否支持 SSL支持,且通常是核心诉求支持 TCP 上的 SSL(流式透传)
域名配置必须配置domain_names不按域名路由

这一区别在源码中也有明确体现:在 backend/internal/stream.js 的create流程里,有一段注释写道streams aren't routed by domain name so don't store domain names in the DB(Stream 不按域名路由,因此不在数据库中存储域名),并在入库前通过delete data_no_domains.domain_namesdomain_names字段移除。这说明 Stream 从数据模型层面就与域名解耦,纯粹以端口为核心标识。

核心概念:入站端口与转发目标

一个 Stream 配置本质上只回答两个问题:

  1. 监听哪个入站端口(incoming_port);
  2. 把流量转发到哪里(forwarding_host + forwarding_port)。

在管理界面中,创建 Stream 时需要在Details(详细信息)标签页填写以下核心字段(对应前端弹窗 frontend/src/modals/StreamModal.tsx 中的表单):

  • Incoming Port(入站端口):Nginx 监听的公网端口,取值范围 1~65535。前端通过validateNumber(1, 65535)校验(见 frontend/src/modals/StreamModal.tsx),OpenAPI 规范同样约束为 1~65535(见 backend/schema/components/stream-object.json)。
  • Forward Host / IP(转发目标主机):目标计算机的域名、IPv4 或 IPv6 地址。OpenAPI 规范允许域名(如example.com)、IPv4(0.0.0.0255.255.255.255格式)或 IPv6(见 backend/schema/components/stream-object.json)。
  • Forward Port(转发端口):目标主机上服务的真实端口,同样取值 1~65535。
  • TCP Forwarding(TCP 转发):布尔开关,是否转发 TCP 流量。
  • UDP Forwarding(UDP 转发):布尔开关,是否转发 UDP 流量。
  • SSL Certificate(SSL 证书):可选,用于对入站 TCP 连接启用 SSL 终止/透传(详见下文)。
  • Enabled(启用):是否立即生效。

从数据库模型看,tcp_forwardingudp_forwarding是独立的布尔字段(见 backend/models/stream.js),二者可以同时开启,也可以只开其一。若同时开启,Nginx 会为同一入站端口生成 TCP 与 UDP 两套server块(见下文模板分析)。

在管理界面中,Stream 列表默认按incoming_port升序排列(见 backend/internal/stream.js 与 backend/models/stream.js),方便运维人员快速定位端口占用情况。

生成的真实 Nginx 配置解析

Nginx Proxy Manager 的本质是「配置生成器」:你在界面上填写的表单,最终会被渲染成一段标准 Nginx 配置。Stream 的配置模板位于 backend/templates/stream.conf,其核心逻辑如下:

# ------------------------------------------------------------ # {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }} # ------------------------------------------------------------ {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { listen {{ incoming_port }} reuseport {%- if certificate %} ssl {%- endif %}; {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} reuseport {%- if certificate %} ssl {%- endif %}; {%- include "_certificates_stream.conf" %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; access_log /data/logs/stream-{{ id }}_access.log stream; error_log /data/logs/stream-{{ id }}_error.log warn; # Custom include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream_tcp[.]conf; } {% endif %} {% if udp_forwarding == 1 or udp_forwarding == true -%} server { listen {{ incoming_port }} udp reuseport; {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp reuseport; proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; access_log /data/logs/stream-{{ id }}_access.log stream; error_log /data/logs/stream-{{ id }}_error.log warn; # Custom include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream_udp[.]conf; } {% endif %} {% endif %}

这段模板揭示了几个关键实现细节:

  1. 条件渲染由enabled开关控制{% if enabled %}保证禁用(disabled)的 Stream 不会生成任何server块,这正是「启用/禁用」功能的底层实现原理——见 backend/internal/stream.js,enable会调用internalNginx.configure重新生成配置,而disable会调用internalNginx.deleteConfig删除配置并reload

  2. TCP 与 UDP 是两套独立的server:TCP 块使用listen {{ incoming_port }} reuseport(可选追加ssl),UDP 块使用listen {{ incoming_port }} udp reuseportreuseport指令允许多个 socket 绑定同一端口,提升多核场景下的分发性能。

  3. IPv6 双栈支持:每套server块都会尝试监听[::]:{{ incoming_port }},当项目未启用 IPv6 时(ipv6为假),模板通过{% unless ipv6 -%} # {%- endunless -%}输出#注释掉该行,实现优雅降级。

  4. 流式访问日志:每个 Stream 生成独立的访问/错误日志文件/data/logs/stream-{{ id }}_access.logstream-{{ id }}_error.log,方便按 Stream 维度排查流量。

  5. 自定义配置钩子:模板末尾 include 了/data/nginx/custom/server_stream[.]confserver_stream_tcp[.]confserver_stream_udp[.]conf三个可选文件(方括号.写法保证文件不存在时不报错),高级用户可以写入额外的 Nginx 指令。

  6. SSL 只在 TCP 块生效{%- if certificate %} ssl {%- endif %}表明当为该 Stream 绑定证书时,TCP 监听会启用ssl指令,证书相关配置由_certificates_stream.conf子模板注入(见 backend/templates/_certificates_stream.conf)。

SSL 支持:为 TCP 流量启用加密

虽然 Stream 面向的是非 HTTP 协议,但 Nginx Proxy Manager 仍允许为 TCP 转发绑定SSL 证书,实现「入站加密 → 内网明文」或「入站加密 → 内网同样加密」的透传模式。

配置方式与 Proxy Host 类似:在 Stream 弹窗的SSL 标签页(见 frontend/src/modals/StreamModal.tsx)中,通过SSLCertificateField选择一个已有证书,或选择「新建证书」快捷创建(certificate_id === "new")。

在 API 层,当提交certificate_id: "new"时,backend/internal/stream.js 会调用internalCertificate.createQuickCertificate(access, data)先快速签发证书,再回填certificate_id完成创建;更新(update)流程同样支持这一快捷路径(见 backend/internal/stream.js)。这表明 Stream 与证书模块是深度集成的,而不是简单的字段挂载。

需要说明的是:Stream 的 SSL 是流式透传/终止于 Nginx 层,与 HTTP 代理的证书续期、HSTS 等 Web 特性无关——因为 Nginx 的stream模块工作在传输层,_certificates_stream.conf只注入ssl_certificatessl_certificate_key等与 TCP 加密直接相关的指令。

Stream 的完整生命周期:从 API 到 Nginx 配置

理解一个 Stream 从创建到生效的完整链路,有助于在生产环境中排查问题。整个过程由 backend/internal/stream.js 驱动,分为以下步骤:

  1. 权限校验:调用access.can("streams:create", data)检查当前用户是否具备创建权限。权限模型定义在 backend/lib/access/streams-create.json:管理员可直接操作,普通用户则需要permission_streams具备 manage 权限。
  2. 数据入库:通过streamModel.query().insertAndFetch(data)写入stream表(backend/models/stream.js)。模型层会自动维护created_on/modified_on时间戳,并把enabledtcp_forwardingudp_forwarding等布尔字段与整数在数据库层面互相转换(见 backend/models/stream.js)。
  3. (可选)快速签发证书:若选择新建证书,会先调用证书模块,再把certificate_id回填。
  4. 生成并应用 Nginx 配置:调用internalNginx.configure(streamModel, "stream", row),用 backend/templates/stream.conf 渲染出实际配置并触发 Nginx reload。
  5. 写入审计日志:调用internalAuditLog.add记录created/updated/deleted/enabled/disabled等动作(见 backend/internal/stream.js),所有操作均可追溯。

更新(update)流程同样遵循「权限校验 → 入库 → 重新生成配置 → 审计」的链路;而删除(delete)与禁用(disable)则调用internalNginx.deleteConfig("stream", row)移除配置文件并reload(见 backend/internal/stream.js)。从源码结构看,enable/disable被实现为独立操作而非字段编辑,便于在审计日志中区分操作类型。

列表查询(getAll)则按is_deleted = 0过滤,默认关联加载certificateowner关系(见 backend/models/stream.js),并支持通过expand参数按需展开关联数据(见 backend/internal/stream.js),这也是前端 Stream 列表页展示证书与所有者信息的底层来源。

通过 REST API 管理 Stream

Nginx Proxy Manager 提供了完整的 REST API 来管理端口转发,OpenAPI 规范中的 Stream 对象定义在 backend/schema/components/stream-object.json,核心字段如下:

字段类型说明
idinteger主键
incoming_portinteger (1–65535)入站监听端口,必填
forwarding_hoststring转发目标域名/IPv4/IPv6,必填
forwarding_portinteger (1–65535)转发目标端口,必填
tcp_forwardingboolean是否启用 TCP 转发,必填
udp_forwardingboolean是否启用 UDP 转发,必填
enabledboolean是否启用,必填
certificate_idinteger可选,绑定的 SSL 证书 ID
metaobject扩展元数据,默认为{}
owner_user_idinteger归属用户,必填

对应的 API 端点包括(定义见 backend/schema/paths/nginx/streams 与 backend/routes/nginx/streams.js):

  • GET /api/nginx/streams—— 列出所有 Stream;
  • POST /api/nginx/streams—— 新建 Stream;
  • GET /api/nginx/streams/{streamID}—— 获取单个 Stream;
  • PUT /api/nginx/streams/{streamID}—— 更新 Stream;
  • DELETE /api/nginx/streams/{streamID}—— 删除 Stream;
  • POST /api/nginx/streams/{streamID}/enablePOST /api/nginx/streams/{streamID}/disable—— 启用/禁用。

例如,创建一个「将公网 2222 端口转发到内网192.168.1.10的 22 端口(SSH)」的 Stream:

{ "incoming_port": 2222, "forwarding_host": "192.168.1.10", "forwarding_port": 22, "tcp_forwarding": true, "udp_forwarding": false, "enabled": true }

提交后,后端会按照上文的生命周期流程生成配置并立即生效。前端通过 frontend/src/api/backend/createStream.ts、updateStream.ts 等封装调用这些端点,管理界面与 API 完全等价。

端口冲突与运维注意事项

从源码实现看,Stream 功能在端口管理上有一个值得注意的点:在 backend/internal/stream.js 的create与 backend/internal/stream.js 的update中,均存在TODO: At this point the existing ports should have been checked(此处应检查已有端口占用)的注释。也就是说,当前版本在后端并未显式校验入站端口是否已被其他 Stream 或系统服务占用,依赖 Nginx 配置 reload 阶段自行报错。

因此在生产环境中,建议运维人员注意:

  1. 入站端口需全局唯一:同一个incoming_port不要重复用于多个 Stream,否则生成的 Nginx 配置会产生listen冲突,reload 时报错导致配置不生效。
  2. 避开宿主已占用端口:入站端口会绑定在运行 Nginx Proxy Manager 的主机上,请勿与 SSH(22)、Web 管理端口(81)等系统端口冲突。
  3. 关注防火墙/安全组:Stream 监听的是原始 TCP/UDP 端口,需在云厂商安全组与系统防火墙中放行对应入站流量,这与 HTTP 代理走 80/443 的情形不同。
  4. TCP/UDP 同开时注意协议差异:同一端口同时开启 TCP 与 UDP 转发是允许的(会生成两套server块),但目标服务必须分别监听对应协议,否则会有一侧连接失败。
  5. 通过自定义配置钩子做精细控制:如需要额外指令(如proxy_timeoutproxy_buffer_size等),可挂载到/data/nginx/custom/server_stream_tcp[.]confserver_stream_udp[.]conf,避免直接改动生成的配置。

从源码进一步学习

如果你想深入了解 Stream 的实现细节,可以从以下文件入手(均在当前仓库内):

  • backend/templates/stream.conf —— 端口转发最终的 Nginx 配置模板,是理解全部行为的最佳起点;
  • backend/internal/stream.js —— Stream 的完整 CRUD、启停与审计逻辑;
  • backend/models/stream.js —— 数据模型、布尔字段转换与关联关系(owner / certificate);
  • backend/schema/components/stream-object.json —— OpenAPI 字段定义与取值范围;
  • backend/routes/nginx/streams.js —— REST API 路由层;
  • frontend/src/modals/StreamModal.tsx —— 前端创建/编辑表单与校验规则;
  • frontend/src/pages/Nginx/Streams —— 前端列表页实现;
  • backend/schema/paths/nginx/streams —— API 路径规范(含 enable/disable 等操作)。

总结

端口转发(Stream)是 Nginx Proxy Manager 中面向非 HTTP 流量的核心能力:它以入站端口 + 转发目标为模型,利用 Nginxstream模块在传输层完成 TCP/UDP 数据的透明转发,天然适用于 SSH、FTP、游戏服务器等场景。在实现上,Stream 与证书模块深度集成支持 TCP SSL,配置通过 backend/templates/stream.conf 模板渲染生成,具备 IPv6 双栈、独立日志、自定义配置钩子与完整审计能力;同时提供了与界面等价的 REST API,便于自动化管理。使用时只需注意入站端口的唯一性与防火墙放行,即可快速将内网任意 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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询