4. SSH 正向隧道与动态转发:SSH -L 本地端口转发、SSH -D 动态 SOCKS5 代理、浏览器代理配置、穿透公司防火墙访问内网资源
好,咱们进入正题。前面几章我们把 SSH 的基础认证和密钥管理捋了一遍,现在该聊聊真正能干活的东西了——隧道转发。
说实话,我刚开始接触 SSH 隧道时,觉得这东西挺玄乎的。后来在项目里被逼着用了一次,才发现它其实就是个「端口搬运工」。你想想看,公司内网有台数据库服务器,你在家想连它,但防火墙只开了 22 端口。怎么办?SSH 隧道就是你的秘密通道。
4.1 本地端口转发:SSH -L 的底层逻辑
本地端口转发,说白了就是把本地某个端口上的流量,通过 SSH 加密通道,扔到远程的某个目标地址上。
命令格式很简单:
ssh -L [本地地址:]本地端口:目标地址:目标端口 用户@跳板机
举个例子。假设公司内网有台 MySQL 服务器 10.0.1.100:3306,你有一台公网跳板机 jump.example.com。你想在本地用 Navicat 连那个 MySQL:
ssh -L 3307:10.0.1.100:3306 user@jump.example.com
这条命令执行后,你本地 localhost:3307 收到的所有 TCP 连接,都会被 SSH 客户端加密,送到跳板机,再由跳板机解密后转发给 10.0.1.100:3306。然后你在 Navicat 里连 localhost:3307 就行了。
关键理解:SSH 客户端是转发起点,SSH 服务端是转发中继。流量全程加密,只有最后一跳(跳板机→目标)是明文的。
我在一个金融项目里遇到过这种情况:客户要求所有数据库操作必须经过审计,但开发人员又需要本地调试。我们就在跳板机上装了审计插件,然后用 -L 强制所有流量走跳板机,一举两得。
4.1.1 绑定地址与端口冲突
默认情况下,-L 只监听 127.0.0.1。如果你想让局域网其他机器也能用这个隧道,需要显式指定 0.0.0.0:
ssh -L 0.0.0.0:3307:10.0.1.100:3306 user@jump.example.com
但要注意,这样会暴露端口。我建议非必要不开启,或者配合防火墙白名单使用。
| 参数 | 作用 | 常用场景 |
|---|---|---|
-L 8080:web:80 |
本地 8080 → 远程 web:80 | 访问内网 Web 服务 |
-L 0.0.0.0:443:10.0.1.50:443 |
全端口监听,转发 HTTPS | 团队共享内网服务 |
-L *:2222:db:5432 |
通配符绑定 | PostgreSQL 远程调试 |
4.2 动态 SOCKS5 代理:SSH -D 的威力
本地转发有个局限:你得事先知道目标地址和端口。如果我想临时访问内网任意机器呢?这时候就该 -D 上场了。
动态转发会在本地启动一个 SOCKS5 代理服务器。所有发到这个代理的请求,都会通过 SSH 隧道转发到远端,再由远端帮你发起连接。
ssh -D 1080 user@jump.example.com
这条命令在本地 127.0.0.1:1080 开启了一个 SOCKS5 代理。你只要把浏览器或应用的代理设置指向它,所有流量就都走 SSH 隧道了。
我的习惯:端口号我喜欢用 1080,这是 SOCKS 协议的默认端口,好记。但如果你同时开多个隧道,记得换端口,比如 1081、1082。
4.2.1 SOCKS5 与 HTTP 代理的区别
很多人搞混这两个概念。我简单说一下:
- HTTP 代理:只能代理 HTTP/HTTPS 流量,需要客户端主动发 CONNECT 请求。
- SOCKS5 代理:工作在更底层,可以代理 TCP 和 UDP 流量,支持任意协议(SSH、FTP、SMTP 都行)。
说白了,SOCKS5 就是个万能管道。你甚至可以在 SOCKS5 隧道里再跑一个 SSH 连接——套娃玩法,后面章节会讲。
4.3 浏览器代理配置实战
隧道建好了,怎么让浏览器用起来?我推荐两种方式。
4.3.1 手动配置(适合临时使用)
以 Chrome 为例:
- 打开设置 → 高级 → 系统 → 打开代理设置。
- 选择「使用代理服务器」。
- 地址填
127.0.0.1,端口填1080。 - 协议选 SOCKS5。
但这样有个问题:所有流量都走代理了,访问百度也走隧道,速度慢不说,还浪费带宽。
4.3.2 使用浏览器插件(推荐)
我习惯用 SwitchyOmega 这个插件。它可以按规则自动切换代理:
- 内网域名(如 *.internal.company.com)走 SOCKS5 代理。
- 其他地址直连。
配置方法:
- 安装 SwitchyOmega。
- 新建一个情景模式,选「代理服务器」。
- 协议选 SOCKS5,地址 127.0.0.1,端口 1080。
- 在「自动切换模式」里添加规则,比如
*.corp.com走这个代理。
避坑指南:我曾经在配置时选了 SOCKS4 而不是 SOCKS5,结果 DNS 解析一直在本地执行,内网域名解析失败。折腾了半小时才发现。记住:SOCKS5 支持远程 DNS 解析,SOCKS4 不支持。内网场景必须用 SOCKS5。
4.4 穿透公司防火墙访问内网资源
现在我们把前面学的串起来,看看真实场景怎么用。
4.4.1 典型拓扑
假设你在家,想访问公司内网的三个服务:
- GitLab(10.0.1.10:80)
- Jenkins(10.0.1.20:8080)
- 一台开发服务器(10.0.1.30:22)
公司防火墙只允许 SSH 出站到公网跳板机 jump.company.com。
方案一:开三个 -L 隧道。
ssh -L 8080:10.0.1.10:80 -L 8081:10.0.1.20:8080 -L 2222:10.0.1.30:22 user@jump.company.com
方案二:开一个 -D 隧道,配合浏览器插件。
ssh -D 1080 user@jump.company.com
我个人更推荐方案二。原因很简单:灵活。你临时想访问内网某个新服务,不用重新建隧道,浏览器里直接输地址就行。
4.4.2 保持隧道稳定
SSH 连接久了容易断。我一般会加几个参数:
ssh -D 1080 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -N user@jump.company.com
-N:不执行远程命令,只建隧道。ServerAliveInterval=30:每 30 秒发一个心跳包。ServerAliveCountMax=3:连续 3 次心跳无响应就断开。
这样隧道可以挂几天都不掉。我有个隧道曾经跑了 47 天,直到机房维护才断。
4.5 本章核心逻辑图
下面这张图展示了本地转发和动态转发的核心区别:
4.6 本章小结
本地转发和动态转发,一个适合固定目标,一个适合灵活访问。我平时开发时,-D 几乎常驻后台,配合浏览器插件,内网资源随便逛。但生产环境维护数据库时,我还是会用 -L,因为目标明确,不容易出错。