VS Code Remote-SSH:让远端 Codex 使用本地网络服务

适用场景:VS Code 通过 Remote-SSH 打开远端工作区,Copilot 侧边栏可以加载,但发送消息时出现 error sending requeststream disconnected、连接超时或 TLS 连接失败。本文介绍如何通过 SSH 端口转发让远端 Codex 访问本地网络服务。
本文仅使用通用示例,不包含任何真实服务器、账户或本机配置。请根据自己的环境替换示例值。

1. 先理解问题

在 Remote-SSH 窗口中,Codex 扩展通常运行在远端 VS Code Server 内。真正发起网络请求的是远端的 Codex 进程,而不是本机 VS Code。

因此:

  • 本机 Codex 能联网,不代表远端 Codex 能联网;
  • 远端的 127.0.0.1 指向远端机器自身;
  • 本地网络服务监听在 127.0.0.1 时,远端不能直接访问;
  • 只修改本机 VS Code 的 http.proxy,通常不能解决远端 Codex 的网络问题;
  • 本机和远端的 ~/.codex 是两个不同目录。

解决思路是使用 SSH 远程端口转发,将本地网络服务映射到远端回环地址:

远端 Codex
    │
    ▼
远端 127.0.0.1:17890
    │
    │ SSH 加密隧道
    ▼
本地 127.0.0.1:7890
    │
    ▼
互联网

2. 本文使用的示例

参数 示例 含义
SSH Host 别名 remote-dev ~/.ssh/config 中的连接名称
服务器地址 203.0.113.10 文档保留地址,不是真实服务器
远端用户名 remote-user 示例用户名
本地服务端口 7890 本地运行的网络服务端口
远端映射端口 17890 SSH 在远端回环地址创建的端口转发端口
本文后续命令均使用这组示例值。使用前至少需要替换:
remote-dev
203.0.113.10
remote-user
7890(如果本机网络服务不是该端口)

17890 只是示例中的远端空闲端口,也可替换为其他未被占用的高位端口。

3. 7890 是什么

7890 不是 Codex、OpenAI、VS Code 或 SSH 的固定端口。它只是本文假设的本机网络服务端口

许多网络服务客户端会提供以下一种或多种监听端口:

  • HTTP 端口;
  • SOCKS 端口;
  • Mixed 端口(同时接受 HTTP 和 SOCKS 请求)。

本文使用 HTTP 网络格式:

http://127.0.0.1:7890

因此应选择网络服务商提供的 HTTP 或 Mixed 端口。如果你的网络服务显示其他端口,例如 108010876152,请以软件界面中的实际配置为准。

即使目标网站使用 HTTPS,网络服务地址仍可写成 http://127.0.0.1:7890。客户端会通过 HTTP CONNECT 建立加密隧道。

确认本机网络服务端口

优先在网络服务商的设置界面查找:

HTTP Port
Mixed Port
本地网络服务端口
混合端口

然后在本机测试:

curl -I --max-time 15 \
  -x http://127.0.0.1:7890 \
  https://chatgpt.com

收到 HTTP 响应说明基础网络服务链路可用。若这里已经失败,应先检查网络服务商、节点、规则和端口,不必继续配置 Remote-SSH。

4. 配置 SSH 反向端口转发

本机编辑:

~/.ssh/config

加入对应 Host:

Host remote-dev
  HostName 203.0.113.10
  User remote-user
  Port 22

  RemoteForward 127.0.0.1:17890 127.0.0.1:7890
  ExitOnForwardFailure no

  ServerAliveInterval 30
  ServerAliveCountMax 3

关键行:

RemoteForward 127.0.0.1:17890 127.0.0.1:7890

它表示:

  • 在远端监听 127.0.0.1:17890
  • 收到的连接经 SSH 隧道转发回本机;
  • 最终转发给本地的网络服务 127.0.0.1:7890

远端只监听 127.0.0.1,可以避免将网络服务入口暴露在远端机器的外部网络接口上。

为什么使用 ExitOnForwardFailure no

VS Code Remote-SSH 可能为同一窗口建立多个 SSH 通道。第一个通道绑定远端端口后,后续通道可能无法重复绑定。

如果配置为:

ExitOnForwardFailure yes

后续辅助连接可能因为端口已被占用而直接退出。将反向转发写在 VS Code 使用的 Host 配置中时,no 通常更兼容。

检查 SSH 配置是否被正确解析:

ssh -G remote-dev | grep -E \
  '^(hostname|user|port|remoteforward|exitonforwardfailure) '

5. 从远端验证隧道

重新连接 Remote-SSH 后,在 VS Code 的远端终端执行:

curl -I --max-time 15 \
  -x http://127.0.0.1:17890 \
  https://chatgpt.com

出现以下任意一种有效 HTTP 响应,通常都说明 DNS、TCP、TLS 和网络服务隧道已经正常工作:

HTTP/2 200
HTTP/2 302
HTTP/1.1 200 Connection established
HTTP/2 401
HTTP/2 403

401403 不一定是隧道失败;手工 curl 没有 ChatGPT 的登录上下文,服务器可以拒绝业务访问。应重点区分这些响应与以下网络层错误:

Connection refused
Operation timed out
Could not connect to 127.0.0.1 port 17890
TLS handshake failed

如果远端无法连接 17890,先检查:

  1. Remote-SSH 是否已重新连接;
  2. 本机 ~/.ssh/config 是否被当前 Host 使用;
  3. 本地网络服务 7890 是否仍在运行;
  4. 远端 17890 是否被其他程序占用。

6. 配置远端 Codex 环境

Codex 官方文档说明,桌面应用和 IDE 扩展可能不会继承 Shell 环境变量,需要将必要变量放入 ~/.codex/.env,然后重启应用或扩展。

因此,以下操作必须在远端终端执行。

先备份已有文件:

mkdir -p ~/.codex
test ! -f ~/.codex/.env || \
  cp ~/.codex/.env ~/.codex/.env.backup

如果该文件没有其他需要保留的变量,可直接写入:

cat > ~/.codex/.env <<'EOF'
HTTP_PROXY=http://127.0.0.1:17890
HTTPS_PROXY=http://127.0.0.1:17890
ALL_PROXY=http://127.0.0.1:17890
NO_PROXY=127.0.0.1,localhost,::1
http_proxy=http://127.0.0.1:17890
https_proxy=http://127.0.0.1:17890
all_proxy=http://127.0.0.1:17890
no_proxy=127.0.0.1,localhost,::1
EOF

chmod 600 ~/.codex/.env

同时提供大小写变量是为了兼容不同平台和网络库。

如果原文件中还有其他配置,请手动编辑并仅更新上述网络服务相关项,不要直接覆盖。

不要把 SSH 密码、ChatGPT 密码或不必要的访问令牌写进该文件。

7. 让远端 Codex 重新读取配置

先在 VS Code 命令面板执行:

Developer: Reload Window

重新打开 Codex 侧边栏并新建任务测试。

如果仍然复用旧进程,可在确认没有运行中 Codex 任务后,在远端终端终止 Codex app-server

pkill -f \
  'openai.chatgpt-.*/bin/.*codex.*app-server' \
  || true

然后再次执行 Developer: Reload Window

该命令会中断正在运行的远端 Codex 任务,因此只应作为重载无效时的排查步骤。

8. 如何确认已经修复

最直接的验证是在远端 Codex 中发送一个简单请求,并确认能够收到完整回复。

还可以使用以下辅助方法进行检查。

检查远端进程

在本机执行:

code --status

Remote: SSH: remote-dev 部分,应能看到远端 extension-host 和 Codex app-server。这说明网络请求确实由远端 Codex 发起。

检查 SSH 是否访问本地网络服务

macOS 可在本地执行:

lsof -nP -a -c ssh -iTCP

当远端正在通过隧道访问网络服务时,可能看到 SSH 进程连接到:

127.0.0.1:7890

这是辅助证据。空闲时没有活动连接,并不代表隧道一定失败。

查看 Codex 输出

在 VS Code 中,打开:

View → Output → Codex

可重点搜索以下关键词:

stream disconnected
error sending request
connection refused
timed out
tls handshake

9. 常见误区

误区一:只设置本机 VS Code 的 http.proxy

它主要影响本机 VS Code 的网络请求,不能代替 SSH 反向转发,也不能保证远端 Codex 子进程获得网络服务的环境。

对于本文方案,最小必要配置是:

  1. 本机 SSH RemoteForward
  2. 远端 ~/.codex/.env
  3. 重启远端 Codex 扩展进程。

误区二:在远端使用本地网络服务端口

远端不能直接使用:

http://127.0.0.1:7890

因为远端的 127.0.0.1 不是本机。远端 Codex 应使用 SSH 创建的远程入口:

http://127.0.0.1:17890

误区三:只在远端终端执行 export

终端 Shell 与 VS Code 扩展的宿主进程不属于同一个进程链。终端里的 export 通常只对该终端及其子进程有效。

误区四:重新打开窗口等于重启 Codex

VS Code Server、扩展宿主和 Codex app-server 都可能被复用。应在修改远端 .env 后显式 Reload;必要时再终止旧的 app-server

误区五:在本机检查远端监听端口

RemoteForward 创建的 17890 监听端口位于远端。在本机执行:

lsof -iTCP:17890

看不到监听进程是正常的。应在远端运行 curl 命令来验证。

误区六:多个 Remote-SSH 窗口同时排障

多个窗口可能产生多个扩展宿主、Codex 进程和 SSH 通道。排障期间最好只保留一个远端窗口。

10. 更稳定的独立隧道方案

如果 VS Code 经常重连,或者多个 SSH 通道反复争抢远端端口,可以把网络服务隧道与 VS Code 连接分开。

在本地网络服务 SSH 配置中建立专用 Host:

Host remote-dev-proxy
  HostName 203.0.113.10
  User remote-user
  Port 22

  RemoteForward 127.0.0.1:17890 127.0.0.1:7890
  ExitOnForwardFailure yes
  ServerAliveInterval 30
  ServerAliveCountMax 3

在本机单独运行:

ssh -N remote-dev-proxy

VS Code 则连接另一个不包含 RemoteForward 的 Host。

该方案的优点:

  • 只有一个 SSH 进程负责绑定远端端口;
  • VS Code Reload 不会自动终止网络服务隧道;
  • 隧道可以独立启动、停止和排查。

如果需要长期运行,可进一步使用 SSH 密钥、autossh 或系统服务,但应遵循所在组织的安全策略。

11. 故障定位表

现象 最可能原因 建议
本地网络服务测试失败 网络服务商、节点、规则或端口异常 先修复本地网络服务
本机成功,远端 17890 拒绝连接 SSH 反向转发未建立 检查 SSH 配置并重连
远端 curl 成功,Codex 仍失败 Codex 未读取网络服务环境 检查远端 .env 并 Reload
Reload 后仍报相同错误 app-server 进程未退出 无运行任务时终止旧进程并重启
提示远端端口转发失败 端口被占用或多个 SSH 通道竞争 换端口或使用独立隧道
运行一段时间后断开 SSH 隧道或本地网络服务中断 检查 KeepAlive、SSH 和网络服务状态

12. 安全与发布注意事项

  1. 远端监听应使用环回地址:

    127.0.0.1:17890
    

    不要轻易改成:

    0.0.0.0:17890
    
  2. 不要启用 GatewayPorts yes,除非明确理解其安全影响。

  3. 不要在截图、日志或教程中公开:

    • 真实服务器 IP 或域名;
    • SSH 用户名和密钥路径;
    • 组织内部 Host 别名;
    • 访问令牌、Cookie 或认证头部;
    • 完整的用户主目录和项目路径。
  4. ~/.codex/.env 建议设置为仅当前用户可读:

    chmod 600 ~/.codex/.env
    
  5. 对外发布前,可使用文档保留地址,例如:

    192.0.2.0/24
    198.51.100.0/24
    203.0.113.0/24
    

13. 最小操作清单

本地网络服务

curl -I --max-time 15 \
  -x http://127.0.0.1:7890 \
  https://chatgpt.com

~/.ssh/config 中配置:

RemoteForward 127.0.0.1:17890 127.0.0.1:7890

远端

curl -I --max-time 15 \
  -x http://127.0.0.1:17890 \
  https://chatgpt.com

在远端机器的 ~/.codex/.env 中配置本地网络服务端口:

HTTP_PROXY=http://127.0.0.1:17890
HTTPS_PROXY=http://127.0.0.1:17890
ALL_PROXY=http://127.0.0.1:17890
NO_PROXY=127.0.0.1,localhost,::1

最后执行:

Developer: Reload Window

14. 一句话总结

Remote-SSH 中的 Codex 是远端进程。先用 SSH RemoteForward 把本地网络服务映射到远端回环地址端口,再把该远端网络服务的地址写入远端 ~/.codex/.env,最后重启 Codex 扩展。

15. 参考资料

更多推荐