Codex Desktop / App 通过 SSH 配置远程服务器记录
Codex Desktop 通过 SSH 连接远程服务器:GPT 辅助排障、代理配置与 app-server 复盘
这篇文章是 GPT 总结我的 Codex Desktop 通过 SSH 连接远程服务器后GPT写的配置记录,也是一份真实排障笔记。你可以选择性的看,大致是没错的。你也可以直接丢给 AI 看,可能有引导之后 AI 做的更快更好。
摘要
这次配置的目标不是简单地“让服务器能连上 Codex”,而是希望把 VSCode Remote-SSH 和 Codex Desktop Remote SSH 分开:
VSCode Remote-SSH:继续走原来的 SSH 入口,尽量保持原样
Codex Desktop:单独走 codex-besci 这个 SSH alias,并通过本机代理访问 OpenAI / Codex 服务
也就是说,同一台远程服务器,希望保留两个 SSH 入口:
原 SSH alias -> 给 VSCode 用
codex-besci -> 给 Codex Desktop 用
其中 codex-besci 只是给同一台服务器单独起的一个 SSH 别名,不代表另一台服务器。
说明:
本文中的用户名、IP、项目路径、服务器路径都已经脱敏。真实路径里可能包含个人用户名、学校/实验室目录或项目目录,因此不直接写进公开博客。
文章目录
- Codex Desktop 通过 SSH 连接远程服务器:GPT 辅助排障、代理配置与 app-server 复盘
-
- 摘要
- @[toc]
- 1. 配置目标
- 2. 最终想实现的结构
- 3. 背景:Codex Desktop 远程连接和 VSCode 插件不是一回事
- 4. SSH 配置:拆成两个 alias
-
- 5. 为什么要换远端端口
- 6. 分层验证网络
-
- 7. 配置远端 Codex wrapper
- 8. 重要坑点:wrapper 改好了,不代表旧 app-server 会自动生效
- 9. 在远端验证 Codex CLI 是否能工作
- 10. Codex Desktop 中连接远程项目
-
- 11. 原本想隔离 VSCode 和 Codex,但最后可能没有完全隔离
-
- 12. 如果重新配置一次,建议这样做
-
- 13. 最终总结
- 14. 参考资料
文章目录
- Codex Desktop 通过 SSH 连接远程服务器:GPT 辅助排障、代理配置与 app-server 复盘
-
- 摘要
- @[toc]
- 1. 配置目标
- 2. 最终想实现的结构
- 3. 背景:Codex Desktop 远程连接和 VSCode 插件不是一回事
- 4. SSH 配置:拆成两个 alias
- 5. 为什么要换远端端口
- 6. 分层验证网络
- 7. 配置远端 Codex wrapper
- 8. 重要坑点:wrapper 改好了,不代表旧 app-server 会自动生效
- 9. 在远端验证 Codex CLI 是否能工作
- 10. Codex Desktop 中连接远程项目
- 11. 原本想隔离 VSCode 和 Codex,但最后可能没有完全隔离
- 12. 如果重新配置一次,建议这样做
- 13. 最终总结
- 14. 参考资料
1. 配置目标
这次配置的核心目标是:让 Codex Desktop 能够通过 SSH 连接远程服务器,同时通过本机代理访问 OpenAI / Codex 后端服务。
但这里并不是简单地修改原有 SSH 配置,而是希望做到:
VSCode Remote-SSH:继续使用原来的 SSH alias
Codex Desktop:使用单独的 SSH alias
也就是让同一台服务器对应两个入口:
<ORIGINAL_SSH_ALIAS> -> 给 VSCode Remote-SSH 使用
codex-besci -> 给 Codex Desktop 使用
这样做的原因是:VSCode 原本已经可以正常远程开发,不希望因为 Codex Desktop 的代理配置影响 VSCode 的使用环境。
2. 最终想实现的结构
理想结构如下:
Windows 本机
├── VSCode
│ └── ssh <ORIGINAL_SSH_ALIAS>
│ └── 尽量不走代理,保持原来的远程开发方式
│
└── Codex Desktop
└── ssh codex-besci
└── RemoteForward <REMOTE_PROXY_PORT> -> 本机 <LOCAL_PROXY_PORT>
└── 让远端 Codex app-server 通过本机代理访问 OpenAI / Codex 后端
本文中使用下面这些占位符表示具体配置:
<ORIGINAL_SSH_ALIAS> 原来的 SSH 入口,主要给 VSCode 用
codex-besci Codex Desktop 专用 SSH 入口
<REMOTE_HOST_IP> 远程服务器 IP
<REMOTE_USER> 远程服务器用户名
<LOCAL_PROXY_PORT> Windows 本机代理端口,例如 7897
<REMOTE_PROXY_PORT> 远端反向代理端口,例如 17897
<PROJECT_DIR> 远端项目目录
<MODEL_NAME> Codex 可用模型名称
3. 背景:Codex Desktop 远程连接和 VSCode 插件不是一回事
最开始参考的是一篇讲 VSCode Remote-SSH 使用 Codex 插件 的文章。它的核心思路是:远程服务器不能直接使用本机代理,所以可以通过 SSH 的 RemoteForward,把远端端口转发到本机代理端口。
这个方向是对的。
但是后续排障发现,VSCode 插件方案 和 Codex Desktop Remote SSH 方案 不是完全一样的。
Codex Desktop 连接远程服务器时,会通过 SSH 启动远端 Codex app-server,并且要求远端登录 shell 的 PATH 里能找到 codex 命令。
因此,Codex Desktop 远程连接至少涉及下面几层:
Codex Desktop
-> SSH alias
-> 远端 shell
-> 远端 codex 命令
-> 远端 codex app-server
-> 远端 app-server 访问 OpenAI / Codex 后端
也就是说,SSH 能登录只是第一步。真正关键的是:
远端 codex 命令能否正确启动
远端 app-server 是否继承了代理环境
远端 app-server 是否真的能访问 Codex 后端
这也是后面排障的重点。
4. SSH 配置:拆成两个 alias
4.1 原来的 SSH alias:给 VSCode 用
原来的 SSH 配置大致如下:
Host <ORIGINAL_SSH_ALIAS>
HostName <REMOTE_HOST_IP>
User <REMOTE_USER>
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
这个入口继续给 VSCode Remote-SSH 使用,尽量保持原样。
4.2 Codex 专用 SSH alias:给 Codex Desktop 用
另外单独增加一个 codex-besci:
Host codex-besci
HostName <REMOTE_HOST_IP>
User <REMOTE_USER>
IdentityFile ~/.ssh/id_ed25519
RemoteForward <REMOTE_PROXY_PORT> 127.0.0.1:<LOCAL_PROXY_PORT>
ServerAliveInterval 60
ServerAliveCountMax 3
例如:
Host codex-besci
HostName <REMOTE_HOST_IP>
User <REMOTE_USER>
IdentityFile ~/.ssh/id_ed25519
RemoteForward 17897 127.0.0.1:7897
ServerAliveInterval 60
ServerAliveCountMax 3
其中最关键的是这一行:
RemoteForward 17897 127.0.0.1:7897
它的含义是:
远端服务器上的 127.0.0.1:17897
-> 通过 SSH 隧道
-> 转发到 Windows 本机的 127.0.0.1:7897
也就是说,远端服务器可以通过访问自己的:
127.0.0.1:17897
间接使用 Windows 本机的代理:
127.0.0.1:7897
5. 为什么要换远端端口
一开始使用过这样的配置:
RemoteForward 9999 127.0.0.1:7897
但是后来发现远端的 9999 端口已经被旧的 SSH 反向转发占用了。
连接时可能出现类似提示:
Warning: remote port forwarding failed for listen port 9999
可以在远端检查端口:
ss -ltn 'sport = :9999'
如果已经看到 127.0.0.1:9999 在监听,说明这个端口不能再被新的 SSH 会话绑定。
所以后来换了一个新的远端端口,例如:
RemoteForward 17897 127.0.0.1:7897
说明:
17897不是固定值,只是一个未占用端口。也可以换成其他端口,只要远端没有被占用即可。
为了避免 SSH 连接成功但端口转发失败,可以用:
ssh -o ExitOnForwardFailure=yes codex-besci "echo SSH_FORWARD_OK"
ExitOnForwardFailure 的作用是:如果本地、远程或动态端口转发无法建立,就让 SSH 直接退出,而不是继续假装连接成功。
6. 分层验证网络
这一步非常重要。
不要一上来就看 Codex Desktop 报什么错,而是先分层验证:
1. 本机代理是否可用
2. 远端服务器能否直连目标服务
3. 远端服务器能否通过 SSH RemoteForward 使用本机代理
6.1 验证本机代理可用
在 Windows PowerShell 中执行:
curl.exe -I -k --ssl-no-revoke --max-time 20 `
-x http://127.0.0.1:7897 `
https://chatgpt.com/backend-api/codex/responses
如果返回类似:
HTTP/1.1 200 Connection established
HTTP/1.1 405 Method Not Allowed
allow: POST
这通常说明代理链路已经到达后端。
这里的 405 Method Not Allowed 不一定是坏事,因为这里用的是 HEAD 请求,而目标接口可能不接受这个方法。
6.2 验证远端直连是否失败
在远端测试直连:
python3 - <<'PY'
import urllib.request
try:
req = urllib.request.Request(
"https://chatgpt.com/backend-api/codex/responses",
method="HEAD",
)
with urllib.request.urlopen(req, timeout=12) as r:
print("direct", r.status, r.reason)
except Exception as e:
print("direct", type(e).__name__, str(e)[:220])
PY
如果出现类似:
direct URLError <urlopen error [Errno 101] Network is unreachable>
说明远端服务器本身无法直连外网。
6.3 验证远端能否通过反向代理访问
先确保 SSH 转发已经建立,然后在远端执行:
python3 - <<'PY'
import urllib.request
proxy = "http://127.0.0.1:17897"
opener = urllib.request.build_opener(
urllib.request.ProxyHandler({
"http": proxy,
"https": proxy,
})
)
try:
req = urllib.request.Request(
"https://chatgpt.com/backend-api/codex/responses",
method="HEAD",
)
with opener.open(req, timeout=12) as r:
print("proxy", r.status, r.reason)
except Exception as e:
print("proxy", type(e).__name__, str(e)[:220])
PY
如果返回类似:
proxy HTTPError HTTP Error 405: Method Not Allowed
说明远端已经可以通过 SSH 反向代理访问到 Codex 后端。
原始排障记录中的结论也是这样:
远端直连失败
远端通过 127.0.0.1:<REMOTE_PROXY_PORT> 可以访问 Codex backend
旧端口存在占用
wrapper 存在但旧 app-server 没继承代理环境
7. 配置远端 Codex wrapper
为了让远端 Codex 一定走代理,GPT 给出的方案是在远端创建一个 wrapper:
~/.local/bin/codex
内容如下:
#!/usr/bin/env bash
export http_proxy=http://127.0.0.1:17897
export https_proxy=http://127.0.0.1:17897
export HTTP_PROXY=http://127.0.0.1:17897
export HTTPS_PROXY=http://127.0.0.1:17897
exec "$HOME/.codex/packages/standalone/releases/<CODEX_VERSION>/bin/codex" "$@"
然后添加执行权限:
chmod +x ~/.local/bin/codex
确认当前 shell 优先找到 wrapper:
which codex
理想输出:
/home/<REMOTE_USER>/.local/bin/codex
这个 wrapper 的作用是:
调用 codex 前,先注入 http_proxy / https_proxy 等代理环境变量
然后再 exec 真正的 standalone codex 二进制文件
8. 重要坑点:wrapper 改好了,不代表旧 app-server 会自动生效
这是整个排障过程中最容易误判的地方。
wrapper 已经配置好,但 Codex Desktop 仍然连接失败。后续排查发现,远端已经存在旧的:
codex app-server --listen unix://
这个旧 app-server 是在 wrapper 修好之前启动的,所以它没有继承新的代理环境变量:
http_proxy
https_proxy
HTTP_PROXY
HTTPS_PROXY
也就是说:
wrapper 文件已经正确
但是旧 app-server 还在用旧环境运行
所以必须重启远端 Codex app-server。
查看进程:
ps -ef | grep 'codex app-server'
重点识别 standalone Codex 的 app-server,例如:
$HOME/.codex/packages/standalone/releases/.../bin/codex app-server --listen unix://
$HOME/.codex/packages/standalone/releases/.../bin/codex app-server proxy
停止这些旧进程后,清理 stale socket / lock:
rm -f ~/.codex/app-server-control/app-server-control.sock
rm -f ~/.codex/app-server-control/app-server-startup.lock
注意:
不要误杀 VSCode Server 或 VSCode 插件自己的进程。
比如下面这种路径就可能是 VSCode 扩展相关进程:~/.vscode-server/extensions/.../codex app-server
原始排障记录显示:旧 standalone app-server 没有代理环境,所以必须停掉旧进程,并清理 app-server-control 里的 socket 和 lock 文件。
9. 在远端验证 Codex CLI 是否能工作
进入一个远端项目目录:
cd <PROJECT_DIR>
为了确保使用 wrapper,可以临时指定 PATH:
PATH="$HOME/.local/bin:$PATH"
然后测试:
printf "Print exactly OK.\n" | timeout 45 codex exec -m <MODEL_NAME> --sandbox read-only -
如果能返回模型响应,说明下面几层都已经打通:
远端 codex 命令可执行
wrapper 生效
代理变量生效
SSH RemoteForward 生效
远端 Codex 可以访问后端
说明:
<MODEL_NAME>请换成自己当前 Codex 可用的模型名称。
10. Codex Desktop 中连接远程项目
完成前面的配置后,再打开 Codex Desktop。
大致流程是:
Codex Desktop
-> 设置
-> 连接
-> 找到 SSH
-> 添加
-> 选择 codex-besci
-> 选择远端项目目录
Codex Desktop 应该会通过 codex-besci 这个 SSH alias 连接远端,并启动远端 Codex app-server。
10.1 不确定点:Codex Desktop 是否一定只使用所选 SSH alias?
从官方文档看,Codex App 会通过 SSH 配置连接远程主机,并启动远端 app-server。
但这次排查中,旧 app-server、socket、lock、VSCode 插件进程之间可能存在残留影响,所以不能百分百确认每一次启动都完全符合预期。
因此,如果要严格隔离,最好每次修改配置后都清理旧 app-server,并重新连接。
11. 原本想隔离 VSCode 和 Codex,但最后可能没有完全隔离
最初目标是:
VSCode:走 <ORIGINAL_SSH_ALIAS>,不走代理
Codex:走 codex-besci,走代理
但是最后实际现象像是:
VSCode 可能也能走代理
Codex Desktop 也能走代理
这部分没有完全搞清楚,所以这里必须标注为不确定。
11.1 不确定点:为什么最后 VSCode 似乎也走了代理?
GPT 根据排障过程推测,可能有下面几种原因。
11.1.1 可能原因 A:代理变量被写进了远端全局 shell 配置
如果在排查过程中,把下面这些内容写进了:
~/.bashrc
~/.profile
~/.zshrc
/etc/environment
例如:
export HTTP_PROXY=http://127.0.0.1:17897
export HTTPS_PROXY=http://127.0.0.1:17897
export http_proxy=http://127.0.0.1:17897
export https_proxy=http://127.0.0.1:17897
那么所有使用这个远端用户的 shell 都可能继承代理,包括 VSCode Remote-SSH。
检查方法:
grep -nEi 'http_proxy|https_proxy|HTTP_PROXY|HTTPS_PROXY|17897|9999' \
~/.bashrc ~/.profile ~/.zshrc 2>/dev/null
如果想让 VSCode 不走代理,就不要把代理变量写进全局 shell 配置。
11.1.2 可能原因 B:VSCode Remote Settings 被配置了代理
如果远端 VSCode 的 settings 里有:
{
"http.proxy": "http://127.0.0.1:17897",
"http.proxySupport": "on"
}
那么 VSCode 插件也可能走代理。
检查:
cat ~/.vscode-server/data/Machine/settings.json
如果目标是让 VSCode 不走代理,就需要删除这类配置。
11.1.3 可能原因 C:旧 app-server 或旧 socket 影响判断
这次遇到过旧 app-server 没有继承 wrapper 代理环境的问题。也就是说,运行中的进程环境和当前文件配置并不一定一致。
所以如果只是看配置文件,可能会误判。
建议检查:
ps -ef | grep 'codex app-server'
必要时清理:
rm -f ~/.codex/app-server-control/app-server-control.sock
rm -f ~/.codex/app-server-control/app-server-startup.lock
11.1.4 可能原因 D:GPT / Codex 辅助调试过程中修改过多处配置
这次不是完全按照一个固定教程一步步手动配置的,而是由 GPT 和 Codex 边排查边修改。过程中可能改过:
SSH config
RemoteForward 端口
远端 wrapper
远端 shell 配置
VSCode Remote Settings
Codex app-server 进程
stale socket / lock
最后 Codex Desktop 确实能连上,但“为什么 VSCode 最后也像是走了代理”,没有完全确认。
更准确的结论是:
这次尝试让 Codex Desktop 单独走 codex-besci 代理入口;
最终 Codex Desktop 成功连接;
但 VSCode 是否仍然完全不受代理影响,没有彻底确认。
12. 如果重新配置一次,建议这样做
12.1 SSH config 明确分两个入口
Host <ORIGINAL_SSH_ALIAS>
HostName <REMOTE_HOST_IP>
User <REMOTE_USER>
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
Host codex-besci
HostName <REMOTE_HOST_IP>
User <REMOTE_USER>
IdentityFile ~/.ssh/id_ed25519
RemoteForward 17897 127.0.0.1:7897
ServerAliveInterval 60
ServerAliveCountMax 3
使用规则:
VSCode 只连接 <ORIGINAL_SSH_ALIAS>
Codex Desktop 只连接 codex-besci
12.2 不要污染远端全局环境变量
不要把代理变量写进:
~/.bashrc
~/.profile
~/.zshrc
/etc/environment
除非目标就是让整个远端用户环境都走代理。
12.3 只在 Codex wrapper 中注入代理
推荐 wrapper:
#!/usr/bin/env bash
export http_proxy=http://127.0.0.1:17897
export https_proxy=http://127.0.0.1:17897
export HTTP_PROXY=http://127.0.0.1:17897
export HTTPS_PROXY=http://127.0.0.1:17897
exec "$HOME/.codex/packages/standalone/releases/<CODEX_VERSION>/bin/codex" "$@"
12.4 每次改 wrapper 后重启 app-server
ps -ef | grep 'codex app-server'
停掉旧 standalone Codex app-server 后清理:
rm -f ~/.codex/app-server-control/app-server-control.sock
rm -f ~/.codex/app-server-control/app-server-startup.lock
12.5 用命令验证,不要只看界面
验证 SSH 转发:
ssh -o ExitOnForwardFailure=yes codex-besci "echo SSH_FORWARD_OK"
验证远端代理:
curl -I -m 20 -x http://127.0.0.1:17897 https://chatgpt.com/
验证 Codex CLI:
PATH="$HOME/.local/bin:$PATH"
printf "Print exactly OK.\n" | timeout 45 codex exec -m <MODEL_NAME> --sandbox read-only -
13. 最终总结
这次配置的核心不是“SSH 能不能登录”,而是要把下面几层全部理清楚:
1. Windows 本机代理是否可用
2. SSH alias 是否配置正确
3. RemoteForward 是否真的建立成功
4. 远端能否通过反向代理访问 OpenAI / Codex 后端
5. 远端 codex 命令是否在 PATH 中
6. Codex wrapper 是否注入了代理
7. 旧 codex app-server 是否仍在使用旧环境
8. VSCode 是否被全局代理变量或 Remote Settings 影响
这次排障得到的核心经验是:
Codex Desktop 连接远程服务器时,SSH 只是入口;
真正关键的是远端 codex app-server 的运行环境。
如果只是想让 Codex Desktop 走代理,而不想影响 VSCode,比较稳妥的方式是:
给 Codex Desktop 单独建 SSH alias;
只在这个 alias 上配置 RemoteForward;
只在 codex wrapper 中注入代理;
不要把代理写入远端全局 shell;
不要改 VSCode Remote Settings;
每次修改后重启旧 app-server。
这次最终能跑通,但仍然保留一个不确定结论:
最初想让 VSCode 和 Codex 完全隔离;
但最后 VSCode 似乎也受到了代理配置影响;
具体是全局环境变量、VSCode settings,还是旧 app-server / socket 残留导致的,没有完全确认。
因此,这篇文章既是教程,也是一次真实的 GPT 辅助排障记录。确定的部分写成步骤;不确定的部分单独标注,避免把猜测写成结论。
14. 参考资料
- OpenAI Codex Remote Connections 官方文档:说明 Codex App 通过 SSH 启动远端 Codex app-server,并要求远端
codex命令在登录 shell 的PATH中可用。 - OpenAI Codex Quickstart / CLI 文档:说明 Codex CLI 的安装和登录方式。
- OpenSSH
ssh_config手册:说明RemoteForward和ExitOnForwardFailure的含义。 - 原始 GPT / Codex 排障记录:远端直连失败、反向代理可用、旧端口占用、wrapper 与旧 app-server 环境不一致等问题。
更多推荐


所有评论(0)