通过 SSH 隧道实现无公网 IP 设备的断线重连方案
文档说明
本方案通过 SSH 反向隧道技术,实现从公网服务器访问无公网 IP 的内网设备。支持自动断线重连和 DNS 缓存刷新,确保隧道连接持久可靠。
一、方案概述
实现原理
反向隧道建立:内网设备主动向公网服务器发起 SSH 连接
端口映射:将服务器公网端口(6022)映射到内网设备的 SSH 端口(22)
自动维护:循环检测连接状态,断线后自动重连
拓扑结构
[内网设备] --SSH隧道--> [公网服务器:**22] <--互联网用户通过 **22 端口访问--> 二、前置条件
服务器端要求
已备案域名或固定公网 IP
开放 SSH 端口(示例使用 9022)
允许 TCP 转发(
/etc/ssh/sshd_config配置):GatewayPorts yes AllowTcpForwarding yes
客户端要求
已生成 SSH 密钥对(推荐 ed25519)
公钥已添加到服务器的
authorized_keys
三、脚本详解
1. recallssh.sh - 隧道维护脚本
#!/bin/bash
# 启动 ssh-agent 并加载私钥
# 目标服务器信息
REMOTE_USER="yanchang"
REMOTE_HOST="www.yanchang.xyz"
REMOTE_PORT=9022
TUNNEL_SPEC="0.0.0.0:6022:localhost:22"
while true; do
# 刷新 DNS 缓存
echo "[$(date)] 刷新 DNS 缓存..."
sudo systemd-resolve --flush-caches
# 解析远程主机地址
REMOTE_IP=$(dig +short "$REMOTE_HOST" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1)
if [ -z "$REMOTE_IP" ]; then
echo "[$(date)] 警告: DNS 解析失败,请检查网络连接或 DNS 配置"
else
echo "[$(date)] 成功解析 $REMOTE_HOST → $REMOTE_IP"
fi
# 建立 SSH 隧道
echo "[$(date)] 正在建立带密钥认证的 SSH 隧道..."
ssh -i ~/.ssh/id_ed25519 -N -T -R ${TUNNEL_SPEC} -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=3 \
-o ExitOnForwardFailure=yes \
-o TCPKeepAlive=yes \
-o BatchMode=yes \
-o StrictHostKeyChecking=no
echo "[$(date)] 连接异常断开,10秒后重试..."
sleep 10
done
~ 核心功能模块
关键 SSH 参数
ssh -i ~/.ssh/id_ed25519 \
-N -T \ # 不执行命令/不分配终端
-R ${TUNNEL_SPEC} \ # 反向隧道配置
-o ExitOnForwardFailure=yes \ # 端口占用时立即退出
-o TCPKeepAlive=yes \ # 启用 TCP 层保活
-o BatchMode=yes \ # 禁用交互式认证2. start.sh - 服务启动脚本
#!/bin/bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
sudo ls ~/DATA/recallssh/
nohup sh ~/DATA/recallssh/recallssh.sh > ~/DATA/recallssh/recallssh.log 2>&1 &启动流程
初始化 SSH-Agent
加载加密私钥
后台运行隧道维护脚本
日志重定向到指定文件
四、部署步骤
1. 服务器端配置
# 修改 SSH 配置后需重启服务
sudo systemctl restart sshd
2. 客户端部署
# 设置脚本可执行权限
chmod +x ~/DATA/recallssh/*.sh
# 启动服务(首次需输入密钥密码)
./start.sh
# 查看运行状态
tail -f ~/DATA/recallssh/recallssh.log五、连接验证
从任意客户端访问:
ssh -p **22 [内网用户名]@[服务器公网IP]服务器端验证隧道:
pgrep -af "**22:localhost:22" pgrep -af "recallssh.sh" sudo netstat -tuln | grep 6022 # 应显示:tcp 0 0 0.0.0.0:6022 0.0.0.0:*
六、高级配置建议
系统服务化(创建 systemd 服务)
日志轮转(配置 logrotate)
邮件告警(添加邮件通知功能)
使用 autossh(替代基础 SSH 客户端)
七、注意事项
安全警告
密钥文件权限必须为 600
建议为隧道单独创建受限系统账户
定期轮换 SSH 密钥