SSH 反向隧道:管理没有公网 IP 的机器
家里或内网的机器没有公网 IP,ssh 连不进去,怎么办?除了 Cloudflare Tunnel 这类商业方案,还有更朴素的做法:SSH 反向隧道。一个命令就能让你从公网机器访问内网机器,而且完全免费、零依赖。
原理
SSH 反向隧道(remote port forwarding)的思路是:让内网机器主动向外连接一台有公网 IP 的跳板机,把跳板机的某个端口转发回内网机器的 ssh(22)端口:
内网机器 --ssh -R--> 跳板机(公网)
↓
你在跳板机上:
ssh -p <映射端口> root@127.0.0.1
→ 就进入了内网机器
数据全程走 SSH 加密,安全性和普通 ssh 一样。
建立隧道
在内网机器上执行:
ssh -R 2222:127.0.0.1:22 root@跳板机IP -N -f
-R 2222:127.0.0.1:22:把跳板机的 2222 端口转发到内网机器的 22 端口-N:不执行远程命令,只做转发-f:后台运行
之后在任何地方 ssh 到跳板机,再 ssh -p 2222 root@127.0.0.1 就能进内网机器。
断线重连:一条命令不够
裸的 ssh -R 有个致命问题:网络抖动就断,断了不会自己连回来。必须加上自动重连:
while true; do
ssh -R 2222:127.0.0.1:22 root@跳板机IP -N
-o ServerAliveInterval=30 -o ServerAliveCountMax=3
-o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no
sleep 5
done
关键参数:
ServerAliveInterval=30:每 30 秒发心跳,检测连接是否存活ExitOnForwardFailure=yes:端口转发失败立即退出,让循环重连while true + sleep 5:断线 5 秒后自动重连
用 systemd 托管
写进 systemd 服务,开机自启、崩溃自拉,这才是长期方案:
[Unit]
Description=SSH Reverse Tunnel
After=network-online.target
[Service]
ExecStart=/usr/bin/ssh -R 2222:127.0.0.1:22 root@跳板机IP -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
不只转发 ssh
反向隧道的妙处是想转发什么就转发什么。内网机器的任意服务都能通过这种方式暴露:
# 把内网机器的 6185 端口(AstrBot 面板)映射到跳板机 16185
ssh -R 16185:127.0.0.1:6185 root@跳板机IP -N
跳板机上再用 nginx 反代 16185 到域名,内网服务就公网可用了。多条隧道可以叠加,一个机器暴露多个服务。
安全注意
- 密钥登录:隧道用密钥认证,别用密码。跳板机被攻破,密码就泄露了。
- 限制转发端口:跳板机 sshd 配置里加
PermitOpen限制可转发的目标,防止隧道被滥用。 - 暴露面控制:只映射需要管理的端口,别把内网全部服务都怼出去。
和 Cloudflare Tunnel 怎么选
| 方案 | 优点 | 缺点 |
|------|------|------|
| SSH 反向隧道 | 零依赖、免费、灵活 | 依赖跳板机在线,纯 TCP |
| Cloudflare Tunnel | 自带 HTTPS、无需跳板机、有防护 | 需要域名在 CF 管理 |
实际使用中两者可以共存:SSH 隧道管运维,CF Tunnel 管对外服务。家里那台机器的方案就是这样:2222 端口走 SSH 隧道给运维,网站服务走 CF Tunnel 给用户。
本文是原创文章,采用 CC BY-NC-SA 4.0 协议,完整转载请注明来自 江江
评论
隐私政策
0/500
滚动到此处加载评论...
