SSH隧道实战指南:本地与远程端口转发

iximiuz 发布于 2026-06-23 阅读 25

SSH隧道(端口转发)是一种强大的网络技术,允许通过SSH连接访问私有网络服务。文章详细介绍了四种SSH隧道模式:本地端口转发(-L)将远程服务映射到本地端口;远程端口转发(-R)将本地服务暴露到远程;动态本地转发(-D)将SSH客户端变为SOCKS代理;动态远程转发将SSH服务器变为SOCKS代理。还涵盖了通过跳板机访问VPC内网、暴露家庭网络服务等实际用例。文章提供了命令语法、图解和记忆技巧,帮助读者快速掌握SSH隧道的使用。

图像

以清晰直观的方式解释 SSH 端口转发:如何使用本地和远程端口转发、可能需要调整哪些 sshd 设置,以及如何记住正确的标志。

SSH 是古老技术至今仍在广泛使用的又一例证。从长远来看,学会几个 SSH 技巧,可能比掌握十几个注定下季度就被弃用的云原生工具或 AI Agent 框架更有价值。

这项技术中我最喜欢的一部分是 SSH 隧道。只需使用标准工具,通常一条命令就能实现以下功能:

但尽管我每天都在使用 SSH 隧道,每次回忆正确的命令时总要花点时间。该用本地隧道还是远程隧道?标志是什么?是 local_port:remote_port 还是反过来?因此,我决定彻底搞懂它,最终制作了一系列实验和一张可视化速查表。

图像

SSH 隧道速查表

本地端口转发

从我最常用的开始。通常,远程机器上可能有服务监听在 localhost 或私有接口上,而我只能通过其公网 IP 进行 SSH 连接。但我迫切需要从本地机器访问这个端口。几个典型例子:

  • 从笔记本电脑使用你喜爱的 UI 工具访问私有远程数据库(MySQL、Postgres、Redis 等)。
  • 使用浏览器访问仅暴露给私有网络的 Web 应用程序。
  • 从笔记本电脑访问容器的端口,而不在服务器的公共接口上发布它。

以上所有用例都可以通过一条 ssh 命令解决:

ssh -L [local_addr:]local_port:remote_addr:remote_port [user@]sshd_addr

-L 标志表示我们正在启动本地端口转发。其实际含义是:

  • 在本地机器上,SSH 客户端将开始监听 local_port(很可能在 localhost 上,但取决于具体情况 —— 请查看 GatewayPorts 设置)。
  • 任何发往此端口的流量都将被转发到 remote_addr:remote_port,该地址可从你 SSH 登录的远程机器上访问。

以下是它在图上的样子:

图像

使用堡垒主机的本地端口转发

初看可能不明显,但 ssh -L 命令允许将本地端口转发到任何机器上的远程端口,而不仅仅是 SSH 服务器本身。注意 remote_addrsshd_addr 可能相同也可能不同:

ssh -L [local_addr:]local_port:remote_addr:remote_port [user@]sshd_addr

用于访问私有目标的远程 SSH 服务器通常称为堡垒或跳板主机。这是我在脑海中想象此场景的方式:

图像

我经常使用上述技巧来访问从堡垒主机可达但从我笔记本电脑不可达的端点(例如,使用具有私有和公共接口的 EC2 实例连接到 OpenSearch 集群或任何完全部署在 VPC 内的服务)。

远程端口转发

另一个常见(但方向相反)的场景是,你想临时将本地服务暴露给外部世界。当然,你需要一个面向公网的入口网关服务器。好消息是,任何带有 SSH 守护进程的公网服务器都可以作为这样的网关:

ssh -R [remote_addr:]remote_port:local_addr:local_port [user@]gateway_addr

上面的命令看起来不比 ssh -L 复杂。但有一个陷阱……

默认情况下,上述 SSH 隧道只允许使用网关的 localhost 作为远程地址。换句话说,你的本地端口只能在网关服务器内部访问,这很可能不是你真正需要的。例如,我通常希望使用网关的公网地址作为远程地址,将本地服务暴露给公共互联网。为此,需要将 SSH 服务器配置为 GatewayPorts yes

远程端口转发的用途如下:

以下是远程端口转发的可视化图示:

图像

远程端口转发到家庭或私有网络

与本地端口转发类似,远程端口转发也有自己的堡垒或跳板主机模式。但这次,运行 SSH 客户端的机器(例如你的开发笔记本电脑)扮演跳板主机的角色。具体来说,它允许将通过笔记本电脑可达的家庭(或私有)网络端口,通过充当入口网关的远程 SSH 服务器暴露给外部世界:

ssh -R [remote_addr:]remote_port:local_addr:local_port [user@]gateway_addr

看起来与简单的远程 SSH 隧道几乎相同,但 local_addr:local_port 变成了家庭网络中设备的地址。以下是它在图中的样子:

图像

我通常将笔记本电脑作为瘦客户端使用,而实际开发在远程服务器上进行。有时,这样的远程服务器可能位于我的家庭网络中,并且没有或受限制的互联网访问(为了额外隔离)。这时我可能希望依赖远程端口转发,将家庭服务器上的服务暴露给公共互联网,利用我的笔记本电脑(可同时访问内部开发服务器和远程 SSH 服务器(入口网关))作为跳板主机。

动态本地端口转发

这种转发模式对客户端来说不那么透明,但比常规的本地端口转发灵活得多。动态(本地)端口转发不是将本地端口连接到单个远程目标(如 ssh -L 所做的那样),而是将 SSH 客户端转换为本地 SOCKS 代理。任何支持 SOCKS 的应用程序都可以通过它发送流量,每次连接选择实际的目标主机和端口——这些信息会被发送到 SSH 服务器,由服务器解析目标并建立连接:

ssh -D [local_addr:]local_port [user@]sshd_addr

使用 -D 标志时,你机器上的 SSH 客户端会启动一个 SOCKS 代理,监听 local_port(默认在 localhost 上)。通过代理建立的每个连接都会被转发到 SOCKS 客户端要求的任何地址,该地址从 sshd_addr 机器可达。

换句话说,就像 ssh -L,但你不需要提前指定单一的 remote_addr:remote_port,因为 SOCKS 协议允许在每次连接开始时指定目标(通过在有效载荷之前发送几个额外字节)。一个(本地)代理端口就能让你访问从(远程)SSH 服务器可达的每个主机和端口。

图像

动态端口转发的用途如下:

  • 通过堡垒访问私有网络中的 API,无需为每个服务创建单独的隧道。
  • 通过单个跳板主机浏览远程网络中的内部 Web 应用。
  • 通过一个 EC2 实例从笔记本电脑访问一系列 VPC 端点。

动态远程端口转发

正如 ssh -L 有动态版本 ssh -D 一样,ssh -R 命令也有自己的动态模式。如果你从 -R 中移除固定的目标,只传递一个端口,OpenSSH 会将 SSH 服务器本身转换为 SOCKS 代理。这正好是 -D 的镜像:这次代理位于网关上,通过它建立的每个连接都会隧道回 SSH 客户端,并从客户端的视角解析:

ssh -R [bind_address:]port [user@]gateway_addr

不带目标的 -R 标志意味着:

  • 在远程网关上,SSH 服务器启动一个 SOCKS 代理,监听 port(默认在网关的 localhost 上;如果设置了 GatewayPorts yes,则在所有接口上监听)。
  • 通过代理建立的每个连接都会隧道回 SSH 客户端,并转发到 SOCKS 客户端要求的任何地址,该地址从客户端侧可达。

这就像常规的 ssh -R,但你不需要提前选择一个单一的 local_addr:local_port。网关上的一个代理就暴露了从 SSH 客户端可达的每个主机和端口——例如,整个家庭网络。

图像

总结

以下是快速回顾和一些助记符,帮助你记住 SSH 隧道命令:

  • 本地端口转发(ssh -L)使远程服务在本地端口上可用。
  • 远程端口转发(ssh -R)使本地服务在远程端口上可用。
  • 动态本地端口转发(ssh -D)将本地 ssh 客户端转换为 SOCKS 代理。
  • 动态远程端口转发(不带目标的 ssh -R)将 sshd 服务器转换为 SOCKS 代理。
  • 本地端口转发(ssh -L)意味着 ssh 客户端开始监听新端口。
  • 远程端口转发(ssh -R)意味着 sshd 服务器开始监听额外端口。
  • local 既可以指 SSH 客户端机器,也可以指从该机器可达的内部主机。
  • remote 既可以指 SSH 服务器机器(sshd),也可以指从该机器可达的任何主机。

助记符是 ssh -L local:remotessh -R remote:local,并且总是左侧打开一个新端口。

希望以上材料能帮助你成为 SSH 隧道大师 🧙

  • 原文链接: x.com/iximiuz/status/206...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论