VS Code Remote-SSH 因 RemoteForward 端口冲突导致连接失败的排查与解决

最近在 Windows 上使用 VS Code Remote-SSH 连接 Linux 服务器时,遇到了一个比较隐蔽的问题:普通 SSH 登录基本正常,但 VS Code Remote-SSH 会直接失败,日志中出现:

text 复制代码
Error: remote port forwarding failed for listen port 10802
过程试图写入的管道不存在。
Failed to parse remote port from server output

一开始容易把注意力放在 VS Code Server、SSH 客户端、Windows 管道或者远程安装脚本上,但真正的根因其实是:

SSH 配置中的 RemoteForward 端口已经被另一个 SSH 会话占用,而 ExitOnForwardFailure yes 又会让整个 SSH 连接因此直接退出。

本文记录完整的排查过程,以及后续遇到的 VS Code Remote-SSH / Dev Containers 配置兼容问题。


1 问题现象

本地环境大致如下:

  • Windows
  • VS Code
  • Remote-SSH
  • Git for Windows 自带 OpenSSH
  • 远端 Linux 服务器
  • SSH 配置中使用 RemoteForward
  • 远端通过 socat 将代理端口转给 Docker 容器

SSH 配置类似:

sshconfig 复制代码
Host my-server
    HostName <SERVER_IP>
    Port <SSH_PORT>
    User <USERNAME>
    IdentityFile "C:\Users\<USER>\.ssh\id_rsa"

    RemoteForward 10802
    ExitOnForwardFailure yes

    ServerAliveInterval 30
    ServerAliveCountMax 3

VS Code Remote-SSH 日志中,真正关键的错误是:

text 复制代码
Error: remote port forwarding failed for listen port 10802

后面的:

text 复制代码
过程试图写入的管道不存在。
Failed to parse remote port from server output

实际上只是 SSH 进程提前退出后的连锁报错。


2 先确认 SSH 客户端是否正常

Remote-SSH 会尝试在本机 PATH 中寻找 ssh.exe,日志里可能会看到大量:

text 复制代码
Checking ssh with "C:\...\ssh.exe -V"
Got error from ssh: ... ENOENT

这些通常不是问题。

只要最终能找到某个可用 SSH,例如:

text 复制代码
C:\Program Files\Git\usr\bin\ssh.exe

并成功输出版本:

text 复制代码
OpenSSH_x.x

就说明本机 SSH 客户端本身是正常的。

所以排查重点应该放到:

text 复制代码
remote port forwarding failed

而不是前面那些 ENOENT。


3 检查远端端口是否已经被占用

在远端服务器执行:

bash 复制代码
sudo ss -lntp | grep 10802

如果看到类似:

text 复制代码
LISTEN 0 128 127.0.0.1:10802 0.0.0.0:* users:(("sshd",pid=123456,fd=9))
LISTEN 0 128 [::1]:10802      [::]:*    users:(("sshd",pid=123456,fd=7))

说明:

10802 已经被某个 sshd 子进程监听。

也就是说,已经存在一个 SSH RemoteForward 会话。

查看具体进程:

bash 复制代码
ps -fp 123456

或者:

bash 复制代码
ps -aux | grep 123456

注意,下面这种写法是不对的:

bash 复制代码
ps -aux | grep pid=123456

因为 ps 输出中并不会出现字面量 pid=123456。

还可以进一步检查该 SSH 会话对应的网络连接:

bash 复制代码
sudo ss -tnp | grep 123456

4 为什么 RemoteForward 失败会导致整个 VS Code 连接退出

关键在于 SSH 配置中的:

sshconfig 复制代码
ExitOnForwardFailure yes

它的含义是:

只要端口转发建立失败,SSH 主连接也立即失败。

因此实际流程是:

text 复制代码
VS Code
  ↓
启动 SSH
  ↓
登录远端服务器
  ↓
申请 RemoteForward 10802
  ↓
10802 已经被占用
  ↓
RemoteForward 创建失败
  ↓
ExitOnForwardFailure yes
  ↓
SSH 直接退出
  ↓
VS Code 远端安装脚本被中断
  ↓
出现"管道不存在"
  ↓
Failed to parse remote port

所以真正的根因依旧只是:

text 复制代码
RemoteForward 端口冲突

5 为什么换一个 RemoteForward 端口后仍然可能失败

一开始我尝试把:

text 复制代码
10802

换成:

text 复制代码
10812

但问题依旧存在。

这时问题就不一定是"旧 SSH 会话占了旧端口",而可能是:

VS Code Remote-SSH 自己启动了多个 SSH 连接,而每个连接都会重复执行同一个 RemoteForward。

例如:

text 复制代码
VS Code SSH connection #1
    ↓
成功监听 10812

VS Code SSH connection #2
    ↓
再次请求监听 10812
    ↓
端口已被 connection #1 占用
    ↓
失败

这种情况下,不管把端口改成多少,第二个 SSH 会话都会撞到第一个。

验证方法很简单。

VS Code 连接失败以后,在服务器上立即执行:

bash 复制代码
sudo ss -lntp | grep 10812

如果新端口此时已经被 sshd 占用,就说明至少有一个 SSH 会话已经成功建立了 RemoteForward。


6 一个很关键的现象:关闭另一个 VS Code 窗口后就正常了

后来发现:

只要把已经连接服务器的 VS Code 窗口关闭,新连接就能正常建立。

这说明问题和 VS Code Remote-SSH 的 SSH 会话复用方式高度相关。

也就是说,很可能存在这种情况:

text 复制代码
VS Code 窗口 A
  ↓
SSH connection A
  ↓
RemoteForward 10802 成功

VS Code 窗口 B
  ↓
SSH connection B
  ↓
再次 RemoteForward 10802
  ↓
失败

而另一台电脑却没有这个问题,说明两台电脑的 Remote-SSH 配置或者连接模式可能不同。


7 尝试使用 useLocalServer

可以在 VS Code 的 settings.json 中尝试:

json 复制代码
{
    "remote.SSH.useLocalServer": true
}

其目的之一,是让多个 VS Code 远程窗口更倾向于复用本地 Remote-SSH 连接,而不是每个窗口都完全独立启动新的 SSH 会话。

对于包含固定 RemoteForward 的 SSH 配置,这样可以降低重复绑定同一远端端口的概率。

修改以后,建议:

  1. 完全退出所有 VS Code 窗口;
  2. 在任务管理器中确认没有残留的 Code.exe;
  3. 重新打开 VS Code;
  4. 再尝试连接。

8 不要轻易关闭 useExecServer

排查 Remote-SSH 时,有一种常见建议是:

json 复制代码
{
    "remote.SSH.useExecServer": false
}

这个选项在某些 Remote-SSH 故障中可能确实有帮助。

但是如果你的使用场景是:

text 复制代码
本地 VS Code
  ↓
Remote-SSH 到 Linux 宿主机
  ↓
Dev Containers
  ↓
Attach to Running Container

那么关闭 useExecServer 可能产生新的问题。

我实际遇到的表现是:

text 复制代码
运行命令 remote-containers.attachToRunningContainerFromViewlet 错误:
出现未知错误

也就是说:

Remote-SSH 本身能用了,但无法继续 Attach 到远端 Docker 容器。

因此,对于 Remote-SSH + Dev Containers 的组合,更合适的配置是:

json 复制代码
{
    "remote.SSH.useLocalServer": true,
    "remote.SSH.useExecServer": true
}

或者更简单:

json 复制代码
{
    "remote.SSH.useLocalServer": true
}

而让 useExecServer 保持默认值。


9 比较推荐的配置

最终更合理的思路是:

json 复制代码
{
    "remote.SSH.useLocalServer": true
}

而 SSH 配置保持:

sshconfig 复制代码
Host my-server
    HostName <SERVER_IP>
    Port <SSH_PORT>
    User <USERNAME>
    IdentityFile "C:\Users\<USER>\.ssh\id_rsa"

    RemoteForward 10802
    ExitOnForwardFailure yes

    ServerAliveInterval 30
    ServerAliveCountMax 3

这样既可以尽量避免多个 VS Code 窗口反复创建 SSH RemoteForward,又不会破坏 Dev Containers over SSH 的使用。


10 更稳定的方案:将代理隧道和 VS Code SSH 解耦

如果不希望 RemoteForward 受 VS Code Remote-SSH 生命周期影响,更稳妥的方法是:

不要把 RemoteForward 写在 VS Code 使用的 Host 配置中。

例如把:

sshconfig 复制代码
RemoteForward 10802
ExitOnForwardFailure yes

删掉,只保留普通 SSH 配置:

sshconfig 复制代码
Host my-server
    HostName <SERVER_IP>
    Port <SSH_PORT>
    User <USERNAME>
    IdentityFile "C:\Users\<USER>\.ssh\id_rsa"

    ServerAliveInterval 30
    ServerAliveCountMax 3

然后单独开一个 SSH 隧道:

powershell 复制代码
& "C:\Program Files\Git\usr\bin\ssh.exe" `
    -N `
    -R 10802 `
    -o ExitOnForwardFailure=yes `
    -o ServerAliveInterval=30 `
    -o ServerAliveCountMax=3 `
    my-server

其中:

text 复制代码
-N

表示只建立 SSH 隧道,不打开远端 shell。

这时整体结构变成:

text 复制代码
Windows
│
├── 独立 SSH tunnel
│     ssh -N -R 10802 my-server
│
└── VS Code Remote-SSH
      ssh my-server

服务器侧:

text 复制代码
127.0.0.1:10802
    ↓
SSH tunnel
    ↓
Windows 本地代理

Docker 侧如果需要经过 socat:

bash 复制代码
socat TCP-LISTEN:10801,bind=<DOCKER_BRIDGE_IP>,reuseaddr,fork \
      TCP:127.0.0.1:10802

整体链路:

text 复制代码
Docker Container
      ↓
<DOCKER_BRIDGE_IP>:10801
      ↓
socat
      ↓
127.0.0.1:10802
      ↓
SSH RemoteForward
      ↓
Windows
      ↓
本地代理

这个方案最大的优点是:

VS Code Remote-SSH 开几个窗口,都不会影响代理隧道。

对于需要长期使用代理的远程开发环境,我个人更推荐这种解耦方案。


11 排查时最有用的几个命令

检查 RemoteForward 端口:

bash 复制代码
sudo ss -lntp | grep <PORT>

查看对应进程:

bash 复制代码
ps -fp <PID>

检查 SSH 网络连接:

bash 复制代码
sudo ss -tnp | grep <PID>

手动测试 SSH:

powershell 复制代码
& "C:\Program Files\Git\usr\bin\ssh.exe" -vvv my-server

重点关注:

text 复制代码
remote forward
remote port forwarding failed
Address already in use

等信息。


12 总结

这类问题最容易误导人的地方,是 VS Code 最终显示的报错往往是:

text 复制代码
Failed to parse remote port

或者:

text 复制代码
过程试图写入的管道不存在

但它们经常并不是根因。

如果日志前面出现:

text 复制代码
remote port forwarding failed for listen port ...

优先检查:

  1. 远端端口是否已经被其他 sshd 占用;
  2. 是否存在旧 SSH 会话;
  3. VS Code 是否同时启动了多个 SSH 连接;
  4. ExitOnForwardFailure yes 是否导致整个 SSH 连接退出;
  5. remote.SSH.useLocalServer 是否可以改善多窗口连接复用;
  6. 如果还需要 Dev Containers,不要随意关闭 remote.SSH.useExecServer;
  7. 最稳定的做法,是将代理 SSH 隧道和 VS Code Remote-SSH 分离。

最终可以把整个问题归纳为一句话:

RemoteForward 本身没有问题,真正的问题是固定远端监听端口与 VS Code 多 SSH 会话之间发生了生命周期冲突。

相关推荐
fengkai45451 小时前
十一、MySQL 第 4-7 章
运维·数据库·mysql
荣合技术服务1 小时前
服务器数据恢复服务商——荣合科算技术服务
运维·服务器·数据恢复·荣合科算
Sayai1 小时前
ClickHouse WITH FILL 实战:监控大屏时间序列补零,附多粒度指标表与物化视图级联设计
大数据·运维·数据仓库·clickhouse·物化视图
九章-悲回风1 小时前
Linux - Docker及常用镜像部署
linux·运维·docker
xUxIAOrUIII1 小时前
守护进程(daemon)
linux·运维
2603_954708311 小时前
微能网的核心硬件协调控制装置有哪些功能?
大数据·运维·人工智能·架构·能源
Lucas_coding1 小时前
SSH 常见用法(四):使用 SCP 和 SFTP 远程传输文件
运维·ssh
Vex2une1 小时前
Windows PowerShell 发展史:从命令行工具到自动化核心
windows·自动化运维·命令行·powershell·cmd·脚本语言·对象管道
Fcy6481 小时前
Linux下 网络层IP协议详解
linux·运维·tcp/ip