Nginx自1.9.0起支持stream模块实现TCP/UDP四层代理,可将SSH连接(端口22)转发至后端多台服务器,但仅为协议透传,不解析SSH内容;需确认或编译启用--with-stream,配置在顶层stream{}块中,支持负载均衡但无法按用户名或域名路由,可行方案包括端口区分或前置跳板服务,同时须加强防火墙、密钥认证及独立日志管理。

可以,Nginx 从 1.9.0 版本开始支持 stream 模块,用于四层(TCP/UDP)代理,因此能将 SSH 连接(默认端口 22)转发到后端不同服务器,实现统一入口管理。但需注意:这不是“SSH 代理”,而是 TCP 层透传,不解析、不干预 SSH 协议本身。
前提条件与启用 stream 模块
Nginx 默认可能未编译 stream 模块。确认方式:
- 运行
nginx -V 2>&1 | grep -o with-stream,有输出表示已启用 - 若无,需重新编译 Nginx,添加
--with-stream参数 - Debian/Ubuntu 用户可安装
nginx-full包(通常含 stream);CentOS/RHEL 可用 EPEL 中的 nginx-mod-stream 或使用官方动态模块
基本 TCP 代理配置示例
在 nginx.conf 的顶层(不在 http{} 块内)添加 stream{} 块:
stream {
upstream ssh_backend {
server 192.168.1.10:22; # 实际 SSH 服务器 A
server 192.168.1.11:22; # 实际 SSH 服务器 B
# 可配 weight、max_fails、fail_timeout 等负载策略
}
<pre class="brush:php;toolbar:false;">server {
listen 22;
proxy_pass ssh_backend;
proxy_timeout 1h;
proxy_responses 1; # SSH 协议无需多响应,设为 1 更稳妥
}}
⚠️ 注意:该配置是简单轮询转发,所有连接均被分发,无法按用户名或目标主机名区分路由(SSH 协议本身不携带 Host 字段,不像 HTTP)。
实现“按用户/主机名区分”的可行方案
纯 Nginx stream 无法识别 SSH 登录用户名,但可通过以下方式间接实现统一入口下的差异化路由:
-
端口区分法:为不同目标分配独立端口(如 2201 → 服务器 A,2202 → 服务器 B),Nginx 按监听端口分发,用户通过
ssh -p 2201 user@proxy-ip连接 -
域名 + 端口映射法:配合 DNS 或 hosts,将
a.example.com:22和b.example.com:22解析到同一 IP,再用 Nginx 的map指令结合$remote_addr或$server_port(不可靠)做判断——但实际中stream不支持$host,故域名区分在纯 TCP 层不可行 -
前置跳板逻辑:Nginx 仅作最外层入口(如监听 22),后接一个轻量 SSH 跳板服务(如
sshservice或自研脚本),由它解析登录用户名并执行exec ssh user@target,Nginx 此时退化为单点透传
安全与运维注意事项
启用 TCP 代理后,原有 SSH 安全机制仍生效,但需额外关注:
- 确保 Nginx 所在机器防火墙放行 22 端口,且仅允许可信来源访问(如限制
allowIP 段) - 后端 SSH 服务器应禁用密码登录,强制密钥认证;Nginx 本身不处理认证,不增加也不削弱认证强度
- 日志需单独配置:
access_log /var/log/nginx/stream-access.log和error_log /var/log/nginx/stream-error.log,因 stream 日志与 http 独立 - 连接超时建议设长(如
proxy_timeout 3600;),避免 SSH 会话被意外中断










