yanchang
yanchang
发布于 2025-05-05 / 38 阅读
1
0

(最新)通过现有公网IP或者域名,使用ssh隧道实现断线重连。远程没有公网IP的设备

通过 SSH 隧道实现无公网 IP 设备的断线重连方案

文档说明

本方案通过 SSH 反向隧道技术,实现从公网服务器访问无公网 IP 的内网设备。支持自动断线重连和 DNS 缓存刷新,确保隧道连接持久可靠。


一、方案概述

实现原理

  1. 反向隧道建立:内网设备主动向公网服务器发起 SSH 连接

  2. 端口映射:将服务器公网端口(6022)映射到内网设备的 SSH 端口(22)

  3. 自动维护:循环检测连接状态,断线后自动重连

拓扑结构

[内网设备] --SSH隧道--> [公网服务器:**22] <--互联网用户通过 **22 端口访问--> 

二、前置条件

  1. 服务器端要求

    • 已备案域名或固定公网 IP

    • 开放 SSH 端口(示例使用 9022)

    • 允许 TCP 转发(/etc/ssh/sshd_config 配置):

      GatewayPorts yes
      AllowTcpForwarding yes
  2. 客户端要求

    • 已生成 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
~     

核心功能模块

模块

功能说明

DNS 缓存刷新

每轮循环前清除系统 DNS 缓存,确保域名解析最新

动态 DNS 解析

自动解析域名对应 IP,支持服务器动态 IP 变更

智能重连机制

异常退出后等待 10 秒重试,防止频繁重连导致服务器压力

连接保活配置

通过 ServerAlive 机制检测隧道状态,60 秒心跳包保持连接活跃

关键 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 &

启动流程

  1. 初始化 SSH-Agent

  2. 加载加密私钥

  3. 后台运行隧道维护脚本

  4. 日志重定向到指定文件


四、部署步骤

1. 服务器端配置

# 修改 SSH 配置后需重启服务
sudo systemctl restart sshd

2. 客户端部署

# 设置脚本可执行权限
chmod +x ~/DATA/recallssh/*.sh

# 启动服务(首次需输入密钥密码)
./start.sh

# 查看运行状态
tail -f ~/DATA/recallssh/recallssh.log

五、连接验证

  1. 从任意客户端访问

    ssh -p **22 [内网用户名]@[服务器公网IP]
  2. 服务器端验证隧道

    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:*

六、高级配置建议

  1. 系统服务化(创建 systemd 服务)

  2. 日志轮转(配置 logrotate)

  3. 邮件告警(添加邮件通知功能)

  4. 使用 autossh(替代基础 SSH 客户端)


七、注意事项

  1. 安全警告

    • 密钥文件权限必须为 600

    • 建议为隧道单独创建受限系统账户

    • 定期轮换 SSH 密钥


评论