nginx本身不支持非http/https协议的正向代理,但可通过启用stream模块实现ssh、rdp等tcp服务的四层反向代理;需确认nginx -v输出with-stream,配置独立stream块(与http平级),使用proxy_pass透明转发,不解析协议,仅作连接中转。

Nginx 本身不支持正向代理非 HTTP/HTTPS 协议(如 SSH、RDP),这是关键前提。它原生只做 HTTP/HTTPS 的正向或反向代理,对 TCP 层协议(SSH 默认走 TCP 22、RDP 走 TCP 3389)无解析能力,也无法在正向代理模式下转发任意 TCP 流量。
但如果你的目标是“让客户端通过 Nginx 所在机器访问内网的 SSH 或 RDP 服务”,实际可行的是 四层(TCP 层)反向代理,而非正向代理——这需要启用 stream 模块,并配置 stream { ... } 块。
以下是实用路径和要点:
✅ 正确做法:用 stream 模块做 TCP 反向代理(非正向)
Nginx 的 stream 模块专为四层代理设计,可透明转发 TCP/UDP 流量(包括 SSH、RDP、MySQL、Redis 等),但它本质是反向代理行为:客户端连接 Nginx 的某个监听端口,Nginx 把连接直接转发到后端真实服务地址,不修改协议内容。
你需要确认并完成以下几步:
-
确认 stream 模块已编译启用
运行命令:nginx -V 2>&1 | grep -o with-stream
输出
with-stream才表示可用。否则需重装或重编译(如 Ubuntu 装nginx-extras,CentOS 8+ 安装nginx-mod-stream)。 -
配置独立的 stream 块(必须与 http 平级)
编辑/etc/nginx/nginx.conf,在http { ... }外层同级添加:stream { upstream ssh_backend { server 192.168.10.134:22; # 内网 SSH 服务器地址 } server { listen 2222; # 公网暴露的 SSH 代理端口(避开 22 防冲突) proxy_pass ssh_backend; proxy_timeout 1s; proxy_responses 1; } upstream rdp_backend { server 192.168.10.135:3389; # 内网 Windows RDP 地址 } server { listen 3390; # 公网暴露的 RDP 代理端口 proxy_pass rdp_backend; } } -
注意关键限制
-
stream块中不能使用location、proxy_set_header、SSL 终止(除非用ssl_preread)、或任何 HTTP 相关指令; - 不做协议识别,纯透传,所以 SSH 密钥认证、RDP 加密协商都由后端真实服务处理;
- 防火墙和云厂商安全组必须放行你配置的监听端口(如 2222、3390);
- 客户端连接时,目标是 Nginx 公网 IP + 代理端口,例如:
ssh user@your-public-ip -p 2222
-
❌ 为什么不能用“正向代理”方式支持 SSH/RDP?
- Nginx 的
http模块下的proxy_pass仅处理 HTTP 协议协商(CONNECT 方法虽存在,但 Nginx 官方不支持将其用于通用 TCP 隧道); - 即使强行配置
proxy_method CONNECT,Nginx 也不会建立真正的 TCP 隧道,会返回 405 或直接拒绝; - 真正的正向代理(如 Squid、TinyProxy)才支持
CONNECT隧道,但它们也需客户端显式配置代理地址+端口,且对 RDP/SSH 支持有限、安全性弱、不推荐生产使用。
? 替代方案(若必须走“正向”逻辑)
如果场景是“内网客户端想通过公网 Nginx 访问外网 SSH/RDP”,那应改用 SSH 反向隧道(Reverse Tunnel):
在内网机器上执行:
ssh -Nf -R 0.0.0.0:2222:localhost:22 user@public-nginx-server
再配合 GatewayPorts yes 和防火墙开放,效果等价于“让公网 Nginx 成为入口跳板”,但底层仍是 SSH 自建隧道,和 Nginx 无关。
不复杂但容易忽略。











