Skip to content

SSH 反向隧道远程访问内网开发机配置指南 ​

开发环境放在内网是常见做法:公司云桌面、实验室服务器只能从内网访问,手机和外部电脑在没有 VPN 入口时无法连入。只要内网机器能访问公网,就有一条通用出路——让它主动出站,建立反向 SSH 隧道到一台公网 VPS,外部设备再通过 VPS 跳转进来。本文给出从 VPS 加固、隧道保活到手机客户端连接的完整配置流程,适合需要在移动设备上远程使用内网开发环境(例如挂着一个长期运行的终端会话或 AI 编程助手)的开发者。

架构 ​

关键点在于连接方向:内网机器无法被动的入站连接触达,但它可以主动出站连到 VPS,并在 VPS 上开一个转发端口。外部设备先登录 VPS,再经这个端口到达内网机器。

端口规划:

端口 用途 监听位置
22 VPS SSH 服务(外部连接 + 内网机建隧道) VPS
2222 反向隧道映射端口(指向内网机 22) VPS,由内网机主动建立

一、VPS 配置 ​

1.1 创建专用用户 ​

bash
sudo adduser jump
sudo usermod -aG sudo jump

1.2 配置 SSH Key 登录 ​

本地生成密钥并上传:

bash
ssh-keygen -t ed25519 -f ~/.ssh/jump_key -C "jump-vps"
ssh-copy-id -i ~/.ssh/jump_key.pub jump@your-vps-ip

1.3 配置 sshd ​

编辑 /etc/ssh/sshd_config:

ini
Port 22
PermitRootLogin no
PasswordAuthentication no
AllowTcpForwarding yes
GatewayPorts clientspecified
ClientAliveInterval 60
ClientAliveCountMax 3

验证并重启:

bash
sudo sshd -t && sudo systemctl restart sshd
sudo ss -tlnp | grep sshd

1.4 安装 fail2ban ​

公网 VPS 的 22 端口会持续收到扫描和爆破尝试,fail2ban 可以自动封禁多次失败的来源 IP:

bash
sudo apt update && sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

如果 fail2ban 误封 IP,解封:

bash
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 你的IP

1.5 防火墙放行 ​

bash
sudo ufw allow 22/tcp
sudo ufw enable

云厂商控制台的安全组也要放行 22 端口。

二、内网开发机配置 ​

2.1 安装必要软件 ​

bash
# Node.js 22 LTS
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

# Claude Code
npm install -g @anthropic-ai/claude-code

# autossh(自动重连)
sudo apt install -y autossh

# tmux
sudo apt install -y tmux

2.2 配置 SSH Key(内网机到 VPS) ​

bash
# 生成无密码密钥(用于自动化)
ssh-keygen -t ed25519 -f ~/.ssh/reverse_tunnel -N "" -C "intranet-desktop-tunnel"

# 上传公钥到 VPS
ssh-copy-id -i ~/.ssh/reverse_tunnel.pub jump@your-vps-ip

# 修复私钥权限(必须 600,否则 SSH 拒绝使用)
chmod 600 ~/.ssh/reverse_tunnel

踩坑: 私钥权限必须为 600,0664 等更开放的权限会导致 SSH 报 UNPROTECTED PRIVATE KEY FILE 错误并拒绝使用该密钥。

2.3 配置 SSH config(内网机需要代理出网时) ​

编辑 ~/.ssh/config:

ini
Host jump-vps
    HostName your-vps-ip
    User jump
    Port 22
    IdentityFile ~/.ssh/reverse_tunnel
    # 通过 HTTP 代理连接(如果需要)
    ProxyCommand /usr/bin/ncat --proxy your-proxy:port --proxy-type http %h %p

不需要代理则去掉 ProxyCommand 那行。

测试连接:

bash
ssh jump-vps echo "连接成功"

2.4 手动建立反向隧道 ​

bash
ssh -R 2222:localhost:22 -N jump-vps

参数说明:

  • -R 2222:localhost:22:在 VPS 上开 2222 端口,转发到内网机的 22 端口
  • -N:不执行远程命令,只建隧道
  • 光标停住无输出 = 成功

踩坑: 反向隧道端口不能和 VPS 已有服务端口冲突,否则报 remote port forwarding failed。

在 VPS 上验证隧道:

bash
ss -tlnp | grep 2222

2.5 systemd 自动保活 ​

手动建立的隧道在断线后不会自动恢复,用 autossh + systemd 做成常驻服务。

创建 /etc/systemd/system/reverse-tunnel.service:

ini
[Unit]
Description=Reverse SSH Tunnel to VPS
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=你的内网机用户名
ExecStart=/usr/bin/autossh -M 0 -N \
    -o "ServerAliveInterval=30" \
    -o "ServerAliveCountMax=3" \
    -o "ExitOnForwardFailure=yes" \
    -o "StrictHostKeyChecking=no" \
    -i /home/你的内网机用户名/.ssh/reverse_tunnel \
    -R 2222:localhost:22 \
    jump-vps
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

参数说明:

  • -M 0:关闭 autossh 自带的监控端口,改用 SSH 协议层的 keepalive 检测断线
  • ServerAliveInterval=30 / ServerAliveCountMax=3:每 30 秒发一次保活请求,连续 3 次无响应即判定断线、SSH 退出,由 autossh 负责重连
  • ExitOnForwardFailure=yes:端口转发失败时直接退出(而不是挂着一个没有隧道的空连接),交给 systemd 重启

如果 SSH 需要代理,ExecStart 改为使用 -F 指定 config 文件:

ini
ExecStart=/usr/bin/autossh -M 0 -N \
    -o "ServerAliveInterval=30" \
    -o "ServerAliveCountMax=3" \
    -o "ExitOnForwardFailure=yes" \
    -o "StrictHostKeyChecking=no" \
    -F /home/你的内网机用户名/.ssh/config \
    -R 2222:localhost:22 \
    jump-vps

启动服务:

bash
sudo systemctl daemon-reload
sudo systemctl enable --now reverse-tunnel
sudo systemctl status reverse-tunnel

踩坑: User= 必须是实际存在的用户名,不能留占位符,否则 systemd 报 exit code 217(USER,表示该用户不存在)。

2.6 配置 Claude Code ​

bash
# API Key 认证
echo 'export ANTHROPIC_API_KEY="sk-ant-xxxxx"' >> ~/.bashrc

# 如果需要代理访问 Anthropic API
echo 'export HTTPS_PROXY="http://your-proxy:port"' >> ~/.bashrc

source ~/.bashrc

2.7 创建 tmux 工作会话 ​

bash
tmux new -s claude
cd ~/your-project
claude
# 退出 tmux:Ctrl+B 然后按 D
# 重新进入:tmux attach -t claude

tmux 鼠标模式(写入 ~/.tmux.conf 永久生效):

ini
set -g mouse on

三、手机端配置(Termius) ​

Termius 是 iOS/Android 上常用的 SSH 客户端,支持 SSH Key 管理与跳板连接。

3.1 导入 SSH Key ​

Keychain → + → Import Key → 导入 jump_key 私钥文件

3.2 配置 VPS 连接 ​

字段 值
Hostname VPS IP
Port 22
Username jump
Authentication 选择导入的 Key

3.3 配置内网机直达(ProxyJump) ​

新建 Host:

字段 值
Hostname localhost
Port 2222
Username 内网机用户名
Proxy Jump 选择上面配好的 VPS 连接

需要先把 VPS 的 SSH 公钥添加到内网机的跳板配置:

bash
# 在 VPS 上执行
ssh-keygen -t ed25519 -f ~/.ssh/intranet-desktop-key -N "" -C "jump-to-desktop"
ssh-copy-id -i ~/.ssh/intranet-desktop-key.pub -p 2222 内网机用户名@localhost

然后把 intranet-desktop-key 私钥也导入 Termius,内网机 Host 的 Authentication 选这个 Key。

四、日常使用流程 ​

  1. 手机打开 Termius
  2. 点击内网机 Host(ProxyJump 自动跳转)
  3. tmux attach -t claude
  4. 开始远程开发
  5. 退出 tmux:Ctrl+B 然后按 D
  6. Claude Code 在内网机持续运行,随时回来继续

五、安全加固 ​

5.1 反向隧道端口仅限本机访问 ​

默认情况下(GatewayPorts no),sshd 把远端转发端口绑定在回环地址上,只有登录 VPS 的用户才能访问。由于 1.3 节配置了 GatewayPorts clientspecified(允许客户端指定绑定地址),建议在隧道参数里显式写明回环绑定,避免配置变化后端口意外暴露:

bash
-R 127.0.0.1:2222:localhost:22

这样外部无法直连 2222,必须先登录 VPS 才能跳转。

5.2 内网机 SSH 加固 ​

编辑 /etc/ssh/sshd_config:

ini
PermitRootLogin no
PasswordAuthentication no
AllowUsers your-username

5.3 定期检查 ​

bash
# VPS 上查看隧道连接
ss -tlnp | grep 2222

# 查看登录记录
sudo last
sudo journalctl -u ssh --since "1 hour ago"

踩坑汇总 ​

问题 原因 解决
fail2ban 安装后 SSH 连接被拒 IP 被误封 fail2ban-client set sshd unbanip IP,或先停 fail2ban 排查
私钥报 UNPROTECTED PRIVATE KEY FILE 私钥文件权限太开放 chmod 600 ~/.ssh/reverse_tunnel
反向隧道报 remote port forwarding failed 端口被 VPS 已有服务占用 换一个未占用的端口
systemd 报 exit code 217 User 字段写的是占位符 替换为实际用户名
tmux 滚轮变成方向键 鼠标模式未开启 set -g mouse on 写入 ~/.tmux.conf

结语 ​

整套方案可以概括为三点:

  1. 方向反转:内网机不可入站,但可出站——反向隧道把访问方向倒过来,VPS 只做中转。
  2. 保活三件套:autossh -M 0 关闭独立监控端口、ServerAliveInterval 检测断线、ExitOnForwardFailure 保证空连接立即退出重启,三者配合让隧道在断网后能自愈。
  3. 最小暴露面:VPS 只开 22 端口、密钥登录 + fail2ban,隧道端口显式绑定回环地址——公网上暴露的攻击面只有一个加固过的 sshd。
最近更新

基于 VitePress 构建