一份面向 macOS、远程 Linux 服务器、Codex Desktop 与 VS Code Remote-SSH 的三别名隔离教程。目标是在不修改、不关闭、不复用当前 Codex Desktop 活跃 SSH 连接的前提下,为 VS Code Remote Codex 建立独立的 SSH RemoteForward 代理通道,并提供一个完全不转发端口的维护入口。
本仓库只包含 Markdown、配置模板和只读 Shell 诊断脚本。请先通读并替换占位符,不要直接粘贴整份个人 SSH 配置。
典型环境如下:
- Mac 上的 HTTP 代理监听
127.0.0.1:<LOCAL_PROXY_PORT>; - Codex Desktop 通过 SSH 登录远程服务器,并需要服务器侧的回环代理端口;
- VS Code Remote-SSH 连接同一台服务器,远端 Codex 扩展也需要代理;
- 两个代理通道应能分别重启、诊断和回滚;
- 普通维护 SSH 不应意外继承任何端口转发。
不适用于 SOCKS-only 代理、需要服务器端 GatewayPorts yes 的公网监听,或希望多个客户端共享同一个 SSH master socket 的方案。
本教程受 sunshinerobot/codex-over-easytier 的网络思路启发,但解决的问题和实现边界不同。
| 项目 | 本仓库 | 上游项目 |
|---|---|---|
| 重点 | 同一台 Mac 到同一服务器的 Desktop、VS Code、维护 SSH 三别名隔离 | 通过 EasyTier 等网络条件运行远程 Codex |
| 代理通道 | Desktop 与 VS Code 各自一个 RemoteForward |
以其仓库当前文档为准 |
| 连接复用 | 三个别名均禁用 ControlMaster、ControlPath 与 ControlPersist |
以其仓库当前文档为准 |
| 维护入口 | codex-shell 强制 ClearAllForwardings yes |
非本教程比较重点 |
| 发布内容 | 脱敏模板、说明和只读诊断脚本 | 独立项目 |
本仓库不是上游项目的分支,也不复制其配置;详见 ATTRIBUTION.md。
flowchart LR
P["Mac HTTP proxy<br/>127.0.0.1:<LOCAL_PROXY_PORT>"]
subgraph M["Mac SSH clients"]
D["codex-desktop<br/>no SSH multiplexing"]
V["codex-vscode<br/>no SSH multiplexing"]
S["codex-shell<br/>ClearAllForwardings yes"]
end
subgraph R["Remote Linux server"]
DP["127.0.0.1:<DESKTOP_REMOTE_PORT><br/>Desktop-only proxy endpoint"]
VP["127.0.0.1:<VSCODE_REMOTE_PORT><br/>VS Code-only proxy endpoint"]
DC["Codex Desktop remote process"]
VS["VS Code Server and remote Codex"]
SH["Maintenance shell<br/>no forwarding listener"]
end
P --> D --> DP --> DC
P --> V --> VP --> VS
S --> SH
codex-dual-ssh-proxy 中的 “dual” 指两条代理通道;第三个别名是无转发维护通道。
仓库只使用以下六个环境相关占位符:
| 占位符 | 含义 | 示例 |
|---|---|---|
<SERVER_IP> |
SSH 可达的服务器地址 | 使用你自己的地址 |
<SERVER_USER> |
服务器 SSH 用户名 | 使用你自己的用户 |
<PRIVATE_KEY> |
Mac 上现有私钥路径 | 仅填写路径,不提交密钥 |
<LOCAL_PROXY_PORT> |
Mac HTTP 代理端口 | 7890 |
<DESKTOP_REMOTE_PORT> |
服务器上的 Desktop 回环端口 | 17890 |
<VSCODE_REMOTE_PORT> |
服务器上的 VS Code 回环端口 | 17892 |
端口可以自行更换,但 <DESKTOP_REMOTE_PORT> 与 <VSCODE_REMOTE_PORT> 必须不同。模板使用显式回环绑定,因此端口只应监听服务器的 127.0.0.1,而不是公网接口。
数据方向容易混淆:RemoteForward 127.0.0.1:17892 127.0.0.1:7890 表示服务器访问 127.0.0.1:17892 时,流量经 SSH 回到 Mac 的 127.0.0.1:7890。
整个迁移过程遵守以下底线:
- 不在 Desktop 活跃工作期间关闭、重连或接管它的 SSH 会话。
- 不执行
pkill ssh、killall ssh或任何按名称批量结束 SSH 的命令。 - 不执行
codex logout,不删除~/.codex,也不发布~/.codex/auth.json。 - 不把代理写进服务器全局 shell 配置;VS Code 代理只进入 VS Code Server 专用环境。
- 不提交私钥、密码、EasyTier 密钥、Clash 订阅、OpenAI token、GitHub token、真实公网地址或完整个人 SSH 配置。
- 先备份精确目标、检查有效配置,再安排需要重连的步骤。
仓库中的三个脚本只读取监听、环境和 ssh -G 结果,不修改配置、不结束进程、不建立持久连接。
先保存正在进行的 Codex 工作,并在另一个本地终端检查原 Host 的有效配置。把命令末尾替换成你当前使用的 Host 名:
ssh -G your-current-host | awk '
$1 == "hostname" ||
$1 == "remoteforward" ||
$1 == "controlmaster" ||
$1 == "controlpath" ||
$1 == "controlpersist" ||
$1 == "exitonforwardfailure"
'ssh -G 是静态有效配置检查,不证明远端监听已经建立;它还可能触发个人配置中的 Match exec。先审阅自己的 SSH 配置,再运行仓库验证脚本。
./scripts/diagnose-local.sh 7890普通用户运行 lsof 可能看不到由特权代理核心持有的监听,因此脚本还会交叉检查 netstat 和 TCP 连通性。
在服务器维护终端中只读检查候选端口:
ss -lnt | awk '$4 ~ /:17890$|:17892$/'结果分三种情况:
- 端口空闲:可作为新通道候选;
17890已由当前 Desktop 通道监听:保持不动,先只添加 VS Code 与维护别名;- 端口被无关进程占用:选择其他未占用端口,不要结束未知进程。
还需确认服务器 SSH 服务允许 TCP forwarding。若你无权查看或修改 sshd 配置,请联系管理员,不要自行绕过策略。
以下命令只创建一份带时间戳的备份,不会激活新配置:
backup_path="$HOME/.ssh/config.backup.$(date +%Y%m%d-%H%M%S)"
cp -p "$HOME/.ssh/config" "$backup_path"
printf 'Backup: %s\n' "$backup_path"然后只从 examples/ssh-config.example 复制相关 Host 块,替换六个占位符。不要用模板覆盖整份 ~/.ssh/config。
如果 Desktop 正在使用原 Host:
- 保留原 Host 块和活跃连接不变;
- 先增加
codex-vscode,只使用<VSCODE_REMOTE_PORT>; - 增加
codex-shell,其中没有RemoteForward,并设置ClearAllForwardings yes; - 运行静态检查;
- 先通过
codex-shell验证普通登录,再让 VS Code 连接codex-vscode。
若原 Host 名已经是 codex-desktop,不要在文件后面再添加同名块。OpenSSH 对重复选项通常采用先取得的值,后面的块未必能覆盖前面的值。请在安排好 Desktop 重连窗口后,精确更新原块。
完成 VS Code 独立通道验证后,再安排 Desktop 迁移:
- 保存并确认 Desktop 工作已完成;
- 精确修改 Desktop 对应 Host 块,使其只拥有
<DESKTOP_REMOTE_PORT>; - 设置
ControlMaster no、ControlPath none、ControlPersist no; - 设置
ExitOnForwardFailure yes; - 正常退出该应用或会话后再重连,不使用批量结束命令。
修改 ~/.ssh/config 不会自动改变已经建立的 SSH 进程;新设置只对后续连接生效。
旧式双通道方案可以给 Desktop 与 VS Code 分配不同 ControlPath,但仍需理解 master socket 的生命周期。三别名新版采用更直接的边界:
ControlMaster no
ControlPath none
ControlPersist no三个别名都不复用已有 master,因此不存在跨别名借用 socket 的路径。若旧配置仍有 master socket,只在确认没有依赖会话、并保存工作后,使用精确 socket 进行检查和优雅退出:
ssh -S /exact/path/to/socket -O check your-current-host
ssh -S /exact/path/to/socket -O exit your-current-host不要把路径换成通配符,也不要用进程名批量结束 SSH。若无法确认 socket 的归属,保留它,等待原会话正常结束。
替换端口参数后运行:
./scripts/verify-three-aliases.sh \
codex-desktop codex-vscode codex-shell \
7890 17890 17892脚本要求:
- Desktop 恰好一个回环
RemoteForward,指向 Mac 代理; - VS Code 恰好一个不同的回环
RemoteForward,指向同一 Mac 代理; - 维护别名没有转发且
ClearAllForwardings yes; - 三个别名均不使用 SSH multiplexing;
- 两个代理别名均设置
ExitOnForwardFailure yes。
不要把代理变量直接追加到服务器的 ~/.bashrc、~/.profile 或系统环境。把 examples/server-env-setup.example 中的标记块合并到服务器的:
~/.vscode-server/server-env-setup
用真实值替换 <VSCODE_REMOTE_PORT> 与 <SERVER_IP>,并保留:
unset ALL_PROXY
unset all_proxy这样 VS Code Server 及其远端扩展使用 http://127.0.0.1:<VSCODE_REMOTE_PORT>,普通维护 shell 不会被教程主动注入代理。该文件可能包含你已有的环境设置,只合并标记块,不要整文件覆盖。
examples/vscode-settings.example.json 是有效 JSON 的分组示例,不是可整体粘贴的 settings.json。把各内层字段合并到对应设置范围:
- 本地 User 设置:为
codex-vscode和codex-shell指定远程平台; - Remote
[SSH: codex-vscode]设置:如确有需要,令远端 VS Code HTTP 流量使用http://127.0.0.1:<VSCODE_REMOTE_PORT>; - 本地 VS Code 若不能自动使用 Mac 代理,可选用
http://127.0.0.1:<LOCAL_PROXY_PORT>; - 只有遇到确切的
PendingMigrationError或navigator兼容性报错时,才在本地和远端设置"extensions.supportNodeGlobalNavigator": true。问题消失且升级验证通过后可移除,不应把它视为永久必需项。
设置入口:命令面板中的 Preferences: Open User Settings (JSON);连接远端后使用 Preferences: Open Remote Settings (JSON)。
按照通道逐个验收,不要同时重启所有客户端。
-
保持现有 Desktop 连接不动。
-
使用
ssh codex-shell验证维护登录;服务器上不应新增教程端口。 -
使用 VS Code 的
Remote-SSH: Connect to Host...连接codex-vscode。 -
若修改了
server-env-setup,通过命令面板执行Remote-SSH: Kill VS Code Server on Host...,只选择codex-vscode,然后重连。 -
在 VS Code 远端终端执行只读诊断:
./scripts/diagnose-remote.sh 17892 https://github.com
-
检查服务器监听只在回环地址:
ss -lnt | awk '$4 ~ /127\.0\.0\.1:17890$|127\.0\.0\.1:17892$/'
-
验证 VS Code 远端 Codex 能发起请求,并确认 Desktop 仍正常。
-
最后在计划窗口中迁移并重连 Desktop,再分别复测两个端口。
验收失败时先停止下一步,不要为了“清理”而结束其他 SSH 进程。参见 故障排查。
Desktop 与 VS Code 可以在服务器上打开同一工作目录,因此磁盘文件通常可见于两端;但同时编辑同一文件仍可能互相覆盖,应依赖 Git、编辑器冲突提示或团队约定协调。
Codex 聊天、任务上下文、认证状态、扩展本地状态和未保存编辑器缓冲区不保证在 Desktop 与 VS Code 之间同步。SSH 通道隔离只解决网络和进程边界,不提供会话同步。
RemoteForward 监听存在只说明 SSH 建立了端口。还要确认 Mac 的本地代理端口可达、代理协议是 HTTP、远端环境变量指向正确的 VS Code 端口。分别运行两个诊断脚本。
macOS 上代理核心可能由不同权限的进程持有,普通用户的 lsof 会漏报。以 netstat 与 nc 的交叉结果为准,不要因为单个空结果就修改代理。
检查更早出现的通配 Host 块、Include 文件和重复别名。验证脚本故意要求代理别名只有一个转发,避免继承未知通道。
OpenSSH 可能在有效配置输出中省略值为 none 的 ControlPath。验证脚本把“未解析出 ControlPath”与 ControlMaster、ControlPersist 都已禁用结合判断。
不能。第二个连接通常会因地址已占用而失败,或者误用另一个客户端的生命周期。选择两个不同端口。
不要修改 codex-shell 的安全语义。临时需求应创建另一个明确命名、明确端口、可单独审计的 Host,而不是让维护入口变得含糊。
更多症状与检查顺序见 docs/troubleshooting.md。
回滚入口是 docs/rollback.md。核心原则是按阶段撤回新增内容:先停止让 VS Code 建立新连接,再移除 VS Code Server 专用环境块和新增别名;不要触碰仍在工作的 Desktop 会话。若已经迁移 Desktop,则在维护窗口中从精确备份恢复其 Host 块,并正常重连验证。
- 本教程根据一份私有三别名实践笔记重新组织、脱敏和独立撰写;私有实例附录、真实地址、账号和路径均未发布。
- 网络思路参考 sunshinerobot/codex-over-easytier,详见 ATTRIBUTION.md。
scripts/与examples/使用 MIT License。README.md、docs/与其他教程文字使用 CC BY 4.0。- 安全边界和报告方式见 SECURITY.md。
本教程不隶属于 OpenAI、Microsoft、Apple 或上游项目。产品行为可能随版本变化;涉及 Codex IDE 的当前能力,请以 OpenAI Codex IDE 官方文档 为准。