《反向 SSH 隧道断线自愈:systemd + 看门狗的最小实践》
反向 SSH 隧道断线自愈:systemd + 看门狗的最小实践
选题:运维实战。场景来自一台没有公网 IP 的云主机,需要长期对外暴露 SSH 与若干 TCP 服务端口。方案用反向 SSH 隧道 + systemd 服务 + 定时看门狗兜底,全程无人工值守。
问题:隧道一断,整条链路就失联
没有公网 IP 的机器要对外提供服务,常见做法是在有公网 IP 的中转机上起 sshd,本机用 ssh -R 把端口反向转发过去:
ssh -N -R 2222:localhost:22 -R 20443:localhost:20443 user@jump-host
这条命令本身没问题,问题在“长期运行”:
- 网络抖动、宿主机重启、中转机 sshd 重启,都会让隧道悄悄断掉;
ssh -N断了不会自己重连,ServerAliveInterval只能发现断线,不能恢复;- 更麻烦的是“假活”:进程还在,但转发端口已经不通,
ps看不出问题。
我们线上真实踩过的坑:一台 VM 重置后,隧道进程消失,面板、订阅、监控全部失联,直到人工发现才恢复。解决思路不是把隧道做得更“结实”,而是接受它一定会断,给它加两层自愈。
第一层:systemd 服务 + 自动重启
把隧道命令包成 systemd 服务,让 systemd 负责拉起:
[Unit]
Description=Reverse SSH tunnel to jump host
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/reverse-ssh-tunnel.sh
Restart=always
RestartSec=10
StartLimitIntervalSec=300
StartLimitBurst=10
[Install]
WantedBy=multi-user.target
要点:
Restart=always+RestartSec=10:进程退出 10 秒后自动重拉;StartLimitBurst:防止配置错误时无限狂刷,给一个上限;- 启动脚本里先做前置检查:中转机是否可达、本地待转发端口是否在监听,不满足就退出让 systemd 重试,而不是挂一个半死不活的隧道。
光有这一层还不够。systemd 只能看到“进程是否活着”,看不到“转发是否真的通”。进程活着但转发已死的“假活”状态,需要第二层来发现。
第二层:定时看门狗,做端到端验证
看门狗是一个每 10 分钟跑一次的脚本,只做三件事:
- 查进程:隧道进程在不在;
- 查端口:中转机上的转发端口能不能连通(从本机经隧道回连一次,或直接
nc -z探测); - 查服务:端口后面真正要暴露的服务(面板、订阅接口)是否返回正常 HTTP 状态码。
任何一项失败,先 systemctl restart 隧道服务;重启后复查仍失败,再按预设的恢复流程走(重建配置、重装缺失组件)。我们的做法是把恢复逻辑写进一个幂等的 restore.sh,看门狗只负责“发现问题并触发恢复”,恢复本身由脚本负责。
# 看门狗核心逻辑(示意)
if ! pgrep -f "ssh -N -R 2222" >/dev/null; then
systemctl restart reverse-ssh-tunnel
fi
# 端到端:经中转机回连本机 22 端口
if ! timeout 5 ssh -p 2222 -o ConnectTimeout=5 jump-host true 2>/dev/null; then
systemctl restart reverse-ssh-tunnel
fi
关键经验:验证必须端到端。只查进程等于没查,2026 年 10 月底我们就吃过亏:dpkg -s 查包状态返回成功,实际服务根本没起来——状态查询本身也可能撒谎。看门狗的判断标准永远是“真实流量能不能走通”,而不是“某个命令的退出码”。
第三层(可选):出站受限时的 egress 代理
如果本机出站也被限制(比如只能走 HTTP CONNECT 代理出站、直连 22 端口被墙),隧道命令本身也要走代理:
ssh -o ProxyCommand="nc -X connect -x proxy-host:8080 %h %p" \
-N -R 2222:localhost:22 user@jump-host
或者用 ProxyCommand 指向一个 TLS 封装脚本。这一层与看门狗无关,但它是隧道能在受限网络里建立的前提。把代理配置写进独立的 env 文件(600 权限),启动脚本 source 它,不要把凭据写进 systemd unit。
恢复脚本要幂等
看门狗触发的 restore.sh 必须满足幂等:跑一次和跑十次结果一样。我们的恢复脚本按段组织,每段先检查最终状态、再决定是否修复:
- 检查服务是否 active,不 active 才重建;
- 检查二进制是否存在,不存在才安装(先 apt,失败走本地离线 deb 兜底);
- 检查配置文件、密钥、systemd unit 是否齐全,缺失才补写;
- 最后统一验证:隧道进程、端口转发、服务 HTTP 状态码三项全绿才算恢复成功。
2026 年 11 月初的一次实测:VM 重置后看门狗检测到 9 个组件缺失,触发恢复,约 2 分钟内全部重建并验证通过,全程无人干预。没有幂等保证的恢复脚本不敢交给定时任务自动跑——重复执行可能把好好的配置覆盖掉。
效果与注意事项
- 隧道断线后 10 秒内 systemd 重拉;假活状态最迟 10 分钟内被看门狗发现并重启;
- 夜间无人值守的重置也能在下次看门狗巡检时自动恢复;
- 注意事项:看门狗本身也要被 systemd timer 或 cron 守护,别让看门狗自己悄悄停了;恢复脚本的操作要写日志,方便事后复盘哪一段触发过。
小结
反向 SSH 隧道的自愈不需要复杂方案,三层就够:systemd 管进程生死、看门狗做端到端验证、幂等恢复脚本兜底。核心就一句话:不要相信进程状态,只相信真实流量。
- 点赞
- 收藏
- 关注作者
评论(0)