SSH隧道原理及其使用方法
SSH 隧道(SSH Tunnel)原理
A Secure Shell (SSH) tunnel consists of an encrypted tunnel created through an SSH protocol connection. Users may set up SSH tunnels to transfer unencrypted traffic over a network through an encrypted channel. It is a software-based approach to network security and the result is transparent encryption.
SSH 隧道(SSH Tunneling),又称为 SSH 端口转发(SSH Port Forwarding),是一种利用SSH协议为其他协议或网络链接加密的方法。通过SSH隧道,用户可以安全地传输未加密的网络流量,通过远程服务器转发到目标目的地,保证了数据传输的私密性和安全性。
SSH 隧道并不是真的建立了一条物理线路,而是在应用层重新包装了数据包。简单来说,它就像是在原本互不相通或不安全的两个点之间,拉了一根加密的“隐形管道”。你把原本要发送的数据包塞进这个管道,数据包在传输过程中会被 SSH 协议严密包裹并加密,等到了管道另一头再由 SSH 拆包发送给最终目标。
1. 协议封装(Protocol Encapsulation)
- 原始数据:假设你通过隧道访问数据库,原始包是
TCP [Target_IP:3306]。 - 隧道封装:SSH 客户端拦截该 TCP 流,提取其 Payload(负载),然后将其作为 SSH 报文的数据部分。
- 外层包裹:这个数据部分会被加上 SSH 的加密头、序列号和 MAC 校验码。
- 最终传输:最终在互联网上传输的包,其目标 IP 是 SSH 服务器,端口是 22。对于中间的路由器和防火墙来说,它们只能看到合法的 SSH 加密流量,完全不知道里面“藏”着数据库请求。
2. 频道多路复用(Channels)
一个 SSH 连接(Connection)内部可以并行跑很多个隧道,这得益于 Channel 机制。
- 在一个物理的 TCP 连接(SSH 会话)中,SSH 协议可以创建多个逻辑上的 Channel。
- 每个
-L或-R转发请求都会开启一个独立的 Channel。 - SSH 协议栈负责将不同 Channel 的流量进行编号和解复用,确保发往本地
8080端口的数据不会错乱到其他端口去。
3. SSH 隧道转发模式(Port Forwarding)
SSH 隧道转发(SSH Port Forwarding)主要有以下三个方式,它们通过在加密的 SSH 连接中建立数据通道,实现网络请求的跨网络传输。
3.1 本地转发
将发送到本地机器特定端口的请求,通过 SSH 隧道转发到远程目标主机的指定端口。请求由本地发起,SSH 客户端充当“中转站”。具体命令如下:
1 | |
-f:让 SSH 客户端在后台运行,即使命令行关闭也能保持 SSH 隧道建立-N:只建立连接,不执行远程命令-L:以本地转发模式建立 SSH 隧道$LocalIP:本地 IP,可以是127.0.0.1,也可以是 DHCP 分配的 IP,区别在于前者只供本机访问,后者可供局域网内其他设备访问。也可以为空,为空时,除了代表允许任何设备都可以访问到这个端口,还可以支持 IPv6 访问。$LocalPort:本地用于接收请求的端口,要求端口号之前不能被占用,建议选择1024以上且未被占用的端口。$TargetIP:可以是 SSH 服务器的 IP,也可以是局域网内能与 SSH 服务器相通的其他服务器 IP。如果是后者的话,需要开启 SSH 服务器的转发权限,即编辑/etc/ssh/sshd_config,修改AllowTcpForwarding为yes(默认通常开启)$TargetPort:目标服务器上提供服务的端口$Username:SSH 服务器上的登录时的用户名$SSHServer: SSH 服务器 IP
3.2 远程转发
将发送到远程 SSH 服务器特定端口的请求,通过 SSH 隧道转发到本地机器或其可达的其他主机的指定端口。命令在本地执行,但请求由远程发起,通常用于将内网服务临时暴露给外网。具体命令如下:
1 | |
-f:让 SSH 客户端在后台运行,即使命令行关闭也能保持 SSH 隧道建立-N:只建立连接,不执行远程命令-R:以远程转发模式建立 SSH 隧道$RemoteIP:SSH 服务器 IP,可填本地回环地址或者SSH 服务器的局域网地址,区别在于前者只转发 SSH 服务器本地访问请求,后者可转发局域网内其他设备访问请求,但需要开启 SSH 服务器的网关端口,即编辑/etc/ssh/sshd_config,修改GatewayPorts为yes(默认通常关闭)。也可以为空,为空时,可转发该端口的所有访问请求。$RemotePort:SSH 服务器用于转发请求的端口,要求端口号之前不能被占用,建议选择1024以上且未被占用的端口。$TargetIP:本机 IP,可填本地回环地址或者本机的局域网地址,区别在于前者只供本机访问,后者可供本机局域网内其他设备访问。$TargetPort:本机上的端口,要求端口号之前不能被占用,建议选择1024以上且未被占用的端口。$Username:SSH 服务器上的登录时的用户名$SSHServer: SSH 服务器 IP
3.3 动态转发
在本地机器上建立一个 SOCKS 代理服务器。它不会绑定固定的目标端口,而是根据应用请求动态决定去向。
1 | |
-f:让 SSH 客户端在后台运行,即使命令行关闭也能保持 SSH 隧道建立-N:只建立连接,不执行远程命令-D:以本地转发模式建立 SSH 隧道$LocalIP:本地 IP,可以是127.0.0.1,也可以是 DHCP 分配的 IP,区别在于前者只供本机访问,后者可供局域网内其他设备访问。也可以为空,为空时,除了代表允许任何设备都可以访问到这个端口,还可以支持 IPv6 访问。$LocalPort:本地用于接收请求的端口,要求端口号之前不能被占用,建议选择1024以上且未被占用的端口。$Username:SSH 服务器上的登录时的用户名$SSHServer: SSH 服务器 IP
3.4 转发模式对比
| 转发方式 | 核心参数 | 流量方向 | 主要用途 |
|---|---|---|---|
| 本地转发 | -L |
本地 -> 远程 | 访问远程内网资源 |
| 远程转发 | -R |
远程 -> 本地 | 内网穿透/反向代理 |
| 动态转发 | -D |
本地 -> 动态目标 | SOCKS5 代理/加密上网 |
SSH隧道适用场景
1. 访问远程内网资源
- 本地 PC(Local PC)
- SSH 服务器(SSH Server)
- MySQL 服务器(MySQL Server)
通过 SSH 隧道
本地转发模式将远程MySQL 服务器的3306端口映射本地的3306端口。

1 | |

1 | |
$PrivateKeyPath:是 SSH 的私钥文件路径,示例路径为$HOME\.ssh\id_rsa,使用$HOME是为了避免中文路径乱码。
2. 内网穿透/反向代理
- 家用 PC(Home PC)
- 家用监控(Home Camera)
- 公司 Laptop(Company Laptop)
- SSH 服务器(SSH Server)
在
家用 PC上通过 SSH 隧道远程转发模式将本地局域网中的家用监控服务 8080 端口映射给SSH 服务器8080 端口,然后在公司 Laptop上通过 SSH 隧道本地转发模式将SSH 服务器8080 端口映射到本地 8080 端口。

在Home PC上执行:
1 | |
在Company Laptop上执行:
1 | |
执行完后,在Company Laptop上的浏览器输入http://127.0.0.1:8080 即可看到监控。
3. SOCKS5代理/加密上网
- 本地 PC(Local PC)
- SSH 服务器(SSH Server)
- MySQL 服务器(MySQL Server)
- Web 服务器(Web Server)
通过 SSH 隧道
动态转发模式将SSH 服务器变成代理服务器,同时将本地 IP 和端口作为代理入口。这样可以在本地 PC或者其所在局域网内其他设备配置应用或系统代理,以此来访问SSH 服务器所在局域网中MySQL 服务器和Web 服务器。

在本地 PC上执行:
1 | |
在本地 PC或者局域网内其他设备的浏览器上配置代理:
- IP:192.168.1.100
- Port:1080
在浏览器上输入http://10.0.1.103:8080即可访问Web Server上的网页
Tabby上SSH隧道使用方法
打开Tabby终端,点击右上设置图标 ⚙,然后点击左侧目录中的Profiles & connections,然后选择+ New profile, 填入如下信息:
Name:ssh-tunnelHost:10.0.1.101Port:22Username:root

然后点击PORTS,此时可按照Local、Remote、Dynamic这三种类型进行配置,配置好后,可点击Save新建并保存 SSH 会话配置。只要该会话被打开,端口转发配置将自动生效,当与 SSH 服务器会话完全关闭后,端口转发配置也将自动失效。




故障排查
1. 后台运行的SSH隧道建立命令如何彻底关闭
使用了
-f参数来建立 SSH 隧道,关闭命令行后,端口仍然被占用,该如何彻底关闭 SSH 隧道,释放端口?
在powershell中执行命令找到占用端口的进程 PID,然后将该进程强制杀掉。
1 | |
$Port是被占用的端口,输出结果中的最后一行数字就是PID。
1 | |
$PID就是输出结果中的PID。
2. SSH隧道建立后,为什么无法访问MySQL的3306端口
直连
MySQL Server的3306端口可以成功,为什么连接映射到本地的3306端口,却显示连接被拒绝?
这一般是因为 MySQL 的监听配置所限制,当连接映射本地的 3306 端口时,一般使用的IP地址为localhost或者127.0.0.1,需要在MySQL bind-address中查看是否已监听这些地址。同时 MySQL 的权限是绑定用户名+主机名的,而localhost和127.0.0.1并不完全等价,如果你的用户权限只授予了'user'@'localhost',使用 127.0.0.1连接可能会被拒绝。
3. SSH隧道建立后,为什么无法转发UDP请求
原生SSH 隧道本身不支持UDP 协议。SSH 的-L和-R参数设计的初衷是建立TCP级的加密隧道。因为UDP是无连接状态的,而SSH 协议是运行在TCP之上,所以它无法直接封装和转发UDP数据包。
4. Tabby配置了SSH会话PORTS,为什么打开会话没有效果
在 Tabby 上配置了PORTS 的 SSH 会话,保存后再打开会话,为什么 SSH 隧道还是未成功建立?
这个一般是因为本地还与 SSH 服务器还存在会话连接,此时需要关闭所有与目标 SSH 服务器的会话连接,然后再次打开配置了PORTS的 SSH 会话,才会顺利建立 SSH 隧道。
5. SSH隧道常常因为网络波动等问题而自动关闭
SSH 隧道极易受不稳定通信线路所影响,当网络高峰时期,延迟太高或者丢包率太高,可能会造成 SSH 隧道自动关闭。
针对 SSH 隧道因网络波动(如 Wi-Fi 切换、短暂掉线、长连接被防火墙切断)而自动关闭的问题,目前业界公认的最优解是 Autossh。
在powershell中安装autossh:
1 | |
然后通过autossh来建立隧道:
1 | |
$MonitorPort:这是autossh特有的参数。它会启动一个本地端口(比如 7277 )来监听连接状态。它会不断通过这个端口发送测试数据。如果发现数据不通,autossh就认为隧道已断开,并立即自动重启 SSH 进程。
如果是在Tabby中,则可以在ADVANCED界面调高如下配置:

Keep Alive Interval(Milliseconds):每5000 ms向服务器发一次心跳包。Max Keep Alive Count:如果连续10次没收到服务器回应,就主动断开重连。
参考信息
1. Tabby github开源项目
https://github.com/Eugeny/tabby
2. SSH Tunneling官方说明
https://www.ssh.com/academy/ssh/tunneling
https://www.ssh.com/academy/ssh/tunneling-example
3. A Visual Guide to SSH Tunnels
https://iximiuz.com/en/posts/ssh-tunnels/
4. SSH Port Forwarding
https://www.digitalocean.com/community/tutorials/ssh-port-forwarding