前言
故事是这样的。
我在做 AIGC 相关的开发,主力环境是一台没有公网 IP 的 GPU 实例以及一台阿里云灵构服务器,主要用来跑 ComfyUI、训练模型。
但使用过程中有几个让人难受的问题:
- 阿里云官方自带的远程桌面控制延迟巨大,体验感太差
- 文件传输太过麻烦,阿里云灵构需要借助网盘中转,而魔搭 WebIDE 有文件大小限制
我第一时间想到的解决办法就是内网穿透,不过第三方的穿透工具不太稳定,要么限速要么频繁掉线。刚好手上有一台 99 元的阿里云服务器,我寻思着不用也是浪费,干脆直接拿它来当做跳板机
不过我并没有考虑自建 frp 的方式来实现穿透,因为安装软件比较麻烦,每台目标机器都要安装 frpc 客户端的话太消耗时间,
本来薅来的免费 GPU 算力时长就有限,所以省事高效是第一原则。
于是我选择了 SSH 反向隧道的方式来穿透
我想要的效果是:
- 本地 VS Code 直接打开远程 GPU 的终端,并实现文件实时编辑和传输
- 本地浏览器直接访问
127.0.0.1:8188操作 ComfyUI - 服务器和本地电脑重启后自动打通隧道
实现原理
穿透的本质就是借道,借有公网IP服务器的道
网络拓扑如下:
1 | ┌──────────┐ SSH 隧道 ┌──────────┐ 反向隧道 ┌──────────┐ |
关键点只有三个:
- GPU 主动连阿里云(因为 GPU 能出网,阿里云有公网)
- 建立反向隧道(-R):把 GPU 的端口“伸”到阿里云本机
- 本地再连阿里云(-L):把本地端口“引”到阿里云
最终效果:
localhost:8188→ 阿里云 → GPU 的 ComfyUI- VS Code
ssh GPU→ 阿里云 → GPU 的终端
具体实现
准备工作:阿里云侧
确保阿里云允许端口转发:
1 | # 在阿里云上执行 |
这里需要明白的是,由于我们走的是 SSH 22 端口通道,所以无需去阿里云安全组开放 2222 和 8188 等端口,有公网 ip 即可,22 端口默认都是开放的.
同时开启ssh保活检测 (非必须操作, 建议加上):
1 | # 追加保活配置 |
ClientAliveInterval 30: 每 30 秒服务端问一次客户端”你还活着吗”ClientAliveCountMax 3: 连续 3 次没回应就断开连接
阿里云加这两个的主要目的是:
- 激发 autossh 重连: 连接被断开但进程还在的情况下,
GPU服务端的autossh会误以为还处于正常通信状态, 阿里云配置作为一个保活补充 - 避免长时间假死时端口一直占着, 导致新连接建立不了
第一步:GPU 实例配置
执行以下指令,让GPU 实例主动将端口暴露给阿里云服务器(记得将IP替换成你的):
1 | # 1. 创建 GPU 专用密钥 |
当然了,如果你不想每次手动挨个复制命令,我还准备了一键安装脚本,以下是在 GPU 上跑的脚本,核心逻辑是:密钥复用 + 反向隧道 +前台运行:
1 |
|
将脚本上传到 GPU 实例中并执行,启动反向隧道(记得将阿里云IP替换成你的服务器)
如果你不想每次启动服务器都运行一遍脚本, 那我们可以开启 systemd后台运行, 以下是补充开机自启动功能的版本:
1 |
|
两个版本, 根据自身需求任选其一即可
第二步:本地电脑的配置
在本地电脑终端执行以下命令
1 | # 1. 创建 SSH 密钥 |
此时我们在浏览器上直接输入http://127.0.0.1:8188即可访问 GPU 实例中的 ComfyUI了
但是我还要实现终端访问,所以我们需要另起一个终端,并输入以下指令:
1 | ssh -J root@阿里云公网 IP:22 -p 2222 ubuntu@127.0.0.1 |
或者
在用户目录下的 config文件中添加如下配置:
1 | # ===== 阿里云跳板机 ===== |
然后在终端中运行 ssh gpu,一样的效果,不过为了方便 VS Code连接,建议采用配置的形式
这里需要注意的是, GPU 部分的 User字段该填 root还是 ubuntu ,取决于你的 GPU 服务器的设置,可以运行以下指令查看是否为root:
1 |
|
同样的,本地电脑也有一键配置脚本,全自动化的同时不破坏原有的 SSH配置,如下:
1 |
|
该脚本兼容 Mac 和 Linux 平台
直接拷贝到本地电脑运行即可,(记得将阿里云IP替换成你的服务器IP)
第三步:将本地电脑公钥拷贝至GPU服务器
隧道打通之后, 阿里云服务器作为跳板机只负责数据传输, 不负责ssh终端身份的验证
我们此时访问GPU终端, 需要GPU服务器终端的访问密码, 很显然这个我们拿不到
要想实现GPU终端免密访问, 需要将本地的comfy_key公钥拷贝至GPU服务器中的./ssh/authorized_keys文件中, 用密钥替代密码, 具体操作如下:
在 GPU 终端里执行以下命令:
1 | # 1. 创建目录(没有就建,有了也不报错) |
或者直接从阿里云中复制公钥:
1 | # 1. 创建目录和文件(没有就建) |
第四步:开始访问
到这里,我想大家应该都知道怎么用了,这里之所以推荐大家使用VS Code的Remote-SSH插件 来连接,因为它既可以访问终端,又能访问文件,省去了手敲命令,一举两得,而且用起来也比较方便:
在VS Code里:
F1→Remote-SSH: Connect to Host- 选择
gpu
会直接进到 GPU 的终端

它和阿里云是独立的互不影响,你想访问阿里云终端,还是按照原来的 ssh -p 22 root@阿里云公网 IP就行
多 GPU 怎么扩展?
假设我有 3 台 GPU,做法是:
| GPU | SSH 端口 | ComfyUI 端口 |
|---|---|---|
| gpu-01 | 2222 | 8188 |
| gpu-02 | 2223 | 8189 |
| gpu-03 | 2224 | 8190 |
本地 ~/.ssh/config:
1 | Host gpu-01 |
VS Code 可以同时连多台 GPU,互不干扰。
最优雅的方法就是只维护SSH端口, 打通终端直连后, 本地电脑可以随意转发GPU任意端口, 无需占用阿里云端口资源.
否则, 则需要在GPU上挨个执行ssh -R进行反向映射, 维护起来稍微麻烦一些
两种方案对比:
| 方案A:只打通 22(直连 gpu-N) | 方案B:挨个 -R |
|
|---|---|---|
| 要敲的命令 | 就一条 ssh gpu-1(或 VS Code 连一下) |
GPU 上写 N 条:ssh -R 3000:... -R 8080:... -R 8188:... root@阿里云 |
| 以后新增端口(比如突然起个 6006) | 本地加一行 -L 6006:127.0.0.1:6006 就行,GPU 不用碰、不用重连 |
得登回 GPU 改命令、杀旧进程、重起 -R,阿里云还得再腾一个端口 |
| 占用中间资源 | 0 个阿里云端口 | N 个阿里云本机端口(3000/8080/8188全占一遍,撞了就静默失败) |
| 断线恢复 | 保活那条 SSH 就行,全跟着活 | 每个 -R 各自可能悄断,得挨个查 |
| 谁动手 | 只动你 Mac | 每次加端口都要登 GPU + 动阿里云 |
| 像什么 | 拉一根万能水管到 GPU,想接啥龙头本地拧一下 | 每个水龙头都单独从 GPU 拉一根管子到阿里云,满地管子 |
问题汇总
ssh gpu登录GPU提示需要输入root@127.0.0.1 password问题出在公钥上, 检查本地
comfy_key.pub公钥和GPU中authorized_keys中存储的公钥是否一致另外有一点需要注意的是, 不要使用老版
ssh-rsa格式密钥, 目前很多新系统默认将其禁用了, 推荐使用新的ssh-ed25519格式密钥关于密钥问题
本地连接阿里云和连接
GPU服务器可以使用不同的密钥, 比如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# Managed by local_tunnel.sh
# 连接阿里云使用aliyun密钥对, 连接gpu使用comfy_key密钥对
Host aliyun
HostName 阿里云服务器IP
User root
Port 22
IdentityFile /Users/xxx/.ssh/aliyun
StrictHostKeyChecking accept-new
Host gpu
HostName 127.0.0.1
Port 2222
User root
ProxyJump aliyun
IdentityFile /Users/xxx/.ssh/comfy_key
IdentitiesOnly yes隧道建立是先连接阿里云服务器, 成功后再连接GPU服务器, 阿里云只负责数据中转, 而不会拿着
comfy_key密钥去替我们连接GPU, 这点需要明白,所以, 他们不一定非得使用相同密钥对, 之前我们为了方便管理和使用, 共用了相同的
comfy_key密钥root用户和admin用户阿里云灵构的
GPU服务器, 默认用户为admin, 在服务器上执行echo ~可以查看如果我们将
comfy_key公钥放在admin下的.ssh/authorized_keys文件中, 那么本地电脑config配置需要以admin身份登录:1
2
3
4
5
6
7
8Host gpu
HostName 127.0.0.1
Port 2222
User admin
ProxyJump aliyun
IdentityFile /Users/songjian/.ssh/comfy_key
IdentitiesOnly yes
LocalForward 8189 127.0.0.1:8188同理, 如果放在
root下的.ssh/authorized_keys文件中, 则需要将User字段改为root, 你以什么身份去登录, 它就会去那个目录下找.ssh/authorized_keys, 这是一个小细节, 需要注意浏览器输入
127.0.0.1:8189一直空转无法访问ComfyUI这里涉及到一个端口转发先后顺序的问题, 场景比如:
- 本地 Mac 转发:Mac本地8189 → 阿里云127.0.0.1:8189
- GPU 反向隧道:GPU本机8189 → 阿里云127.0.0.1:8189
时序如下:
启动顺序 阿里云侧8189状态 结果 Mac自启先跑(ProxyJump建连) 阿里云侧只是“连一下8189”,没监听者 → 连接被拒,但ssh不报错 Mac隧道建了,但中间是空的 GPU反向隧道后起 -R 8189想在阿里云监听8189,发现没冲突反而能绑上✅ 但 Mac 那条旧连接已经失败了,不会自动重连 Mac自启先跑 + GPU反向隧道后起 Mac那条通道里流量一直不通,你浏览器访问就是转圈/空响应 ❌ 表现就是“连不上但又不报错” 更糟的情况:如果你之前手动起过某个
autossh -R占着阿里云8189,GPU 上再起-R直接报bind failed,反向隧道静默退出,你完全看不到错。所以, 不出错的办法就是: 先启动GPU反向隧道, 再起本地转发
本文为作者原创 转载时请注明出处 谢谢
