SSH本地隧道 远程隧道 动态隧道

noteSSH

2026-03-042 min

SSH隧道基本原理

SSH不仅仅是远程登录工具,更重要的是它在客户端和服务端之间建立加密通道。当SSH登录成功后:

  • 客户端输入的命令(如ls)会被封装成加密数据包传输到服务端
  • 命令执行结果以同样的加密方式返回给客户端
  • 防火墙只知道进出的是SSH数据包,无法知道数据包内容

网络访问限制场景

假设有以下网络拓扑:

  • SSH客户端(本地电脑)
  • SSH服务端(跳板机,有公网IP)
  • 数据库服务器(内网,只有内网IP)

存在两个主要限制:

  1. 网络限制:公网无法直接访问内网
  2. 端口限制
    • SSH服务端默认监听22端口
    • 数据库默认监听3306端口
    • 如果只开放特定端口,其他服务进程无法访问

SSH本地隧道(Local Tunnel)

工作原理

本地隧道将本地端口的流量通过SSH加密通道转发到远程目标:

  1. SSH客户端监听本地新端口(如3307
  2. 本地应用连接3307端口时,SSH客户端拦截请求
  3. 请求通过SSH加密通道发送给跳板机
  4. 跳板机解密后转发给内网数据库的3306端口
  5. 响应数据原路返回

命令格式

bash
ssh -L [本地地址:]本地端口:目标主机:目标端口 用户名@跳板机地址 -i 私钥文件

实操示例

环境准备:

  • 跳板机:有公网IP,开放入站22端口
  • 数据库服务器:只有内网IP,与跳板机在同一网络,开放入站3306端口

建立本地隧道:

bash
ssh -L 127.0.0.1:3307:数据库内网IP:3306 用户名@跳板机公网IP -i ~/.ssh/private_key

或者省略本地地址(支持IPv4和IPv6):

bash
ssh -L 3307:数据库内网IP:3306 用户名@跳板机公网IP -i ~/.ssh/private_key

使用隧道访问数据库:

bash
# 在新终端中连接本地3307端口mysql -h 127.0.0.1 -P 3307 -u 数据库用户名 -p

常用参数

  • -N:不执行远程命令,只建立隧道
  • -f:后台运行隧道
bash
ssh -L 3307:数据库内网IP:3306 -N -f 用户名@跳板机公网IP -i ~/.ssh/private_key

配置检查

确保跳板机的SSH配置文件 /etc/ssh/sshd_config 中:

AllowTcpForwarding yes

SSH远程隧道(Remote Tunnel)

应用场景

当需要从远程服务器访问本地电脑时,但本地电脑:

  • 位于NAT后面,没有公网IP
  • 路由器屏蔽了SSH的22端口

工作原理

远程隧道让远程服务器能够访问本地电脑:

  1. 从本地向服务器发起SSH连接
  2. 同时建立反向隧道,服务器监听指定端口(如2200
  3. 服务器访问2200端口的流量会转发到本地22端口
  4. 实现内网穿透

命令格式

bash
ssh -R [远程地址:]远程端口:本地主机:本地端口 用户名@远程服务器 -i 私钥文件

实操示例

本地电脑准备:

  • 开启SSH服务(macOS在"系统偏好设置"→"共享"→"远程登录")
  • 确认SSH服务监听22端口:
bash
lsof -i :22

建立远程隧道:

bash
ssh -R 2200:localhost:22 用户名@远程服务器IP -i ~/.ssh/private_key

在远程服务器上验证:

bash
# 检查2200端口是否在监听netstat -tlnp | grep 2200
# 通过隧道SSH回本地电脑ssh 本地用户名@localhost -p 2200

扩展访问权限

默认情况下,远程隧道只能被建立隧道的服务器使用。如需让其他公网机器也能访问,需在远程服务器的 /etc/ssh/sshd_config 中设置:

GatewayPorts yes

SSH动态隧道(Dynamic Tunnel)

解决的问题

本地隧道和远程隧道都是一对一的端口映射,存在以下限制:

  • 多个服务需要建立多条隧道
  • 可能发生端口冲突
  • 需要预先知道目标IP和端口
  • IP地址变化时需要重新配置

工作原理

动态隧道通过SOCKS5协议实现:

  • 只需指定一个本地监听端口
  • 该端口成为SOCKS5代理服务器
  • 支持SOCKS5的应用可通过此端口访问远程网络中的任意地址和端口

命令格式

bash
ssh -D 本地端口 用户名@远程服务器 -i 私钥文件

实操示例

建立动态隧道:

bash
ssh -D 1080 用户名@远程服务器IP -i ~/.ssh/private_key

使用动态隧道访问服务:

bash
# 通过SOCKS5代理访问远程服务器的8001端口curl --socks5-hostname localhost:1080 127.0.0.1:8001
# 访问远程服务器的8002端口curl --socks5-hostname localhost:1080 127.0.0.1:8002

动态隧道优势

  1. 一条隧道访问多个服务:无需为每个服务单独建立隧道
  2. 动态目标:建立隧道时无需指定目标IP和端口
  3. 灵活性强:可访问远程服务器能访问的任意网络资源
  4. 配置简单:只需指定一个本地端口

三种隧道对比

隧道类型参数起点终点适用场景
本地隧道-L本地电脑远程指定服务访问远程内网特定服务
远程隧道-R远程服务器本地电脑远程访问本地服务(内网穿透)
动态隧道-D本地电脑动态(SOCKS5代理)访问远程网络中的多个服务

实用技巧

命令换行

长命令可使用反斜杠换行:

bash
ssh -L 3307:数据库内网IP:3306 \    用户名@跳板机公网IP \    -i ~/.ssh/private_key

后台运行

bash
ssh -D 1080 -N -f 用户名@远程服务器IP -i ~/.ssh/private_key

配置文件检查

确保SSH服务端配置支持端口转发:

bash
# 检查SSH配置grep -i "allowtcpforwarding\|gatewayports" /etc/ssh/sshd_config

SSH隧道是网络穿透和安全访问的强大工具,掌握这三种隧道类型可以解决大部分网络访问限制问题。