Private Cloud 部署
Private Cloud 适合把一组团队任务放到你们自己的服务器或虚拟机上执行。团队成员在 Agentrix Web 应用里创建任务,任务会被派发到这组 runner;代码仓库、系统依赖和本地凭据都留在你们管理的环境里。
适用场景
- 团队想共用一组稳定的 Linux runner,而不是依赖每个人的开发机。
- 仓库、内网依赖、构建工具或模型网关只能在公司网络里访问。
- 需要给团队成员开放任务入口,但不想把 runner secret 分发给每个人。
- 需要多台机器承载同一个 private cloud,并受订阅中的机器数量上限限制。
如果只是个人本地使用,优先看 CLI 安装 或 桌面应用安装。
前置条件
- Agentrix 账号已开通 Private Cloud 权限。
- 一台可长期运行的 Linux 服务器或虚拟机。
- 服务器可以访问 Agentrix 后端 API。使用官方服务时默认是
https://agentrix.xmz.ai;自部署时替换为你的 API 地址。 - 已安装 Node.js 18+、npm、git,以及任务需要的 agent CLI,比如 Claude Code 或 Codex。
- 服务器上有一个专门运行 Agentrix 的系统用户,比如
agentrix。
依赖安装和检查方式见 依赖项。启动前可以先运行 agentrix doctor。
创建 Private Cloud
- 打开 Agentrix Web 应用。
- 进入
Settings->Private Clouds。 - 点击右上角菜单,选择创建新的 Private Cloud。
- 创建后进入详情页,复制 runner secret。
runner secret 用来注册 runner 机器,相当于这组 runner 的机器令牌。它不等同于邀请链接,不要发给普通成员,也不要提交到代码仓库。
如果创建入口不可用,通常是当前订阅没有开启 Private Cloud,或者数量已经达到上限。
在服务器上启动 runner
在 runner 服务器上安装 CLI 和必要 agent:
npm install -g @agentrix/cli
npm install -g @anthropic-ai/claude-code
如果你要执行 Codex 类型任务,再安装 Codex CLI:
npm install -g @codex-ai/codex-cli
用 runner secret 启动 daemon:
export AGENTRIX_SERVER_URL=https://agentrix.xmz.ai
export AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai
export AGENTRIX_HOME_DIR=/opt/agentrix
export CLOUD_AUTH_TOKEN=<runner-secret>
agentrix start
agentrix status
自部署环境需要把 AGENTRIX_SERVER_URL 和 AGENTRIX_WEBAPP_URL 改成自己的地址。CLOUD_AUTH_TOKEN 存在时,CLI 会跳过浏览器登录流程,用该 secret 生成并注册 cloud runner 机器。
用 Docker 镜像启动 runner
CLI Docker 镜像适合不想在宿主机上单独安装 Node.js、Claude Code、Codex 和沙箱依赖的 runner。镜像默认执行 agentrix daemon,启动时必须提供 CLOUD_AUTH_TOKEN,也就是 Private Cloud 详情页里的 runner secret。
docker run -d \
--name agentrix-runner \
--restart unless-stopped \
-e AGENTRIX_SERVER_URL=https://agentrix.xmz.ai \
-e AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai \
-e CLOUD_AUTH_TOKEN=<runner-secret> \
-e AGENTRIX_BASE_URL=https://api.xmz.ai \
-e AGENTRIX_API_KEY=<llm-gateway-api-key> \
-e GITLAB_BASE_URL=https://gitlab.example.com \
-e GITLAB_TOKEN=<gitlab-token> \
-e AGENTRIX_GITLAB_USE_AS_PROXY=true \
-v agentrix-home:/home/agentrix/.agentrix \
-v agentrix-workspaces:/home/agentrix/.agentrix/workspaces \
ghcr.io/xmz-ai/agentrix/agentrix-cli:latest
自部署环境需要把 AGENTRIX_SERVER_URL 和 AGENTRIX_WEBAPP_URL 换成自己的 Agentrix 地址;如果你们维护自己的镜像,也可以把镜像名换成自有 registry 里的 agentrix-cli 镜像。AGENTRIX_API_KEY 在这里是 LLM 网关密钥,runner 注册和任务鉴权仍然使用 CLOUD_AUTH_TOKEN。
容器启动 agentrix daemon 或 agentrix start 前,会自动执行 agentrix llm-config apply,根据环境变量生成 Claude、Codex、PI 和 Gemini 的配置:
| 配置 | 默认路径 |
|---|---|
| Claude Code | /home/agentrix/.claude/settings.json |
| Codex | /home/agentrix/.codex/config.toml |
| PI | $AGENTRIX_PI_HOME/models.json 和 settings.json,默认是 /home/agentrix/.pi/agent |
| Gemini | $AGENTRIX_GEMINI_HOME/settings.json,默认是 $AGENTRIX_HOME_DIR/config/gemini/settings.json |
自动配置默认只写入缺失文件,不覆盖已有配置。缺少 AGENTRIX_API_KEY 且没有可读的 AGENTRIX_API_KEY_FILE 时,entrypoint 会在启动 daemon 前报错退出。需要重建配置时设置 AGENTRIX_LLM_CONFIG_FORCE=true;如果你想完全自己挂载配置文件,设置 AGENTRIX_LLM_AUTO_CONFIG=false。
如果容器需要访问私有 GitLab,可以同时传入 GITLAB_BASE_URL 和 GITLAB_TOKEN。已认证的 Private Cloud runner 在未配置 AGENTRIX_GITLAB_BIND_USER 时默认使用 false:token 只保存在 runner 本地,不会把公共 bot 绑定为每个 runner owner 的 Git 身份。AGENTRIX_GITLAB_USE_AS_PROXY=true 独立控制 proxy node 注册。多台 runner 可以安全复用同一组 bot 配置,API 发起 Git 操作时会从在线节点中选择一个。只有 PAT 确实代表当前 Agentrix 用户,并且需要出现在该用户的 GitServer 和仓库列表中时,才应设置 AGENTRIX_GITLAB_BIND_USER=true。
常用变量如下:
| 变量 | 默认值 | 说明 |
|---|---|---|
AGENTRIX_API_KEY | — | LLM 网关密钥,用于生成 Claude、Codex、PI 和 Gemini 配置 |
AGENTRIX_API_KEY_FILE | — | 从文件读取 LLM 网关密钥,适合 Docker secret |
AGENTRIX_BASE_URL | https://api.xmz.ai | LLM 网关地址;Codex 配置会自动使用该地址下的 /v1 |
AGENTRIX_CODEX_MODEL | gpt-5.5 | Codex 默认模型 |
AGENTRIX_PI_MODEL | 同 AGENTRIX_CODEX_MODEL | PI 默认模型 |
AGENTRIX_CLAUDE_MODEL | claude-sonnet-4-6 | Claude 默认模型 |
AGENTRIX_CLAUDE_FAST_MODEL | claude-haiku-4-5 | Claude fast model |
AGENTRIX_CLAUDE_SUBAGENT_MODEL | 同 AGENTRIX_CLAUDE_MODEL | Claude subagent model |
AGENTRIX_GEMINI_IMAGE_MODEL | gemini-2.5-flash-image | Gemini 图片模型 |
AGENTRIX_CLAUDE_HOME | /home/agentrix/.claude | Claude Code 配置目录 |
AGENTRIX_CODEX_HOME | /home/agentrix/.codex | Codex 配置目录 |
AGENTRIX_PI_HOME | /home/agentrix/.pi/agent | PI 配置目录;也兼容 PI_CODING_AGENT_DIR |
AGENTRIX_CLAUDE_PATH | /usr/local/bin/claude | Claude Code 二进制路径 |
AGENTRIX_CODEX_PATH | /usr/local/bin/codex | Codex 二进制路径 |
AGENTRIX_GEMINI_HOME | $AGENTRIX_HOME_DIR/config/gemini | Gemini 配置目录 |
CLOUD_AUTH_TOKEN_FILE | — | 从文件读取 runner secret,适合 Docker secret |
AGENTRIX_EVENT_FORWARD_WS_URL | — | 企业事件转发接收服务地址,见下文"事件转发" |
AGENTRIX_EVENT_FORWARD_TOKEN_FILE | — | 从文件读取事件转发认证 token,适合 Docker secret |
GITLAB_BASE_URL | — | 自动配置的 GitLab 站点 URL |
GITLAB_API_URL | <base-url>/api/v4 | 自动配置 GitLab 时使用的 API URL |
GITLAB_TOKEN | — | GitLab token,写入本地加密 store,并在启用用户绑定时同步为 API 侧 credential |
GITLAB_TOKEN_FILE | — | 从文件读取 GitLab token,适合 Docker secret |
AGENTRIX_GITLAB_BIND_USER | false | 是否把 GitLab 账号绑定到 runner owner 的 Agentrix 用户;只有个人 PAT 才应设为 true |
AGENTRIX_GITLAB_USE_AS_PROXY | true | 是否把当前 runner 注册为 Git proxy node |
AGENTRIX_GITLAB_AUTO_CONFIG | true | 设为 false 可禁用 GitLab 自动配置 |
镜像还会在启动时检查并补齐全局 Git 身份,默认是 Agentrix <[email protected]>。如需使用团队身份,可以设置 AGENTRIX_GIT_USER_NAME 和 AGENTRIX_GIT_USER_EMAIL。
用 systemd 托管
生产环境建议用 systemd 或同类进程管理器托管 daemon。先确认 agentrix 的真实路径:
command -v agentrix
如果还没有专用系统用户,先创建一个:
sudo useradd --system --create-home --home-dir /opt/agentrix --shell /usr/sbin/nologin agentrix
创建环境变量文件:
sudo mkdir -p /etc/agentrix
sudo install -m 600 /dev/null /etc/agentrix/private-cloud.env
sudoedit /etc/agentrix/private-cloud.env
写入以下内容:
AGENTRIX_SERVER_URL=https://agentrix.xmz.ai
AGENTRIX_WEBAPP_URL=https://agentrix.xmz.ai
AGENTRIX_HOME_DIR=/opt/agentrix
CLOUD_AUTH_TOKEN=<runner-secret>
创建 /etc/systemd/system/agentrix-private-cloud.service:
[Unit]
Description=Agentrix Private Cloud Runner
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=agentrix
WorkingDirectory=/opt/agentrix
EnvironmentFile=/etc/agentrix/private-cloud.env
ExecStart=/usr/local/bin/agentrix daemon
ExecStop=/usr/local/bin/agentrix stop
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
把 ExecStart 和 ExecStop 中的路径替换为 command -v agentrix 的输出。systemd 下使用 agentrix daemon,因为 agentrix start 会拉起后台 daemon 后退出。然后启动服务:
sudo mkdir -p /opt/agentrix
sudo chown -R agentrix:agentrix /opt/agentrix
sudo systemctl daemon-reload
sudo systemctl enable --now agentrix-private-cloud
sudo systemctl status agentrix-private-cloud
查看日志:
journalctl -u agentrix-private-cloud -f
tail -f /opt/agentrix/logs/daemon.log
验证 runner 在线
回到 Settings -> Private Clouds,进入对应 cloud 详情页,确认 runner 数量显示为在线,例如 1/3。也可以在服务器上运行:
sudo systemctl status agentrix-private-cloud
agentrix status
agentrix doctor
如果 daemon 由 systemd 以 agentrix 用户运行,命令行检查也要使用同一个 AGENTRIX_HOME_DIR 环境。
如果状态正常,但 Web 应用里暂时没有变化,等几秒后刷新列表。runner 通过 WebSocket 上报在线状态,网络抖动或 daemon 重启时会有短暂延迟。
邀请团队成员
Private Cloud owner 可以在详情页生成邀请链接。成员打开链接并登录后,会把这个 private cloud 绑定到自己的账号。
邀请链接只用于加入成员,不用于启动 runner。成员加入后可以在创建任务时选择这个 private cloud,但看不到 runner secret。
在任务里使用
创建新任务时,在 runner 或执行环境选择器里选择对应的 private cloud。通过 agentrix-run 提交任务时,使用对应的 cloud-* runner ID:
agentrix-run \
--prompt "Run the test suite and fix failures" \
--runner-id cloud-xxx
更多 CI 用法见 agentrix-run。
事件转发
事件转发让 runner 把任务互动的全量 task event(用户消息、assistant 回复、tool 调用与结果、worker 生命周期事件、task-usage-report 等计量事件)主动外推到企业自建的 WebSocket 接收服务。数据从 runner 直连企业内网服务,不经过第三方,适合对接审计、归档、消息通知等内部系统。
启用条件(两者同时满足):
- runner 运行在 cloud 模式(配置了
CLOUD_AUTH_TOKEN)。local 模式消息端到端加密,转发密文没有意义,不支持。 - 配置了
AGENTRIX_EVENT_FORWARD_WS_URL。设置即启用,无需其他开关。
配置
| 变量 | 必填 | 说明 |
|---|---|---|
AGENTRIX_EVENT_FORWARD_WS_URL | 是(设置即启用) | 企业 WS 接收服务地址,ws:// 或 wss:// |
AGENTRIX_EVENT_FORWARD_TOKEN | 否 | 握手时放入 Authorization: Bearer <token> header,由接收端自行校验 |
AGENTRIX_EVENT_FORWARD_RETENTION_HOURS | 否,默认 24 | 已确认(acked)事件在本地 outbox 的保留时长 |
AGENTRIX_EVENT_FORWARD_MAX_DB_MB | 否,默认 512 | 本地 outbox 体积上限,超限时从最旧事件开始丢弃并打 WARN |
Docker 镜像额外支持 AGENTRIX_EVENT_FORWARD_TOKEN_FILE,用法与 CLOUD_AUTH_TOKEN_FILE 相同。
工作机制
- 事件先持久化到 runner 本地 outbox(
$AGENTRIX_HOME_DIR/forward/outbox.db),daemon 内的转发服务按游标批量推送。daemon 重启、接收端宕机期间事件不丢,重连后按 cursor 回放。 - 投递语义是 at-least-once:接收端必须按
eventId幂等去重。 cursor是 runner 级单调递增序号,多台 runner 汇聚到同一个接收端时,按machineId分别记录 cursor。- 转发不承诺服务端全局
sequence(发送时可能尚未回填)。需要任务内全序或 100% 对账时,用 RESTGET /v1/tasks/:taskId/events兜底;只在 API 侧产生、从不下发到 runner 的纯服务端事件也不会被转发。 - outbox 超过体积上限被迫丢弃未确认事件时,重连后的首个
events帧会带droppedBeforeCursor字段标记 gap。 - 转发状态通过 daemon 日志查看(
$AGENTRIX_HOME_DIR/logs/daemon.log,搜索[FORWARD])。
协议
原生 WebSocket + JSON 文本帧,接收端可用任何语言实现:
// CLI → 接收端:连接后握手(cloudId 为该 runner 所属的 private cloud)
{ "type": "hello", "protocolVersion": 1, "machineId": "machine-xxx", "cloudId": "cloud-xxx", "hostname": "runner-01", "cliVersion": "0.45.0" }
// 接收端 → CLI:握手确认。resumeFromCursor 可选,声明自己已消费到的 cursor;
// 省略时由 runner 本地已确认的 cursor 决定回放起点
{ "type": "hello-ack", "resumeFromCursor": 12345 }
// CLI → 接收端:事件批次(droppedBeforeCursor 仅在 outbox 曾丢弃未确认事件时出现)
{ "type": "events", "events": [
{ "cursor": 12346, "eventId": "evt-xxx", "taskId": "task-xxx", "chatId": "chat-xxx",
"eventType": "task-message", "direction": "outbound",
"eventData": { /* 完整事件 payload,如 TaskMessageEventData */ },
"createdAt": "2026-07-02T08:00:00.000Z" }
] }
// 接收端 → CLI:累积确认(确认 cursor 及之前的全部事件)
{ "type": "ack", "cursor": 12346 }
direction 为 outbound 表示 worker 产生的事件(assistant 回复、tool 调用、生命周期事件等),inbound 表示下发给 runner 的事件(用户消息、任务创建/恢复的初始消息等)。心跳使用 WebSocket 协议层的 ping/pong 帧,应用层无需处理。
参考接收端实现
一个最小可用的 Node 接收服务(npm install ws 后运行):
const { WebSocketServer } = require('ws');
const seenEventIds = new Set(); // 生产环境换成持久化存储
const cursors = new Map(); // machineId -> 已确认 cursor
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (socket, request) => {
const auth = request.headers.authorization;
if (process.env.FORWARD_TOKEN && auth !== `Bearer ${process.env.FORWARD_TOKEN}`) {
socket.close(4401, 'unauthorized');
return;
}
let machineId = null;
socket.on('message', (raw) => {
const frame = JSON.parse(raw);
if (frame.type === 'hello') {
machineId = frame.machineId;
const resumeFromCursor = cursors.get(machineId) ?? 0;
socket.send(JSON.stringify({ type: 'hello-ack', resumeFromCursor }));
console.log(`runner ${machineId} connected, resume from ${resumeFromCursor}`);
return;
}
if (frame.type === 'events') {
if (frame.droppedBeforeCursor) {
console.warn(`gap: events before cursor ${frame.droppedBeforeCursor} were dropped`);
}
for (const event of frame.events) {
if (seenEventIds.has(event.eventId)) continue; // at-least-once 去重
seenEventIds.add(event.eventId);
console.log(`[${event.direction}] ${event.eventType} task=${event.taskId} cursor=${event.cursor}`);
// 在这里写入你的审计 / 归档 / 通知系统
}
const last = frame.events[frame.events.length - 1];
cursors.set(machineId, last.cursor);
socket.send(JSON.stringify({ type: 'ack', cursor: last.cursor }));
}
});
});
console.log('forward receiver listening on :8080');
安全建议
- runner secret 泄露后,应停止旧 runner,并重新创建 private cloud 或联系管理员处理。
- 用单独的低权限系统用户运行 daemon。
- 确保
AGENTRIX_HOME_DIR、环境变量文件和日志目录权限受控。 - 不要把 runner secret 写进仓库、CI 明文变量或多人共享的 shell 配置。
- runner 服务器一般只需要主动访问 Agentrix API,不需要暴露公网入站端口。
常见问题
runner 没有上线
检查 CLOUD_AUTH_TOKEN 是否在 daemon 进程环境里生效,systemd 场景下重点看 EnvironmentFile。再确认 AGENTRIX_SERVER_URL 指向正确 API,并查看 daemon.log。
启动时打开了浏览器登录
这说明 daemon 没有读到 CLOUD_AUTH_TOKEN。重新导出环境变量,或重启 systemd 服务并检查环境变量文件权限。
任务一直排队
先确认 private cloud 详情页里有在线 runner。然后在 runner 上运行 agentrix doctor,检查 git、Claude Code、Codex 和沙箱依赖是否缺失。任务级日志在 $AGENTRIX_HOME_DIR/logs/worker-<taskId>.log。
提示 token 无效或 cloud 不存在
通常是复制了错误的 secret,或者 runner 连接到了错误的 Agentrix API。重新复制详情页里的 runner secret,并确认 AGENTRIX_SERVER_URL 使用同一个部署环境。