实验室服务器位于严格 NAT 后,不能接受公网入站连接;深圳 Mac 与它之间也无法稳定完成 UDP 打洞。本文选择一台到深圳和实验室网络延迟都较低的 VPS,分别部署反向 SSH 隧道、Tailscale Peer Relay 和 RustDesk Relay。三套方案不互相依赖,可以同时运行。
命名
为避免混淆,全文固定使用以下名称:
| 名称 | 设备 | 作用 |
|---|---|---|
mac-client | 深圳 Mac;Tailscale 名称为 MBA | 发起 SSH 或远程桌面连接 |
relay-vps | 公网 VPS;Tailscale 名称为 hk-relay | 提供固定公网入口和中转 |
lab-server | 实验室服务器;Tailscale 名称为 lab-server | 最终访问目标 |
文中的占位符含义如下:
| 占位符 | 含义 | 获取方法 |
|---|---|---|
<RELAY_IP> | relay-vps 的公网 IPv4 地址 | 在 VPS 服务商控制台查看 |
<RELAY_USER> | mac-client 登录 VPS 使用的 SSH 用户 | 可以是 root 或普通管理用户;不等于专用隧道用户 tunnel |
<LAB_USER> | 登录 lab-server 使用的 Linux 用户 | 在目标端执行 whoami |
<LAB_TS_IP> | lab-server 的 Tailscale IPv4 地址 | 在目标端执行 tailscale ip -4 |
<TUNNEL_PUBLIC_KEY> | lab-server 为反向隧道生成的 SSH 公钥 | 执行 sudo cat /root/.ssh/id_ed25519_vps_tunnel.pub |
<RUSTDESK_KEY> | RustDesk 服务端的公钥 | 在 VPS 执行 sudo cat /opt/rustdesk/data/id_ed25519.pub;不要复制私钥 id_ed25519 |
<VNI_ID> | Tailscale 为一次 Peer Relay 连接分配的标识 | 自动生成,只用于识别输出,不需要手工填写 |
RustDesk 的“服务端”专指 VPS 上的 hbbs 和 hbbr,不是 lab-server。
方案一:反向 SSH 隧道
这套方案只依赖 TCP。首先由 lab-server 主动连接 relay-vps,在 VPS 回环地址上建立两个反向端口:22022 → lab-server:22 和 23389 → lab-server:3389。之后 mac-client 再通过 VPS 进入这条隧道。开始配置前,必须确认 lab-server 的 SSH 服务监听 22/tcp,RDP 服务监听 3389/tcp;不使用 RDP 时删除所有包含 23389 或 3389 的配置。
在 relay-vps 创建专用隧道用户:
| |
在 lab-server 生成专用密钥并显示公钥:
| |
以管理员身份把公钥写入 relay-vps 的 /home/tunnel/.ssh/authorized_keys。下面的选项拒绝 shell 和远程命令,并把 -R 允许创建的监听地址限定为两个回环端口:
| |
| |
在启动 systemd 服务前,先比较 relay-vps 本机显示的 Ed25519 指纹与 lab-server 扫描到的指纹。两者完全一致后,才把主机密钥写入 root 的 known_hosts:
| |
在 lab-server 创建 /etc/systemd/system/relay-vps-tunnel.service:
| |
| |
在 relay-vps 验证端口。两者必须监听在 127.0.0.1,不需要在防火墙中开放 22022 或 23389:
| |
在 mac-client 的 ~/.ssh/config 中写入:
| |
mac-client 需要分别通过 <RELAY_USER> 和 <LAB_USER> 完成两次 SSH 认证。如果需要免密码登录,在反向隧道已经运行后,把 Mac 公钥分别加入两个账户。下面以 id_rsa.pub 为例;使用 Ed25519 密钥时改为 id_ed25519.pub。只能复制 .pub 公钥,私钥始终留在 Mac:
| |
~/.ssh/id_rsa 和 ~/.ssh/id_ed25519 都是 OpenSSH 默认尝试的私钥文件,因此不需要 IdentityFile;只有非默认路径的私钥才需要显式指定。SSH 登录执行 ssh lab-server-via-ssh。切换目标端用户可执行 ssh 其他用户名@lab-server-via-ssh,但该用户必须已在 lab-server 上创建,并已配置密码或 Mac 公钥。远程桌面先运行 ssh -NT lab-rdp-via-ssh,再让 RDP 客户端连接 127.0.0.1:13389。
方案二:Tailscale Peer Relay
mac-client、relay-vps 和 lab-server 都安装 Tailscale,并登录同一个 tailnet。参与 Peer Relay 的版本必须不低于 1.86。本次 tailnet 中三个节点分别显示为 MBA、hk-relay 和 lab-server,可用 tailscale status 确认。
在 relay-vps 配置 Peer Relay,并确保配置端口与防火墙端口完全一致:
| |
在 Tailscale 管理后台的 Access controls 中,把下面的规则合并到现有 grants 数组:
| |
这里的 src 是位于严格 NAT 后、需要通过中转访问的 lab-server,dst 才是提供中转的 relay-vps,即 tailnet 中的 hk-relay。在 mac-client 验证连接:
| |
成功时会看到:
| |
tailscale ping 的首个响应可以显示 DERP,因为客户端仍在协商路径;后续响应和 tailscale status 必须显示 peer-relay,否则 VPS 中转没有生效。direct connection not established 只表示点对点打洞失败。Peer Relay 只转发端到端加密的 Tailscale 流量,不能读取 SSH 或 RDP 内容。本文使用系统 OpenSSH,因此 SSH 命令是 ssh <LAB_USER>@<LAB_TS_IP>;切换 Linux 用户只需更改 <LAB_USER>。RDP 连接地址是 <LAB_TS_IP>:3389。
方案三:RustDesk Relay
这套方案不依赖 Tailscale。VPS 上的 hbbs 负责 ID、注册和信令,hbbr 负责中转桌面流量;mac-client 和 lab-server 都是 RustDesk 客户端。
在 relay-vps 创建 /opt/rustdesk/compose.yml:
| |
ALWAYS_USE_RELAY=Y 强制会话经过 VPS,hbbr -k _ 使用同一密钥校验客户端,避免 VPS 成为开放中转。启动服务并放行原生客户端所需的最小端口:
| |
21115/tcp 用于 NAT 测试,21116/tcp 和 21116/udp 用于注册与信令,21117/tcp 承载中转流量。原生 RustDesk 客户端不需要 WebSocket 端口 21118 和 21119。最后一条命令输出的内容就是 <RUSTDESK_KEY>。在 mac-client 的 RustDesk Settings → Network 中填写:
| |
lab-server 的普通桌面安装可以填写同样的图形界面选项,并在 Settings → Security 中设置永久密码;未设置永久密码时,每次连接都需要目标端人工确认。本次部署使用 systemd 和 GDM 提供无人值守访问,有效配置源是 /root/.config/rustdesk/RustDesk2.toml,不能只修改普通用户目录。先停止服务并编辑该文件;只修改下面列出的字段,其余内容保持不变:
| |
| |
通过界面确认服务器公钥时,RustDesk 会自动记录确认状态。若完全手动配置,还要在 /root/.config/rustdesk/RustDesk.toml 和 /var/lib/gdm3/.config/rustdesk/RustDesk.toml 已有的 [keys_confirmed] 段中都加入:
| |
然后重新启动目标端服务:
| |
RustDesk2.toml 会从 root 配置同步给 GDM,但密钥确认记录应单独检查。启动后确认 /var/lib/gdm3/.config/rustdesk/RustDesk2.toml 中的 ID Server、Relay Server 和 Key 仍与 root 配置一致。在 mac-client 输入上一步得到的 RustDesk ID 发起连接,同时在 relay-vps 执行 docker logs -f hbbr;出现 got paired 表示桌面流量正在经过 VPS。ID Server 和 Relay Server 必须填写 VPS 公网地址,不能填写 VPS 的 Tailscale 地址,否则会变成 RustDesk over Tailscale。
选择
只需要 SSH、VS Code Remote-SSH 或 RDP,且 tailscale status 能稳定显示 peer-relay 时,使用 Tailscale。Tailscale 无法建立 Peer Relay,或者网络只能稳定传输 TCP 时,使用反向 SSH 隧道。需要完整桌面、文件传输或无人值守控制时,使用 RustDesk。保留反向 SSH 隧道,可在 Tailscale 或 RustDesk 故障时继续登录 lab-server。