|
| 1 | +# Remote Control Server 私有化部署指南 |
| 2 | + |
| 3 | +本指南说明如何将 Remote Control Server (RCS) 部署到私有环境,并通过 Claude Code CLI 连接使用。 |
| 4 | + |
| 5 | +## 架构概览 |
| 6 | + |
| 7 | +``` |
| 8 | +┌──────────────────┐ ┌──────────────────────┐ |
| 9 | +│ Claude Code CLI │ ◄── HTTP/SSE/WS ─►│ Remote Control │ |
| 10 | +│ (Bridge Worker) │ 长轮询 + 心跳 │ Server (RCS) │ |
| 11 | +└──────────────────┘ │ │ |
| 12 | + │ ┌──────────────┐ │ |
| 13 | +┌──────────────────┐ HTTP/SSE │ │ In-Memory │ │ |
| 14 | +│ Web UI 控制面板 │ ◄─────────────── │ │ Store │ │ |
| 15 | +│ (/code/*) │ │ └──────────────┘ │ |
| 16 | +└──────────────────┘ │ ┌──────────────┐ │ |
| 17 | + │ │ JWT Auth │ │ |
| 18 | + │ └──────────────┘ │ |
| 19 | + └──────────────────────┘ |
| 20 | +``` |
| 21 | + |
| 22 | +**RCS 是一个纯内存的中间服务**,它的职责是: |
| 23 | +- 接收 Claude Code CLI 的环境注册和工作轮询 |
| 24 | +- 提供 Web UI 供操作者远程监控和审批 |
| 25 | +- 通过 WebSocket/SSE 双向传输消息 |
| 26 | +- 管理会话、环境、权限请求 |
| 27 | + |
| 28 | +## 前置条件 |
| 29 | + |
| 30 | +- 一台可被 Claude Code CLI 和 Web 浏览器同时访问的服务器(物理机、VM、容器均可) |
| 31 | +- [Docker](https://www.docker.com/) |
| 32 | +- 启用 `BRIDGE_MODE` feature flag 的 Claude Code 构建 |
| 33 | + |
| 34 | +## 部署 |
| 35 | + |
| 36 | +### 构建 Docker 镜像 |
| 37 | + |
| 38 | +在项目根目录执行: |
| 39 | + |
| 40 | +```bash |
| 41 | +docker build -t rcs:latest -f packages/remote-control-server/Dockerfile . |
| 42 | +``` |
| 43 | + |
| 44 | +### 启动容器 |
| 45 | + |
| 46 | +```bash |
| 47 | +docker run -d \ |
| 48 | + --name rcs \ |
| 49 | + -p 3000:3000 \ |
| 50 | + -e RCS_API_KEYS=sk-rcs-your-secret-key-here \ |
| 51 | + -e RCS_BASE_URL=https://rcs.example.com \ |
| 52 | + -v rcs-data:/app/data \ |
| 53 | + --restart unless-stopped \ |
| 54 | + rcs:latest |
| 55 | +``` |
| 56 | + |
| 57 | +### Docker Compose |
| 58 | + |
| 59 | +```yaml |
| 60 | +version: "3.8" |
| 61 | +services: |
| 62 | + rcs: |
| 63 | + build: |
| 64 | + context: . |
| 65 | + dockerfile: packages/remote-control-server/Dockerfile |
| 66 | + args: |
| 67 | + VERSION: "0.1.0" |
| 68 | + ports: |
| 69 | + - "3000:3000" |
| 70 | + environment: |
| 71 | + - RCS_API_KEYS=sk-rcs-your-secret-key-here |
| 72 | + - RCS_BASE_URL=https://rcs.example.com |
| 73 | + volumes: |
| 74 | + - rcs-data:/app/data |
| 75 | + restart: unless-stopped |
| 76 | + |
| 77 | +volumes: |
| 78 | + rcs-data: |
| 79 | +``` |
| 80 | +
|
| 81 | +启动: |
| 82 | +
|
| 83 | +```bash |
| 84 | +docker compose up -d |
| 85 | +``` |
| 86 | + |
| 87 | +## 环境变量参考 |
| 88 | + |
| 89 | +### 服务器端 |
| 90 | + |
| 91 | +| 变量 | 必填 | 默认值 | 说明 | |
| 92 | +|------|------|--------|------| |
| 93 | +| `RCS_API_KEYS` | **是** | _(空)_ | API 密钥列表,逗号分隔。用于客户端认证和 JWT 签名。**务必设置强密钥** | |
| 94 | +| `RCS_PORT` | 否 | `3000` | 服务监听端口 | |
| 95 | +| `RCS_HOST` | 否 | `0.0.0.0` | 服务监听地址 | |
| 96 | +| `RCS_BASE_URL` | 否 | `http://localhost:3000` | 外部访问 URL。用于生成 WebSocket 连接地址,必须与客户端实际访问的地址一致 | |
| 97 | +| `RCS_VERSION` | 否 | `0.1.0` | 版本号,显示在 `/health` 响应中 | |
| 98 | +| `RCS_POLL_TIMEOUT` | 否 | `8` | V1 工作轮询超时(秒) | |
| 99 | +| `RCS_HEARTBEAT_INTERVAL` | 否 | `20` | 心跳间隔(秒) | |
| 100 | +| `RCS_JWT_EXPIRES_IN` | 否 | `3600` | JWT 令牌有效期(秒) | |
| 101 | +| `RCS_DISCONNECT_TIMEOUT` | 否 | `300` | 断线判定超时(秒) | |
| 102 | + |
| 103 | +### 客户端(Claude Code CLI) |
| 104 | + |
| 105 | +| 变量 | 必填 | 说明 | |
| 106 | +|------|------|------| |
| 107 | +| `CLAUDE_BRIDGE_BASE_URL` | **是** | RCS 服务器地址,例如 `https://rcs.example.com`。设置此变量即启用自托管模式,跳过 GrowthBook 门控 | |
| 108 | +| `CLAUDE_BRIDGE_OAUTH_TOKEN` | **是** | 认证令牌,必须与服务器端 `RCS_API_KEYS` 中的某个值匹配 | |
| 109 | +| `CLAUDE_BRIDGE_SESSION_INGRESS_URL` | 否 | WebSocket 入口地址(默认与 `CLAUDE_BRIDGE_BASE_URL` 相同) | |
| 110 | +| `CLAUDE_CODE_REMOTE` | 否 | 设为 `1` 时标记为远程执行模式 | |
| 111 | + |
| 112 | +## Claude Code 客户端连接 |
| 113 | + |
| 114 | +### 1. 设置环境变量 |
| 115 | + |
| 116 | +在运行 Claude Code 的机器上设置: |
| 117 | + |
| 118 | +```bash |
| 119 | +export CLAUDE_BRIDGE_BASE_URL="https://rcs.example.com" |
| 120 | +export CLAUDE_BRIDGE_OAUTH_TOKEN="sk-rcs-your-secret-key-here" |
| 121 | +``` |
| 122 | + |
| 123 | +### 2. 启动 Claude Code |
| 124 | + |
| 125 | +```bash |
| 126 | +# 使用 dev 模式(BRIDGE_MODE 默认启用) |
| 127 | +bun run dev |
| 128 | + |
| 129 | +# 或使用构建产物 |
| 130 | +bun run dist/cli.js |
| 131 | +``` |
| 132 | + |
| 133 | +### 3. 执行 /remote-control 命令 |
| 134 | + |
| 135 | +在 Claude Code 的 REPL 中输入: |
| 136 | + |
| 137 | +``` |
| 138 | +/remote-control |
| 139 | +``` |
| 140 | + |
| 141 | +CLI 会向 RCS 注册环境,注册成功后在终端显示连接 URL: |
| 142 | + |
| 143 | +``` |
| 144 | +https://rcs.example.com/code?bridge=<environmentId> |
| 145 | +``` |
| 146 | + |
| 147 | +同时支持 QR 码扫码打开。该 URL 即 Web UI 控制面板入口,在浏览器中打开即可远程操控当前会话。 |
| 148 | + |
| 149 | +若已连接,再次执行 `/remote-control` 会显示对话框,包含以下选项: |
| 150 | +- **Disconnect this session** — 断开远程连接 |
| 151 | +- **Show QR code** — 显示/隐藏二维码 |
| 152 | +- **Continue** — 保持连接,继续使用 |
| 153 | + |
| 154 | +也可通过 CLI 参数直接启动: |
| 155 | + |
| 156 | +```bash |
| 157 | +claude remote-control |
| 158 | +# 或简写 |
| 159 | +claude rc |
| 160 | +# 或 |
| 161 | +claude bridge |
| 162 | +``` |
| 163 | + |
| 164 | +## Web UI 控制面板 |
| 165 | + |
| 166 | +通过 `/remote-control` 命令获取 URL 后,在浏览器打开即可使用。功能: |
| 167 | + |
| 168 | +- 查看已注册的运行环境 |
| 169 | +- 创建和管理会话 |
| 170 | +- 实时查看对话消息和工具调用 |
| 171 | +- 审批 Claude Code 的工具权限请求 |
| 172 | + |
| 173 | +Web UI 使用 UUID 认证(无需用户账户),适合受信任网络环境。 |
| 174 | + |
| 175 | +## 工作流程详解 |
| 176 | + |
| 177 | +``` |
| 178 | +┌──────────────────────────────────────────────────────────┐ |
| 179 | +│ 完整工作流程 │ |
| 180 | +└──────────────────────────────────────────────────────────┘ |
| 181 | +
|
| 182 | + 1. Claude Code CLI 启动,设置环境变量指向自托管 RCS |
| 183 | +
|
| 184 | + 2. 用户执行 /remote-control 命令 |
| 185 | +
|
| 186 | + 3. 注册环境 |
| 187 | + CLI ──POST /v1/environments/bridge──► RCS |
| 188 | + CLI ◄── { environment_id, environment_secret } ── RCS |
| 189 | +
|
| 190 | + 4. 终端显示连接 URL |
| 191 | + https://rcs.example.com/code?bridge=<environmentId> |
| 192 | +
|
| 193 | + 5. 开始工作轮询(循环) |
| 194 | + CLI ──GET /v1/environments/:id/work/poll──► RCS |
| 195 | + (长轮询,等待任务分配,超时 8 秒后重试) |
| 196 | +
|
| 197 | + 6. 浏览器打开 URL → Web UI 创建任务 |
| 198 | + Browser ──POST /web/sessions──► RCS |
| 199 | + RCS 分配 work 给正在轮询的 CLI |
| 200 | +
|
| 201 | + 7. CLI 收到任务并确认 |
| 202 | + CLI ◄── { id, data: { type, sessionId } } ── RCS |
| 203 | + CLI ──POST /v1/environments/:id/work/:workId/ack──► RCS |
| 204 | +
|
| 205 | + 8. 建立会话连接 |
| 206 | + CLI ──WebSocket /v1/session_ingress──► RCS |
| 207 | + (或使用 V2 的 SSE + HTTP POST) |
| 208 | +
|
| 209 | + 9. 双向通信 |
| 210 | + CLI ──消息/工具调用结果──► RCS ──► Browser |
| 211 | + CLI ◄──权限审批/指令───── RCS ◄──── Browser |
| 212 | +
|
| 213 | +10. 心跳保活(每 20 秒) |
| 214 | + CLI ──POST /v1/environments/:id/work/:workId/heartbeat──► RCS |
| 215 | +
|
| 216 | +11. 任务完成 → 归档会话 → 注销环境 |
| 217 | +``` |
| 218 | + |
| 219 | +## 故障排查 |
| 220 | + |
| 221 | +### CLI 无法连接 |
| 222 | + |
| 223 | +``` |
| 224 | +Error: Remote Control is not available in this build. |
| 225 | +``` |
| 226 | + |
| 227 | +**原因**:`BRIDGE_MODE` feature flag 未启用。 |
| 228 | + |
| 229 | +**解决**:使用 dev 模式(默认启用)或确保构建时包含 `BRIDGE_MODE` flag。 |
| 230 | + |
| 231 | +### 认证失败 (401) |
| 232 | + |
| 233 | +``` |
| 234 | +Error: Unauthorized |
| 235 | +``` |
| 236 | + |
| 237 | +**检查项**: |
| 238 | +1. `CLAUDE_BRIDGE_OAUTH_TOKEN` 是否与 `RCS_API_KEYS` 中的值匹配 |
| 239 | +2. API Key 是否包含多余的空格或换行 |
| 240 | +3. 两个环境变量是否都已正确设置 |
| 241 | + |
| 242 | +### WebSocket 连接中断 |
| 243 | + |
| 244 | +**检查项**: |
| 245 | +1. 如果使用反向代理,确认已正确配置 WebSocket 升级(`Upgrade` / `Connection` 头) |
| 246 | +2. 代理的 `proxy_read_timeout` 是否足够大(建议 86400 秒) |
| 247 | +3. 网络防火墙是否允许 WebSocket 流量 |
| 248 | + |
| 249 | +### 健康检查 |
| 250 | + |
| 251 | +```bash |
| 252 | +curl https://rcs.example.com/health |
| 253 | +# 预期: {"status":"ok","version":"0.1.0"} |
| 254 | +``` |
| 255 | + |
| 256 | +## 限制与注意事项 |
| 257 | + |
| 258 | +| 项目 | 说明 | |
| 259 | +|------|------| |
| 260 | +| 存储 | 纯内存存储(Map),服务器重启后所有会话和环境数据丢失 | |
| 261 | +| 扩展 | 不支持水平扩展(无共享状态),单实例部署 | |
| 262 | +| 并发 | 适合中小规模使用,大量并发会话可能需要性能调优 | |
| 263 | +| 数据持久化 | `/app/data` 卷已预留但当前未使用,未来可能用于持久化 | |
| 264 | +| Web UI 认证 | 基于 UUID,无用户账户系统,适合受信任网络环境 | |
| 265 | + |
| 266 | +## 与云端模式对比 |
| 267 | + |
| 268 | +| 特性 | 云端 (Anthropic CCR) | 自托管 (RCS) | |
| 269 | +|------|---------------------|--------------| |
| 270 | +| 认证方式 | claude.ai OAuth 订阅 | API Key | |
| 271 | +| GrowthBook 门控 | 需要 `tengu_ccr_bridge` 通过 | 自动跳过 | |
| 272 | +| 功能标志 | 需要 `BRIDGE_MODE=1` | 同样需要 | |
| 273 | +| 部署位置 | Anthropic 云端 | 用户自有服务器 | |
| 274 | +| 数据流经 | Anthropic 基础设施 | 用户私有网络 | |
| 275 | +| 依赖 | claude.ai 订阅 + OAuth | 仅需 API Key | |
| 276 | + |
| 277 | +自托管模式的核心优势是:设置 `CLAUDE_BRIDGE_BASE_URL` 后,代码自动调用 `isSelfHostedBridge()` 返回 `true`,跳过所有 GrowthBook 和订阅检查,无需 claude.ai 账户即可使用。 |
| 278 | + |
0 commit comments