SSH 隧道实战:把远程服务安全地映射到本地
有些服务天生就不该对公网开放:数据库、管理后台、只有本机能访问的内部面板。
但你又需要从自己电脑上打开它。
常见的错误做法是改配置、开防火墙、把服务挂到公网上——为了图一时方便,把攻击面扩大了几十倍。正确做法是 SSH 隧道:不新增任何一个监听端口,把远端的东西"搬"到本地来用。
一、本地转发:把远端服务搬到本地
最常用的模式。命令结构:
ssh -N -L 本机端口:目标地址:目标端口 用户@跳板机
-N 表示只做转发,不执行命令,也不开交互 shell。
假设远端有一台机器上的数据库只监听本机,你想在自己电脑上用客户端连它:
ssh -N -L 13306:<目标主机>:3306 user@server
这条命令跑起来之后,连接自己电脑的 13306 端口,流量就会经过 SSH 加密到 server,再由 server 转发到它自己的 3306。
注意两件事:端口号是随手写的示例,跟实际服务无关;<目标主机> 是占位符,填 127.0.0.1 就表示"跳板机自己"。真正要记住的是三段结构:本地端口 : 目标主机 : 目标端口。
关键在于:目标地址是从跳板机的视角去看的。所以 127.0.0.1 指的是跳板机自己,而不是你的电脑。这个视角切换是新手最容易绕晕的地方。
二、远程转发:反过来,把本地服务推上去
-R 是反方向。把本机的服务暴露到远端去:
ssh -N -R 8080:<目标主机>:3000 user@server
意思是:在 server 上监听 8080,把流量转发回你本机的 3000。
这个模式适合"我本地在调试一个服务,但需要让远端机器访问到它"。比如远端有个回调服务要访问你的开发机。
注意默认情况下,-R 绑定的是远端的 127.0.0.1,也就是只有远端那台机器自己能访问。想让别人也能访问,需要在服务端 sshd 配置里打开 GatewayPorts,并且绑定到 0.0.0.0。
这一步要想清楚再开,因为它等于把你本机的服务暴露到网络上。
三、动态转发:一个临时的网络代理
-D 比较特殊,它在本机开一个代理端口:
ssh -N -D 1080 user@server
之后把浏览器的代理设成这个端口,所有流量都会经过 server 出去。
适合临时需要从另一个网络出口访问的场景。但它只是转发,不解决 DNS 污染之类的问题,也不该被当成长期的翻墙方案来用。
四、让隧道稳定:三个必备参数
裸的 ssh -L 有两个毛病:长时间不用会断,断了不会自己重连。
保持连接,在 ~/.ssh/config 里加:
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
TCPKeepAlive yes
意思是每 30 秒发一次心跳,连续 3 次没回应就认为断了。不加这个,中间的 NAT 或防火墙会在几分钟没流量后悄悄把连接回收掉,你只看到"连不上了",却找不到原因。
自动重连,写成循环:
while true; do
ssh -N -L 13306:<目标主机>:3306 user@server
sleep 5
done
多路复用,让第二条以后的连接瞬间建立:
Host server
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
配了之后,第一次连接建立后,后续所有连接复用这条通道,不再重复握手。开一堆终端窗口的时候,差别非常明显。
五、几个真会踩的坑
坑一:端口被占用。 本地那个端口如果已经有程序在听,ssh -L 会静默失败或者直接报错退出。先确认端口空着。
坑二:-N 之前加了别的参数。 比如同时想开 shell 又想转发,那 -N 就不能用。两者只能选一个。
坑三:以为关掉终端隧道还在。 隧道跟着 ssh 进程走,进程没了隧道就没了。要长期跑,用前面那个 while 循环配 systemd,或者干脆用 autossh。
坑四:把 -R 当成安全的暴露方式。 只要绑到了 0.0.0.0,就等于开了公网入口,SSH 加密只保护传输过程,不保护"谁能连进来"。该加认证就加认证。
六、小结
想干什么 | 用哪个
在本地访问远端服务 | -L 本地转发
让远端访问我本地的服务 | -R 远程转发
临时换个网络出口 | -D 动态转发
一句话记住方向:-L 是"拉过来",-R 是"推过去",-D 是"开个代理"。
用好隧道,很多"必须开公网"的需求其实根本不需要开。
- 点赞
- 收藏
- 关注作者
评论(0)