---
title: Codex 远程使用指南：把开发环境留在办公室
slug: codex-remote-server-lan-wss
date: 2026-10-30
author: Frankie 徐
category: ai
tags: ['codex', 'remote-development', 'app-server', 'websocket', 'tls', 'tailscale']
description: 把 Codex app-server 和开发环境放在办公室 Mac，通过 CLI 远程连接，梳理 WSS、证书、Token、项目目录、会话恢复和断网行为，并说明外网组网的配置边界。
permalink: https://www.210k.cc/codex-remote-server-lan-wss
---

如果代码、依赖和开发环境已经放在办公室的一台 Mac 上，换到另一台 MacBook 时，能不能继续让那台电脑干活，自己只负责输入指令、看结果和处理审批？

Codex CLI 的远程终端模式可以这样使用：在办公室主机上运行 `codex app-server`，客户端通过网络连接。文件操作、命令执行和模型请求都留在主机，客户端提供交互界面。

我已经跑通了局域网连接，也做过一次客户端断线后任务继续执行的验证。外网访问还没有部署，本文后半部分介绍的是可采用的组网路径。

> 本文整理于 2026 年 10 月 30 日。原始实测使用服务端 Codex 0.166.0、客户端 0.162.1；WebSocket app-server 在官方文档中仍标记为实验性、未受支持的接口。下面保留实测版本的经验，升级后需重新核对参数和行为。地址、口令及私有路径均已改为示例。

## 代码和任务究竟在哪台电脑上

这里把办公室实际运行 Codex 的 Mac 称为 Server，另一台输入指令的电脑称为客户端。

| 内容 | 所在位置或执行方 |
|---|---|
| 项目文件、依赖、测试、Git 操作 | Server |
| Shell 命令和工具调用 | Server |
| 模型请求 | 由 Server 发出，推理由所配置的模型提供方完成 |
| 输入指令、查看输出、处理审批 | 客户端 |
| 会话历史 | Server 使用的 Codex 用户目录 |

客户端当前所在目录不会自动上传或同步到 Server。在客户端发出创建文件的指令，文件也会写入远端会话的工作目录。

连接后，可以先发一条只读指令确认环境：

```text
执行 hostname、whoami 和 pwd，只读检查，不修改文件。
```

服务启动时的默认目录，与某个会话保存的工作目录也可以不同。判断文件写到哪里，应以当前会话实际返回的 `pwd` 为准。

## 先理解 WSS 入口和 app-server 的关系

本次测试使用两个独立进程，连接关系如下：

```text
客户端 Codex CLI
    │ WSS：加密连接
    ▼
Server 的 TLS 入口（端口 4500）
    │ WS：只走本机 127.0.0.1:4501
    ▼
Codex app-server
    │ 原生 Token 校验、模型请求、文件和命令执行
    ▼
Server 上的项目
```

TLS 入口负责加密，连接 Token 仍由 app-server 原生校验。这两个测试进程没有替换原先使用中的 Codex 后台服务。

**TLS 入口是额外的部署前提。** app-server 的 WebSocket 监听参数使用 `ws://`；客户端要连接 `wss://`，需要由反向代理或独立 TLS 入口完成加密。只把客户端地址中的 `ws` 改成 `wss`，不会让明文端口自动支持 TLS。

带 Token 连接非本机地址时，CLI 要求使用 WSS。明文 WS 只适合本机或 SSH 端口转发等场景。下面以 `wss://codex.example.com:4500` 作为占位地址，实际使用时需要替换为可达、且与服务证书匹配的名称或 IP。

## 在客户端准备证书和连接 Token

先检查客户端版本和支持的参数：

```bash
codex --version
codex --help
```

需要支持 `--remote` 和 `--remote-auth-token-env`。本文的客户端连接已在 0.162.1 上验证。

### 私有 CA 要先核对，再信任

如果 TLS 入口使用公开受信任机构签发的有效证书，通常无需额外配置私有 CA。下面的证书步骤针对本次使用私有 CA 的测试方式。

让 Server 管理员通过可信渠道提供公开 CA 证书和 SHA-256 指纹。证书放到固定目录，可以避免重启或清理临时目录后丢失：

```bash
mkdir -p "$HOME/.config/codex-lan"
```

本次 TLS 入口还提供了 `/ca.pem` 下载地址。**这是测试入口自己的约定，不是 app-server 内置的证书下载接口。** 如果你的入口也提供该文件，可以这样取回并核对：

```bash
CODEX_SERVER_HOST='codex.example.com'
CODEX_CA_SHA256='替换为通过独立可信渠道取得的64位SHA-256值'

curl --noproxy '*' -kfsS \
  "https://${CODEX_SERVER_HOST}:4500/ca.pem" \
  -o "$HOME/.config/codex-lan/ca.pem"

printf '%s  %s\n' \
  "$CODEX_CA_SHA256" \
  "$HOME/.config/codex-lan/ca.pem" \
  | shasum -a 256 -c -
```

只有校验显示 `ca.pem: OK` 才继续。`-k` 只用于首次取回公开证书，真实性依靠事先从独立可信渠道收到的指纹；从同一个未验证的下载地址再拿一份指纹，没有建立额外的信任。

后面的 Codex 连接仍正常校验证书。这个测试方式不需要把 CA 安装进系统钥匙串，也不需要把 CA 私钥或服务端私钥复制给客户端。

### 连接 Token 与模型登录是两回事

Server 的连接 Token 是访问这台 app-server 的凭据，不是模型 API Key，也不是 ChatGPT 密码。它应是专门分配的高强度随机值，不应复用模型服务凭据。

下文假设管理员已通过可信渠道提供 Token，并将其保存到客户端的以下文件中：

```text
~/.config/codex-lan/remote-token
```

该文件只保存 Token 本身，限制读取权限，并放在版本控制之外：

```bash
chmod 600 "$HOME/.config/codex-lan/remote-token"
```

示例会从文件读入命令环境变量，不把真实 Token 写进文章或命令参数。

## 连接远程主机并指定项目

完成地址、TLS、证书和 Token 准备后，在客户端执行：

```bash
CODEX_REMOTE_TOKEN="$(cat "$HOME/.config/codex-lan/remote-token")" \
CODEX_CA_CERTIFICATE="$HOME/.config/codex-lan/ca.pem" \
SSL_CERT_FILE="$HOME/.config/codex-lan/ca.pem" \
codex --remote wss://codex.example.com:4500 \
  --remote-auth-token-env CODEX_REMOTE_TOKEN
```

原始 0.162.1 测试中，仅设置 `CODEX_CA_CERTIFICATE` 仍遇到 `UnknownIssuer`，同时设置 `SSL_CERT_FILE` 后连接成功，因此这里保留两项设置，并指向同一份 CA 文件。当前官方文档说明前者优先于后者；这条实测经验不代表所有版本都必须同时设置。上述环境变量只作用于当前命令。

如果要为新会话指定项目，在命令中加 `-C`，传入 **Server 上的绝对路径**：

```bash
CODEX_REMOTE_TOKEN="$(cat "$HOME/.config/codex-lan/remote-token")" \
CODEX_CA_CERTIFICATE="$HOME/.config/codex-lan/ca.pem" \
SSL_CERT_FILE="$HOME/.config/codex-lan/ca.pem" \
codex --remote wss://codex.example.com:4500 \
  --remote-auth-token-env CODEX_REMOTE_TOKEN \
  -C /absolute/path/on/server/my-project
```

这个目录需要提前存在于 Server。客户端上有同名文件夹，不意味着远端也有这份代码；恢复已有会话时，还要留意是否沿用了该会话保存的目录。

开发服务器也运行在远端。如果它只监听 Server 的 `127.0.0.1`，客户端浏览器无法直接打开。预览页面需要另外配置端口转发或合适的监听方式，Codex 连接成功并不意味着项目的所有端口都能远程访问。

## 退出后，怎样恢复远程会话

会话历史保存在 Server 的 Codex 用户目录中，正常保存的历史不会因客户端退出而删除。恢复时仍然要带上远程地址和鉴权参数：

```bash
CODEX_REMOTE_TOKEN="$(cat "$HOME/.config/codex-lan/remote-token")" \
CODEX_CA_CERTIFICATE="$HOME/.config/codex-lan/ca.pem" \
SSL_CERT_FILE="$HOME/.config/codex-lan/ca.pem" \
codex resume --all \
  --remote wss://codex.example.com:4500 \
  --remote-auth-token-env CODEX_REMOTE_TOKEN
```

用方向键选择会话，再按回车恢复。`--all` 用于显示所有目录的候选会话，避免因为目录过滤找不到目标。如果询问使用哪个目录，应根据需要选择原会话目录。

也可以先在原会话中用 `/status` 记下 Session ID，之后把 `resume --all` 换成 `resume SESSION_ID`，直接恢复指定会话。

不要省略远程地址，只在客户端执行 `codex resume`，否则可能打开客户端本地的历史。多个项目共用一台 Server 时，也不宜只凭 `--last` 猜测要恢复哪个会话。

## 客户端断网，任务还会继续吗

需要区分“客户端暂时看不到输出”和“远端任务已经被中断”。

如果请求已被 Server 接收，只是客户端与 Server 之间的网络断开，而 Server 仍然醒着、进程正常且能访问模型服务，任务可以继续运行。

原始实验做过一次实际验证：Server 执行一个等待 45 秒的命令；执行途中直接断开客户端 TCP 连接，没有发送停止指令。断线后，第一条命令完成，Codex 还发起并完成了第二次独立工具调用，最终该轮状态为 `completed`。该实验使用服务端 0.166.0。

这证明了本次纯连接断开场景中的继续执行能力，不能扩大为任意故障下都保证完成：

| 情况 | 应怎样理解 |
|---|---|
| 客户端断网，Server 正常 | 已接收的任务可继续；本次已验证后续工具调用也能完成 |
| 请求尚未送达 Server 就断网 | 任务可能尚未启动，需要重连检查 |
| 等待审批、提问或客户端动态工具结果 | 可能等待或失败，不能保证无人值守完成 |
| 主动发送停止指令或 `turn/interrupt` | 会请求中断当前任务 |
| 按 Ctrl+C 或正常退出客户端 | 可能发送中断或退订，不能当作本次验证过的纯断网 |
| Server 睡眠、关机或 Codex 进程退出 | 不能继续正常执行；历史存在不等于任务自动恢复 |
| 模型网络、额度、凭据或工具执行出错 | 仍可能让任务失败，WSS 和 VPN 无法替代这些依赖 |

重连后，先恢复原会话，检查任务状态、工具输出和文件结果。如果仍在运行，就继续观察；如果已经失败，再从完成的位置继续。尤其是部署、上传或写入外部系统，不要在未确认状态前直接重复发送原任务。

必须持续运行并保留输出的构建、下载等任务，可以在 Server 中用 tmux 或任务管理工具执行并保存日志。但它们不会替 Codex 回答审批，也不能抵御 Server 关机。

## 在办公室以外，怎样访问同一台 Server

优先考虑 VPN 或 Tailscale 这类私有组网。OpenAI 官方也建议用 VPN 或组网工具连接远端，而不是把 app-server 直接暴露到互联网。

这部分尚未在本环境部署，下面是两种可选路径。

### 沿用办公室局域网地址

如果希望保留原来的局域网连接地址，可以使用 Tailscale 子网路由：

1. 在办公室的常开设备与外出 MacBook 上安装并接入同一个私有网络。
2. 配置办公室设备发布所需的主机路由或实际网段。
3. 在管理端批准路由，并用访问规则限制允许访问的设备和端口。
4. 确认客户端能经过该路由访问 TLS 入口。
5. 继续使用对应地址、证书和远程恢复命令。

仅仅在两端安装 Tailscale，不会自动让办公室原有内网地址可达。路由需要配置和批准；外出网络若使用重叠网段，还要检查路由冲突。

### 改用主机的私有组网地址或名称

也可以直接连接办公室主机的 Tailscale 地址或名称，减少对原局域网路由的依赖。

这时要相应调整 TLS 入口监听范围，并为新的名称或 IP 签发匹配的服务证书。不能只改客户端地址，就假定原证书对新地址仍然有效。

如果使用桌面 App，官方还提供在 Connections 设置中添加 SSH 主机、选择远程项目的路径。它与本文的原生 CLI WSS 连接不同；本文没有验证桌面 App 能直接填写这里的 WSS 地址。具体入口和可用性以 App 版本及账号开放情况为准。

## Server 端需要预先准备什么

办公室主机需要接通电源、保持清醒，并保持网络及模型服务可用。显示器可以熄屏，但主机睡眠会影响执行；笔记本合盖也可能进入睡眠。切换网络后，要重新确认地址、监听范围和证书匹配关系。

原始测试使用手动启动的后台进程，没有配置开机自启。重启后需要重新启动服务，历史记录不会让未完成的任务自动续跑。

以下是 app-server 的服务端命令形态。**它假设 Codex 已安装并完成模型鉴权，专用 Token 文件已准备好，TLS 入口也已另行配置；不包含证书签发和 TLS 代理的完整部署脚本。**

先在 Server 上检查端口归属，避免重复启动或干扰其他会话：

```bash
lsof -nP -iTCP:4500 -iTCP:4501 -sTCP:LISTEN
```

确认测试服务已经停止、端口空闲后，才启动一个新的 app-server：

```bash
codex app-server \
  --listen ws://127.0.0.1:4501 \
  --ws-auth capability-token \
  --ws-token-file "$HOME/.config/codex-server/remote-token"
```

这里的 `$HOME` 属于 Server。服务端文件中的 Token 应与发给客户端的连接 Token 一致；它与 Server 访问模型所使用的凭据分开管理。

TLS 入口应把已授权客户端的加密连接转发到这个本机端口，后端 app-server 自己执行 Token 检查。长期使用时还要安排进程托管、开机启动、日志和证书续签，并限制网络访问范围。

证书有效期应从实际部署的证书中读取。例如，在 Server 上执行以下命令，查看你保存的服务证书到期时间：

```bash
openssl x509 -in /path/to/server.pem -noout -enddate
```

公开 CA 证书可以交给客户端，CA 私钥、服务端私钥和模型凭据留在 Server。CA 更换后，客户端也要重新取得并核对公开证书。

## 常见错误怎么查

| 错误或现象 | 检查方向 |
|---|---|
| 提示远程鉴权只允许 WSS 或 loopback WS | 非本机带 Token 连接使用 WSS，确认不是明文入口 |
| `InvalidContentType` 或 `received corrupt message` | 检查是否把 WSS 连到了明文 WS 端口 |
| `UnknownIssuer` | 检查 CA 路径；参考上文实测版本的两个证书环境变量设置 |
| 证书名称或 IP 不匹配 | 连接地址必须包含在服务证书中，换地址后要更新证书 |
| 证书过期 | 服务端续签；CA 变化时，客户端重新获取并核对 |
| `401 Unauthorized` | 检查 Token 文件、环境变量名称和两端值是否一致 |
| 连接被拒绝或超时 | 检查主机状态、进程、地址、防火墙与 VPN 路由 |
| 恢复列表找不到会话 | 带上远程地址，使用 `resume --all`，确认 Server 的 Codex 用户环境一致 |

远程使用最关键的是执行位置和状态：代码属于哪台主机、会话保存在哪里、TLS 与 Token 是否正确配置、断线后任务到底完成到哪一步。把这些边界分清，换设备时才能继续使用同一份开发环境。

## 参考资料

- [OpenAI：CLI 连接远程 app-server](https://learn.chatgpt.com/docs/app-server#connect-the-cli-terminal-ui)
- [OpenAI：传输协议和鉴权](https://learn.chatgpt.com/docs/app-server#protocol)
- [OpenAI：证书环境变量](https://learn.chatgpt.com/docs/config-file/environment-variables#authentication-and-network)
- [OpenAI：恢复会话](https://learn.chatgpt.com/docs/developer-commands#codex-resume)
- [OpenAI：远程连接和网络暴露](https://learn.chatgpt.com/docs/remote-connections#authentication-and-network-exposure)
- [OpenAI：桌面 App 连接 SSH 主机](https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host)
- [Tailscale：子网路由](https://tailscale.com/kb/1019/subnets)