5月28日 00:47

SSH 端口转发有哪些类型?本地转发、远程转发和动态转发怎么用?

SSH 端口转发(Port Forwarding),也叫 SSH 隧道(SSH Tunneling),是通过 SSH 加密连接转发任意 TCP 流量的技术。它能让不安全的协议获得加密保护,也能穿透网络限制访问内网服务。SSH 端口转发有三种类型:本地转发(-L)、远程转发(-R)和动态转发(-D),三者数据流向和使用场景各不相同。

本地端口转发(-L)

本地端口转发将本地某个端口的流量,经 SSH 隧道转发到远程服务器可达的目标地址。换句话说,你访问本机的一个端口,数据会自动通过 SSH 加密隧道到达远端目标。

数据流向:本机应用 → 本地端口 → SSH 隧道 → SSH 服务器 → 目标主机:目标端口

bash
# 语法 ssh -L [本地地址:]本地端口:目标主机:目标端口 用户@SSH服务器 # 访问远程 MySQL ssh -L 3306:localhost:3306 user@remote-server # 现在连接 localhost:3306 等同于连接远程服务器的 MySQL # 通过跳板机访问内网服务 ssh -L 8080:192.168.1.50:80 user@jump-host # 本机访问 localhost:8080 → jump-host 转发 → 192.168.1.50:80

注意 -L 后面的「目标主机:目标端口」是从 SSH 服务器的视角解析的,所以 localhost 指的是 SSH 服务器自身。这是理解本地转发的关键——目标地址是远端网络中的地址,不是你本机的地址。

典型场景:远程数据库只有内网可访问,你在外网通过 SSH 跳板机建立本地转发,即可用本地客户端直连远程数据库。

远程端口转发(-R)

远程端口转发与本地转发方向相反:把远程服务器上的某个端口流量,经 SSH 隧道转发回本机可达的目标地址。这在本地服务需要暴露给远程网络时使用。

数据流向:远程客户端 → 远程端口 → SSH 隧道 → 本机 → 目标主机:目标端口

bash
# 语法 ssh -R [远程地址:]远程端口:目标主机:目标端口 用户@SSH服务器 # 让远程服务器能访问你本地的 Web 服务 ssh -R 8080:localhost:3000 user@public-server # 他人访问 public-server:8080 → SSH 隧道 → 你本机的 localhost:3000 # 绑定到远程服务器的所有网络接口 ssh -R 0.0.0.0:8080:localhost:3000 user@public-server

远程转发默认只绑定到远程服务器的 127.0.0.1,外部无法连接。要让其他机器也能通过该端口访问,需要在远程服务器的 /etc/ssh/sshd_config 中设置 GatewayPorts yes,然后重启 sshd。

典型场景:本地开发了一个 Web 应用,需要临时让外部人员预览,但本机没有公网 IP。通过远程转发把本地服务映射到公网服务器的端口上,外部即可访问。

动态端口转发(-D)

动态端口转发在本地创建一个 SOCKS 代理端口,根据应用层协议动态决定流量转发目标。与本地转发只能指定一个固定目标不同,动态转发支持任意目标。

数据流向:本机应用(SOCKS 客户端)→ 本地 SOCKS 端口 → SSH 隧道 → SSH 服务器 → 任意目标

bash
# 语法 ssh -D [本地地址:]本地端口 用户@SSH服务器 # 创建 SOCKS5 代理 ssh -D 1080 user@proxy-server # 配置浏览器或系统代理为 socks5://127.0.0.1:1080

动态转发本质上把 SSH 服务器变成了一个代理服务器,所有通过 SOCKS5 协议发出的请求都由 SSH 服务器代为访问,再把结果加密返回。

典型场景:在不安全的网络环境中,通过 SSH 服务器代理所有流量,确保通信加密且无法被中间人窃听。

三种转发的区别与选择

对比项本地转发 -L远程转发 -R动态转发 -D
数据方向本机→远端远端→本机本机→远端(动态目标)
目标数量固定一个固定一个任意多个
协议支持任意 TCP任意 TCPSOCKS5 代理
典型用途访问内网服务内网穿透安全代理/翻墙

选择原则:访问特定内网服务用 -L,暴露本地服务用 -R,需要灵活代理多种目标用 -D。

SSH 配置文件简化操作

频繁使用端口转发时,可以在 ~/.ssh/config 中预设,避免每次输入长命令:

shell
Host db-tunnel HostName jump.example.com User deploy LocalForward 3306 db-server:3306 ServerAliveInterval 60 ServerAliveCountMax 3 Host dev-expose HostName public.example.com User deploy RemoteForward 8080 localhost:3000

使用时只需 ssh db-tunnelssh dev-expose,转发规则自动生效。

常用参数组合

bash
# -N: 不执行远程命令,只做端口转发 # -f: 后台运行 # -C: 启用压缩 # 后台运行本地转发 ssh -f -N -L 3306:db-server:3306 user@jump-host # 保持连接不断 ssh -o ServerAliveInterval=60 -N -L 3306:localhost:3306 user@remote-server # 使用 autossh 自动重连(适合持久化隧道) autossh -M 0 -o ServerAliveInterval=60 -N -L 3306:localhost:3306 user@remote-server

-N-f 是端口转发最常用的两个参数:-N 避免 SSH 打开一个不需要的 shell,-f 让隧道在后台运行不占用终端。

安全注意事项

  1. 默认绑定 localhost:-L 和 -D 默认只监听 127.0.0.1,不要随意改为 0.0.0.0,否则局域网内任何人都可能使用你的隧道
  2. GatewayPorts 慎开:开启后远程转发的端口对公网可见,务必配合防火墙限制来源 IP
  3. 禁用端口转发:服务器可在 sshd_config 中设置 AllowTcpForwarding no 禁止所有端口转发,适用于只允许交互式登录的场景
  4. 密钥认证优于密码:端口转发往往配置为自动连接,使用密钥认证更安全且免输入密码
  5. 审计活跃隧道:定期检查服务器上的 SSH 转发连接,防止未授权的隧道

故障排查

bash
# 确认端口是否在监听 ss -tlnp | grep 3306 # 测试隧道是否通畅 curl -x socks5://127.0.0.1:1080 http://目标地址 # 动态转发 telnet localhost 3306 # 本地转发 # 查看 SSH 连接日志 ssh -v -L 3306:localhost:3306 user@remote-server # -v 参数会输出详细的连接过程,定位握手或认证问题 # 常见错误 # bind: Address already in use → 本地端口被占用,换一个端口 # Channel 3: open failed: connect failed → 目标地址从 SSH 服务器不可达 # Permission denied → SSH 认证失败,检查密钥或密码
标签:SSH