Skip to content

Commit 2da6514

Browse files
claude-code-bestclaudegithub-advanced-security[bot]
authored
feat: 支持自托管的 remote-control-server (#214)
* feat: 支持自托管的 remote-control-server (#214) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent f17b7c7 commit 2da6514

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+9875
-40
lines changed

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
dist
3+
.git
4+
.githooks
5+
.github
6+
docs
7+
*.md
8+
packages/remote-control-server/data/*.db
9+
packages/remote-control-server/data/*.db-wal
10+
packages/remote-control-server/data/*.db-shm
11+
.claude

.github/workflows/release-rcs.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: Release RCS Docker Image
2+
3+
on:
4+
push:
5+
tags:
6+
- 'rcs-v*'
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository_owner }}/remote-control-server
11+
12+
jobs:
13+
build-and-push:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Login to GHCR
23+
uses: docker/login-action@v3
24+
with:
25+
registry: ${{ env.REGISTRY }}
26+
username: ${{ github.actor }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Extract version
33+
id: version
34+
run: echo "VERSION=${GITHUB_REF_NAME#rcs-v}" >> "$GITHUB_OUTPUT"
35+
36+
- name: Generate tags
37+
id: tags
38+
run: |
39+
VERSION="${{ steps.version.outputs.VERSION }}"
40+
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
41+
TAGS="${IMAGE}:${VERSION}"
42+
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
43+
if [ -n "$MAJOR" ] && [ -n "$MINOR" ]; then
44+
TAGS="${TAGS},${IMAGE}:${MAJOR}.${MINOR}"
45+
fi
46+
TAGS="${TAGS},${IMAGE}:latest"
47+
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
48+
49+
- name: Build Docker image
50+
uses: docker/build-push-action@v5
51+
with:
52+
context: .
53+
file: packages/remote-control-server/Dockerfile
54+
push: false
55+
load: true
56+
tags: ${{ steps.tags.outputs.tags }}
57+
build-args: VERSION=${{ steps.version.outputs.VERSION }}
58+
cache-from: type=gha
59+
cache-to: type=gha,mode=max
60+
61+
- name: Verify image
62+
run: |
63+
IMAGE_TAG=$(echo "${{ steps.tags.outputs.tags }}" | cut -d',' -f1)
64+
docker run -d --name rcs-test -p 3000:3000 "$IMAGE_TAG"
65+
sleep 5
66+
curl -sf http://localhost:3000/health || { docker logs rcs-test; exit 1; }
67+
docker stop rcs-test
68+
docker rm rcs-test
69+
70+
- name: Push Docker image
71+
run: |
72+
IFS=',' read -ra TAGS <<< "${{ steps.tags.outputs.tags }}"
73+
for TAG in "${TAGS[@]}"; do
74+
docker push "$TAG"
75+
done

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ src/utils/vendor/
2727
__pycache__/
2828
*.pyc
2929
logs
30+
31+
data

bun.lock

Lines changed: 321 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
"check:unused": "knip-bun",
5151
"health": "bun run scripts/health-check.ts",
5252
"postinstall": "node scripts/postinstall.cjs",
53-
"docs:dev": "npx mintlify dev"
53+
"docs:dev": "npx mintlify dev",
54+
"rcs": "bun run scripts/rcs.ts"
5455
},
5556
"dependencies": {},
5657
"devDependencies": {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# ---- Stage 1: Install deps + build ----
2+
FROM oven/bun:1 AS builder
3+
WORKDIR /app
4+
5+
ARG VERSION=0.1.0
6+
7+
COPY packages/remote-control-server/package.json ./package.json
8+
RUN bun install
9+
10+
COPY packages/remote-control-server/src ./src
11+
RUN bun build src/index.ts --outfile=dist/server.js --target=bun \
12+
--define "process.env.RCS_VERSION=\"${VERSION}\""
13+
14+
# ---- Stage 2: Runtime ----
15+
FROM oven/bun:1-slim AS runtime
16+
17+
ARG VERSION=0.1.0
18+
ENV RCS_VERSION=${VERSION}
19+
20+
WORKDIR /app
21+
22+
COPY --from=builder /app/dist/server.js ./dist/server.js
23+
COPY packages/remote-control-server/web ./web
24+
25+
VOLUME /app/data
26+
27+
EXPOSE 3000
28+
29+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
30+
CMD bun run -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
31+
32+
CMD ["bun", "run", "dist/server.js"]
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Remote Control Server (RCS)
2+
3+
Remote Control Server 是 Claude Code 的远程控制后端,允许你通过浏览器 Web UI 远程监控和操作 Claude Code 会话。
4+
5+
## 功能
6+
7+
- **会话管理** — 创建、监控、归档 Claude Code 会话
8+
- **实时消息流** — WebSocket / SSE 双向传输,实时查看对话和工具调用
9+
- **权限审批** — 在 Web UI 中审批 Claude Code 的工具权限请求
10+
- **多环境管理** — 注册多个运行环境,支持心跳和断线重连
11+
- **认证安全** — API Key + JWT 双层认证
12+
13+
## 快速开始
14+
15+
### Docker 部署(推荐)
16+
17+
```bash
18+
docker run -d \
19+
--name rcs \
20+
-p 3000:3000 \
21+
-e RCS_API_KEYS=your-api-key-here \
22+
-v rcs-data:/app/data \
23+
ghcr.io/claude-code-best/remote-control-server:latest
24+
```
25+
26+
## 环境变量
27+
28+
### 服务器配置
29+
30+
| 变量 | 默认值 | 说明 |
31+
|------|--------|------|
32+
| `RCS_PORT` | `3000` | 监听端口 |
33+
| `RCS_HOST` | `0.0.0.0` | 监听地址 |
34+
| `RCS_API_KEYS` | _(空)_ | API 密钥列表,逗号分隔。客户端和 Worker 连接时需要提供 |
35+
| `RCS_BASE_URL` | _(自动)_ | 外部访问地址,例如 `https://rcs.example.com`。用于生成 WebSocket 连接 URL |
36+
| `RCS_VERSION` | `0.1.0` | 服务版本号,显示在 `/health` 响应中 |
37+
38+
### 超时与心跳
39+
40+
| 变量 | 默认值 | 说明 |
41+
|------|--------|------|
42+
| `RCS_POLL_TIMEOUT` | `8` | V1 轮询超时(秒) |
43+
| `RCS_HEARTBEAT_INTERVAL` | `20` | 心跳间隔(秒) |
44+
| `RCS_JWT_EXPIRES_IN` | `3600` | JWT 令牌有效期(秒) |
45+
| `RCS_DISCONNECT_TIMEOUT` | `300` | 断线判定超时(秒) |
46+
47+
## Claude Code 客户端配置
48+
49+
### 连接到自托管服务器
50+
51+
在 Claude Code 所在环境设置以下变量:
52+
53+
```bash
54+
# 指向你的 RCS 服务器地址
55+
export CLAUDE_BRIDGE_BASE_URL="https://rcs.example.com"
56+
57+
# 认证令牌(与 RCS_API_KEYS 中的值对应)
58+
export CLAUDE_BRIDGE_OAUTH_TOKEN="your-api-key-here"
59+
```
60+
61+
然后启动远程控制模式:
62+
63+
```bash
64+
ccb --remote-control
65+
```
66+
67+
> **注意**:远程控制功能需要启用 `BRIDGE_MODE` feature flag。开发模式下默认启用。
68+
69+
### 环境变量参考
70+
71+
| 变量 | 说明 |
72+
|------|------|
73+
| `CLAUDE_BRIDGE_BASE_URL` | RCS 服务器地址,覆盖默认的 Anthropic 云端地址 |
74+
| `CLAUDE_BRIDGE_OAUTH_TOKEN` | 认证令牌,用于连接 RCS 服务器 |
75+
| `CLAUDE_BRIDGE_SESSION_INGRESS_URL` | WebSocket 入口地址(默认与 BASE_URL 相同) |
76+
| `CLAUDE_CODE_REMOTE` | 设为 `1` 时标记为远程执行模式 |
77+
78+
## Docker Compose 示例
79+
80+
```yaml
81+
version: "3.8"
82+
services:
83+
rcs:
84+
build:
85+
context: .
86+
dockerfile: packages/remote-control-server/Dockerfile
87+
args:
88+
VERSION: "0.1.0"
89+
ports:
90+
- "3000:3000"
91+
environment:
92+
- RCS_API_KEYS=sk-rcs-change-me
93+
- RCS_BASE_URL=https://rcs.example.com
94+
volumes:
95+
- rcs-data:/app/data
96+
restart: unless-stopped
97+
98+
volumes:
99+
rcs-data:
100+
```
101+
102+
## 反向代理配置
103+
104+
使用 Nginx 或 Caddy 反向代理时,需要支持 WebSocket 升级:
105+
106+
```nginx
107+
server {
108+
listen 443 ssl;
109+
server_name rcs.example.com;
110+
111+
location / {
112+
proxy_pass http://127.0.0.1:3000;
113+
proxy_http_version 1.1;
114+
proxy_set_header Upgrade $http_upgrade;
115+
proxy_set_header Connection "upgrade";
116+
proxy_set_header Host $host;
117+
proxy_set_header X-Real-IP $remote_addr;
118+
proxy_read_timeout 86400s;
119+
}
120+
}
121+
```
122+
123+
Caddy 配置更简单,自动处理 WebSocket:
124+
125+
```
126+
rcs.example.com {
127+
reverse_proxy localhost:3000
128+
}
129+
```
130+
131+
## 架构概览
132+
133+
```
134+
┌─────────────┐ WebSocket/SSE ┌──────────────────┐
135+
│ Claude Code │ ◄──────────────────► │ Remote Control │
136+
│ (Bridge CLI)│ HTTP API │ Server │
137+
└─────────────┘ │ │
138+
│ ┌────────────┐ │
139+
┌─────────────┐ HTTP/SSE │ │ Event Bus │ │
140+
│ Web UI │ ◄────────────────── │ └────────────┘ │
141+
│ (/code/*) │ │ ┌────────────┐ │
142+
└─────────────┘ │ │ In-Memory │ │
143+
│ │ Store │ │
144+
│ └────────────┘ │
145+
└──────────────────┘
146+
```
147+
148+
- **传输层**:WebSocket(V1)和 SSE + HTTP POST(V2)
149+
- **存储**:纯内存存储(Map),重启后数据清除
150+
- **认证**:API Key(客户端)+ JWT(Worker)
151+
- **前端**:原生 JS SPA,通过 `/code/*` 路径访问
152+
153+
## 开发
154+
155+
```bash
156+
# 安装依赖
157+
bun install
158+
159+
# 开发模式(热重载)
160+
bun run dev
161+
162+
# 类型检查
163+
bun run typecheck
164+
165+
# 运行测试
166+
bun test packages/remote-control-server/
167+
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "@anthropic/remote-control-server",
3+
"version": "0.1.0",
4+
"type": "module",
5+
"scripts": {
6+
"dev": "bun run --watch src/index.ts",
7+
"start": "bun run src/index.ts",
8+
"build:web": "cd web && bun run build",
9+
"typecheck": "tsc --noEmit"
10+
},
11+
"dependencies": {
12+
"hono": "^4.7.0",
13+
"uuid": "^11.0.0"
14+
},
15+
"devDependencies": {
16+
"@types/uuid": "^10.0.0",
17+
"typescript": "^5.7.0",
18+
"vite": "^6.0.0",
19+
"@vitejs/plugin-react": "^4.0.0",
20+
"react": "^19.0.0",
21+
"react-dom": "^19.0.0",
22+
"@types/react": "^19.0.0",
23+
"@types/react-dom": "^19.0.0",
24+
"tailwindcss": "^4.0.0",
25+
"@tailwindcss/vite": "^4.0.0"
26+
}
27+
}

0 commit comments

Comments
 (0)