
1. 背景与需求
实验室有一台搭载 RTX 4090 GPU 的 Debian 服务器,主要用于深度学习训练和科研实验。由于实验室服务器位于内网环境,没有方便使用的公网 SSH 入口,因此无法在校外直接通过 SSH 或 VS Code Remote-SSH 访问。
为了解决这个问题,我准备了一台具有公网 IP 的腾讯云 Debian 服务器作为跳板机,通过 Reverse SSH Tunnel(反向 SSH 隧道),将实验室服务器的 SSH 服务映射到腾讯云服务器上。
最终实现以下目标:
- 在校外通过公网 IP 直接连接实验室服务器。
- 使用 SSH 密钥认证,避免开启密码登录。
- 通过 VS Code Remote-SSH 远程开发。
- 后续配置 systemd,实现隧道开机自启和断线自动重连。
本文记录从环境检查、密钥配置到隧道建立、故障排查的完整过程。
2. 网络架构与工作原理
2.1 网络拓扑
假设环境如下:
| 设备 | 操作系统 | 地址或端口 | 作用 |
|---|---|---|---|
| 本地电脑 | Windows 11 | 本地网络 | SSH 客户端、VS Code |
| 腾讯云服务器 | Debian | CLOUD_PUBLIC_IP:22 |
公网跳板机 |
| 腾讯云隧道入口 | Debian | 0.0.0.0:4090 |
接收外部 SSH 连接 |
| 实验室服务器 | Debian | 127.0.0.1:4090 |
实际 SSH 服务 |
注意: 隧道入口和服务器 SSH 服务的端口可以不同,也可以自行指定。
CLOUD_PUBLIC_IP需要替换为腾讯云服务器的真实公网 IP。
整体连接过程如下:
Windows 电脑
|
| SSH 连接 CLOUD_PUBLIC_IP:4090
v
腾讯云公网服务器
|
| 反向 SSH 隧道转发
v
实验室 Debian 服务器
|
| SSH 服务监听 TCP 4090
v
完成远程登录
2.2 为什么使用反向 SSH 隧道?
传统 SSH 连接通常要求客户端能够直接访问目标服务器的 SSH 端口。如果实验室服务器位于内网,外部网络无法直接访问该服务器,就需要额外配置公网入口。
反向 SSH 隧道的思路是:
- 由实验室服务器主动连接腾讯云公网服务器。
- 在腾讯云服务器上创建一个远程监听端口。
- 将发往该端口的 TCP 流量通过已经建立的 SSH 连接转发回实验室服务器。
- 外部客户端访问腾讯云公网 IP 和指定端口,即可连接实验室服务器。
这种方式不需要在实验室路由器上配置端口映射,也不要求实验室服务器本身拥有公网 IP。
需要注意:反向隧道解决的是网络可达性问题,并不会自动完成目标服务器的 SSH 用户认证。
3. 第一步:检查实验室服务器的 SSH 服务
首先登录实验室 Debian 服务器,检查 SSH 服务实际监听的端口:
sudo ss -lntp | grep sshd
我的实验室服务器输出中包含:
LISTEN ... 0.0.0.0:4090 ... users:(("sshd",...))
LISTEN ... [::]:4090 ... users:(("sshd",...))
这说明 SSH 服务监听 TCP 4090 端口,并且可以接收发往对应网络接口的连接。
因此,本文统一使用 4090 作为实验室 SSH 服务端口。
如果你的服务器 SSH 服务实际监听的是 22 端口,那么后续命令中指向实验室 SSH 服务的目标端口应改为 22。
4. 第二步:为反向隧道创建专用 SSH 密钥
为了让实验室服务器能够主动登录腾讯云,需要先配置 SSH 公钥认证。
建议为隧道单独生成一对密钥,避免直接复用日常开发密钥。
4.1 在实验室服务器生成密钥
以下命令必须在实验室 4090 服务器上执行,而不是在腾讯云服务器上执行。
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ed25519 \
-f ~/.ssh/id_ed25519_tunnel \
-N "" \
-C "lab4090-to-tencent"
生成两个文件:
~/.ssh/id_ed25519_tunnel
~/.ssh/id_ed25519_tunnel.pub
其中:
id_ed25519_tunnel:私钥,用于实验室服务器登录腾讯云。id_ed25519_tunnel.pub:公钥,需要添加到腾讯云的授权列表。
这里使用空口令是为了便于后续 systemd 无人值守地建立隧道。代价是私钥文件一旦泄露,就可能被直接使用,因此必须限制文件权限并保护好服务器账户。
查看公钥:
cat ~/.ssh/id_ed25519_tunnel.pub
复制完整的一行公钥。
4.2 将公钥添加到腾讯云服务器
通过腾讯云 TAT 登录公网服务器,确保云服务器上已经存在用于连接的 Linux 用户,例如 yehui。
然后执行:
sudo install -d -m 700 -o yehui -g yehui \
/home/yehui/.ssh
sudo touch /home/yehui/.ssh/authorized_keys
sudo chown yehui:yehui \
/home/yehui/.ssh/authorized_keys
sudo chmod 600 \
/home/yehui/.ssh/authorized_keys
sudo nano /home/yehui/.ssh/authorized_keys
将实验室服务器刚才生成的公钥追加到文件末尾,单独占一行。
注意保留已有公钥,不要覆盖原有的授权记录。
4.3 测试密钥认证
回到实验室服务器执行:
ssh -i ~/.ssh/id_ed25519_tunnel \
-o IdentitiesOnly=yes \
yehui@CLOUD_PUBLIC_IP
首次连接可能出现 SSH 主机指纹确认提示。应先核实腾讯云服务器的主机指纹,再决定是否接受。
如果能够正常登录腾讯云,说明实验室服务器到云服务器的 SSH 密钥认证已经打通。
退出远程会话:
exit
关键点:隧道密钥的私钥保留在实验室服务器上,公钥添加到腾讯云服务器。不要把私钥复制到腾讯云。
5. 第三步:配置腾讯云 SSH 服务,允许公网监听
这是整个配置过程中容易忽略的一步。
默认情况下,OpenSSH 的反向转发端口通常只监听远程服务器的回环地址,也就是 127.0.0.1。
这种情况下,腾讯云服务器本机能够访问隧道入口,但外部 Windows 电脑无法直接通过公网 IP 连接该端口。
如果希望直接连接:
CLOUD_PUBLIC_IP:4090
就需要允许 SSH 服务使用指定的非回环监听地址。
5.1 检查当前配置
在腾讯云服务器上执行:
sudo sshd -T | grep -E \
'^(gatewayports|allowtcpforwarding)'
其中:
-
gatewayports决定远程转发端口是否可以监听非回环地址。 -
allowtcpforwarding决定 SSH 服务是否允许 TCP 转发。
对于本文采用的直接公网连接方案,需要确认有效配置允许指定监听地址,并允许 TCP 转发。
5.2 修改 SSH 配置
编辑配置文件:
sudo nano /etc/ssh/sshd_config
设置:
GatewayPorts clientspecified
如果 AllowTcpForwarding 被显式设置为 no,还需要根据安全策略调整为允许转发,例如:
AllowTcpForwarding yes
注意检查 /etc/ssh/sshd_config.d/ 中的配置片段,以及 sshd -T 输出的最终生效配置,避免配置被其他规则覆盖。
保存后执行:
sudo sshd -t
sudo systemctl reload ssh
第一条命令用于检查 SSH 配置语法。只有检查通过后才重新加载服务。
建议保留当前 TAT 管理会话,避免配置错误时失去管理入口。
6. 第四步:建立反向 SSH 隧道
现在可以正式建立反向 SSH 隧道。
这条命令必须在实验室 4090 服务器上执行。
ssh -NT \
-i ~/.ssh/id_ed25519_tunnel \
-o IdentitiesOnly=yes \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R 0.0.0.0:4090:127.0.0.1:4090 \
yehui@CLOUD_PUBLIC_IP
6.1 理解 -R 参数
核心配置是:
-R 0.0.0.0:4090:127.0.0.1:4090
它的格式是:
-R [远程监听地址:]远程端口:目标地址:目标端口
各部分的含义如下:
| 参数 | 含义 |
|---|---|
0.0.0.0 |
腾讯云服务器上监听所有 IPv4 网络接口 |
第一个 4090 |
腾讯云服务器上的隧道入口端口 |
127.0.0.1 |
实验室服务器本机的回环地址 |
第二个 4090 |
实验室 SSH 服务实际监听的端口 |
因此,访问腾讯云服务器的公网 4090 端口,流量就会通过 SSH 隧道转发到实验室服务器的 SSH 4090 端口。
其他选项的作用:
-
-N -T:不执行远程命令、不分配终端,只建立隧道。 -
ExitOnForwardFailure=yes:远程端口转发创建失败时退出。 -
ServerAliveInterval=30:每隔 30 秒发送一次存活检测。 -
ServerAliveCountMax=3:连续检测无响应时断开连接。 -
IdentitiesOnly=yes:限制 SSH 使用指定的身份密钥。
执行后,如果没有出现错误,并且终端一直停留在那里,通常说明 SSH 正在保持连接。
此时不要关闭该终端,否则隧道会随 SSH 连接结束而关闭。
7. 第五步:检查腾讯云上的隧道监听
保持实验室服务器上的隧道运行。
通过 TAT 登录腾讯云,执行:
sudo ss -lntp | grep ':4090'
理想情况下可以看到类似输出:
LISTEN ... 0.0.0.0:4090 ... users:(("sshd-session",...))
如果输出是:
127.0.0.1:4090
说明该端口仍然只绑定在回环地址上,需要检查:
-
隧道命令是否使用了
-R 0.0.0.0:4090:...。 -
腾讯云的
GatewayPorts是否已经生效。 -
是否存在其他 SSH 配置覆盖了当前设置。
-
是否有旧隧道仍占用端口。
如果没有任何输出,则检查隧道是否已经断开,以及 SSH 日志中是否存在转发失败信息。
这里需要区分两个概念:
-
端口正在监听:说明隧道入口已经创建。
-
SSH 能够成功登录:还需要目标服务器接受客户端的身份认证。
端口监听成功,并不等于 SSH 用户认证必然成功。
8. 第六步:开放腾讯云安全组端口
⚠️这一点很重要,很多云服务器厂商为了安全考虑都需要手动去打开端口。
即使腾讯云上的 4090 已经监听在 0.0.0.0,公网流量仍可能被云安全组或系统防火墙拦截。
进入腾讯云控制台,找到云服务器关联的安全组,在入站规则中添加:
| 配置项 | 设置 |
|---|---|
| 协议 | TCP |
| 端口 | 4090 |
| 来源 | 自己的公网 IP /32 |
| 策略 | 允许 |
例如,若客户端公网 IP 为 203.0.113.10,来源应设置为 203.0.113.10/32。这里的地址仅用于演示。
不要直接将来源设置为 0.0.0.0/0,除非确实需要允许整个互联网访问。
如果系统启用了 UFW、nftables 等防火墙,也要检查对应的入站规则。
腾讯云 TCP 22 端口则用于实验室服务器主动连接腾讯云建立隧道。它与公网访问实验室 SSH 所使用的 4090 端口用途不同。
9. 第七步:配置 Windows SSH 公钥认证
完成端口转发后,还需要让 Windows 电脑能够通过实验室服务器自己的 SSH 认证。
注意:腾讯云与实验室服务器是两台独立的机器,各自维护自己的 authorized_keys。
9.1 查看 Windows 公钥指纹
在 Windows PowerShell 执行:
ssh-keygen -lf "$env:USERPROFILE\.ssh\id_ed25519.pub"
输出类似:
256 SHA256:xxxxxxxxxxxxxxxx yehui (ED25519)
这是公钥指纹,不是公钥本身。
9.2 检查实验室服务器授权文件
在实验室服务器执行:
ssh-keygen -lf /home/yehui/.ssh/authorized_keys
如果输出的指纹中包含 Windows 公钥对应的 SHA256 指纹,说明授权文件中已经存在这把公钥。
公钥注释名称可以不同,但同一把密钥的 SHA256 指纹应当一致。
如果不存在,就将 Windows 的公钥追加到实验室服务器的:
/home/yehui/.ssh/authorized_keys
然后确保权限正确:
chmod 700 /home/yehui/.ssh
chmod 600 /home/yehui/.ssh/authorized_keys
同时确认文件属于对应的 Linux 用户。
10. 第八步:从 Windows 直接连接实验室服务器
先在 Windows PowerShell 中测试公网 TCP 端口:
Test-NetConnection CLOUD_PUBLIC_IP -Port 4090
如果出现:
TcpTestSucceeded : True
说明 TCP 连接已经可以建立。
接着执行:
ssh -i "$env:USERPROFILE\.ssh\id_ed25519" `
-o IdentitiesOnly=yes `
-p 4090 yehui@CLOUD_PUBLIC_IP
首次连接时,SSH 可能要求确认主机指纹。
由于该端口最终连接到实验室服务器的 SSH 服务,因此这里看到的目标主机指纹应与实验室服务器的 SSH 主机密钥对应。应核对指纹后再接受。
如果成功进入实验室服务器的命令行,说明公网连接、端口转发和 SSH 用户认证已经全部打通。
10.1 配置 VS Code Remote-SSH
打开 Windows 上的 SSH 配置文件:
%USERPROFILE%\.ssh\config
添加:
Host LAB_PC_4090_Cloud
HostName CLOUD_PUBLIC_IP
User yehui
Port 4090
IdentityFile C:\Users\你的用户名\.ssh\id_ed25519
IdentitiesOnly yes
将 CLOUD_PUBLIC_IP 和 Windows 用户目录替换为实际值。
随后在 VS Code 中使用 Remote-SSH 连接 LAB_PC_4090,即可在本地编辑代码,并在实验室服务器上运行训练任务。
11. 配置 systemd,实现自动重连
手动运行的隧道在终端关闭、服务器重启或连接异常中断后可能失效,因此可以使用 systemd 管理隧道进程。
首先,停止之前手动运行的隧道,避免重复占用远程端口。
在实验室服务器创建服务文件:
sudo nano /etc/systemd/system/reverse-ssh-tunnel.service
写入:
[Unit]
Description=Reverse SSH Tunnel to Tencent Cloud
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=yehui
Environment=HOME=/home/yehui
ExecStart=/usr/bin/ssh -NT \
-i /home/yehui/.ssh/id_ed25519_tunnel \
-o IdentitiesOnly=yes \
-o BatchMode=yes \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R 0.0.0.0:4090:127.0.0.1:4090 \
yehui@CLOUD_PUBLIC_IP
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
注意:如果编辑器或 systemd 不接受将 ExecStart 分成多行,应将该命令写成一整行。这里的反斜杠只用于说明参数之间的关系,不应原样写成多条独立的 ExecStart。
保存后执行:
sudo systemctl daemon-reload
sudo systemctl enable --now reverse-ssh-tunnel
sudo systemctl status reverse-ssh-tunnel --no-pager
查看日志:
sudo journalctl -u reverse-ssh-tunnel -n 50 --no-pager
如果服务正常运行,并且腾讯云上的 4090 端口重新监听,说明 systemd 已经成功建立隧道。
这里需要注意,active (running) 只能证明服务进程处于运行状态;仍应检查日志和远程端口监听情况,确认实际转发成功。
12. 实际踩坑记录与排查方法
问题一:在错误的服务器上执行隧道命令
实验过程中曾在腾讯云服务器上执行:
ssh -i ~/.ssh/id_ed25519_tunnel ...
随后出现:
Identity file .../id_ed25519_tunnel not accessible
Permission denied (publickey).
原因是隧道专用私钥只保存在实验室服务器上,而不是腾讯云服务器上。
解决方法:反向隧道命令应由实验室服务器发起。
问题二:腾讯云上的端口监听成功,但 SSH 登录失败
在腾讯云上执行:
ssh -p 4090 yehui@127.0.0.1
出现:
Permission denied (publickey).
这并不一定意味着隧道失败。该命令是腾讯云本机上的 SSH 客户端发起的连接,它使用的是腾讯云本机可用的客户端密钥,而不是 Windows 上的私钥。
隧道是否建立,应通过端口监听和转发状态检查;用户认证则应使用正确的客户端密钥进行测试。
问题三:端口只监听在 127.0.0.1
如果输出为:
127.0.0.1:4090
说明端口只允许腾讯云本机访问。
如果目标是公网直连,需要使用:
GatewayPorts clientspecified
并通过:
-R 0.0.0.0:4090:127.0.0.1:4090
指定监听地址。
问题四:公网端口无法访问
即使监听地址已经是:
0.0.0.0:4090
仍可能因为腾讯云安全组未开放 TCP 4090,导致 Windows 连接超时。
解决思路是依次检查:
-
实验室隧道进程是否仍在运行。
-
腾讯云是否监听
0.0.0.0:4090。 -
腾讯云安全组是否允许 TCP 4090。
-
腾讯云系统防火墙是否拦截流量。
-
Windows 当前网络是否能够访问该端口。
问题五:Windows 公钥指纹是否匹配
不要仅凭公钥注释名称判断密钥是否一致。
正确方式是分别计算 Windows 公钥和实验室服务器授权文件中的公钥指纹:
ssh-keygen -lf "$env:USERPROFILE\.ssh\id_ed25519.pub"
ssh-keygen -lf /home/yehui/.ssh/authorized_keys
如果 SHA256 指纹一致,说明对应的公钥已经存在于授权文件中。
13. 安全注意事项
本文采用的方案将实验室 SSH 服务通过腾讯云公网端口暴露出来,因此需要特别关注以下事项。
13.1 限制安全组来源
腾讯云安全组应尽可能只允许自己的公网 IP 访问 TCP 4090。
如果公网 IP 发生变化,需要更新安全组来源规则。
13.2 关闭不必要的密码认证
可以在腾讯云和实验室服务器上分别检查 SSH 的有效认证配置:
sudo sshd -T | grep -E \
'^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin)'
确认密钥认证可用后,再根据需要设置:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
修改后先检查配置语法:
sudo sshd -t
然后再重新加载 SSH 服务。
需要注意:腾讯云 SSH 服务的密码认证配置控制的是对腾讯云 SSH 服务本身的登录;通过 4090 转发到实验室服务器的连接,其用户认证由实验室服务器上的 SSH 服务决定。
13.3 保护隧道私钥
不要将 id_ed25519_tunnel 私钥上传到代码仓库,也不要通过聊天工具公开分享。
13.4 不要为了方便关闭防火墙
只开放确实需要的端口,并尽可能限制来源 IP。不要为了排障而直接关闭整个服务器的防火墙。
14. 总结
整个方案的核心是三个环节:
-
认证: 实验室服务器使用专用 SSH 密钥登录腾讯云。
-
转发: 通过反向 SSH 隧道,将腾讯云的 4090 端口映射到实验室 SSH 服务。
-
访问: Windows 通过腾讯云公网 IP 和端口 4090,使用自己的 SSH 密钥登录实验室服务器。
在排查问题时,建议按以下顺序进行:
密钥认证
↓
反向隧道建立
↓
腾讯云端口监听
↓
安全组与防火墙
↓
Windows TCP 测试
↓
SSH 用户认证
↓
VS Code Remote-SSH
这样可以将网络可达性问题与 SSH 身份认证问题分开排查,避免在错误的环节反复修改配置。
对于需要长期使用的科研服务器,最后再使用 systemd 管理隧道,可以减少手动重连的操作。
一起聊聊
欢迎留下想法。评论由 GitHub Issues 托管,登录 GitHub 后即可参与。
评论框没有显示?直接在 GitHub 留言 ↗