跳转至

CapOwn — 部署指南(手动)

首次安装? 请先阅读 快速开始(Master → Worker → token → Agent)。本页侧重进阶部署、Nginx 与故障排查。

提示: 部署脚本(python3 deploy.py)同时支持交互式部署和配置源驱动部署:

# 交互式 Master 部署(首次安装)
python3 deploy.py install master --public-url http://192.168.1.10:9210

首次安装 Master 时会自动创建 starter 用户 chiral 和 bundle enrollment token。部署完成后会显示生成的 Worker 和 Client 安装命令。

# 从配置源一键部署(本地 TOML、TOML URL 或 bundle enrollment URL)
python3 deploy.py install worker https://master.example.com/api/enroll/cown_tmp_xxxxx
python3 deploy.py install worker capown-worker.toml
python3 deploy.py install worker capown-worker.toml --mirror-cn   # 中国镜像
python3 deploy.py install client https://master.example.com/api/enroll/cown_tmp_xxxxx
python3 deploy.py install client capown-client.toml

# 配合 uv 镜像用于受限网络
python3 deploy.py install worker --uv-mirror https://pypi.example.com/simple
CAPOWN_UV_MIRROR_URL=https://pypi.example.com/simple python3 deploy.py install worker

# 使用自定义工作空间路径(覆盖配置源 defaults)
python3 deploy.py install worker capown-worker.toml --workspace /srv/my-project

对于多用户场景,在 Master 主机上生成 bundle enrollment URL:

# 在 Master 主机上
capown-master tokens create alice

# 或指定显式 URL(覆盖已配置的 public_url)
capown-master tokens create alice --type bundle --master-url https://master.example.com

# 在用户 Worker 机器上:一键安装 + 身份配置
python3 deploy.py install worker https://master.example.com/api/enroll/cown_tmp_xxxxx

# 或已安装——仅重新配置身份
capown-worker config https://master.example.com/api/enroll/cown_tmp_xxxxx

# 在用户 Client/AI Agent 机器上:一键安装 + 身份配置
python3 deploy.py install client https://master.example.com/api/enroll/cown_tmp_xxxxx

# 或已安装——仅重新配置身份
capown config https://master.example.com/api/enroll/cown_tmp_xxxxx

同一个临时 URL 可用于两种角色;CLI 会向 Master 报告当前角色。tokens create --type bundle 默认还会写入本地 TOML 文件,支持 deploy.py install worker <source>deploy.py install client <source> 工作流。每个用户仅允许一个活跃的 bundle URL—— 生成新的 bundle 会自动撤销前一个。

重新运行不带 source 参数的 install 命令会更新软件并保留现有本地配置。 运行 deploy.py install worker <source>deploy.py install client <source> 会显式应用该配置源并替换本地身份信息。仅在需要移除配置和数据时使用 deploy.py uninstall <component> --purge

部署完成后,capowncapown-master CLI 工具会被安装到 ~/.capown/bin/。 将其加入 PATH 以便使用:

export PATH="$PATH:$HOME/.capown/bin"

启动配置选项

首次安装 Master(尚未存在 ~/.capown/master/config.toml~/.capown/master/data/registry.db)时,会自动创建 starter 用户和 bundle。

# 默认情况下自动创建用户 'chiral'
python3 deploy.py install master --public-url http://192.168.1.10:9210

# 自定义用户名
python3 deploy.py install master --public-url http://192.168.1.10:9210 --bootstrap-user admin

# 跳过自动引导(无需 public URL)
python3 deploy.py install master --no-bootstrap

也可通过 MASTER_PUBLIC_URL 环境变量设置 public URL:

MASTER_PUBLIC_URL=http://192.168.1.10:9210 python3 deploy.py install master

选项说明: - --bootstrap-user <name>:starter 用户的用户名(默认:chiral) - --no-bootstrap:跳过自动创建用户和 bundle - --public-url <url>:Master 的公共 URL(也可使用 MASTER_PUBLIC_URL 环境变量)

启动配置仅在全新安装时执行。重新安装或升级现有 Master 不会创建、 替换或吊销任何用户或 token。starter bundle 的默认 TTL 为 24 小时。 如果启动配置失败,Master 会保持运行状态并显示恢复命令。

本文档涵盖面向高级使用场景的手动配置方法。

前提条件

  • Master 主机上已安装 Docker 和 Docker Compose
  • 所有 Worker 主机到 Master 的出站 HTTPS 访问
  • 运行 deploy.py 需要 Python 3.10+。无需手动安装 Python 3.12——deploy.py 通过 uv(安装到 ~/.capown/tools/uv/)自动管理 Python 运行时。Python 3.12 在首次部署时 由 uv 自动下载和管理。部署前不需要自行安装 Python 包依赖;部署脚本会自动创建 虚拟环境并安装运行时依赖。

使用网络镜像(适用于中国或离线环境):

# 通过环境变量(适用于所有 install 命令)
export CAPOWN_UV_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple

# 或通过 CLI 标志(逐命令生效)
python deploy.py install worker --uv-mirror https://pypi.tuna.tsinghua.edu.cn/simple

Master 部署(容器)

1. 部署 Master

使用部署脚本部署 Master。首次安装时会自动创建 starter 用户 chiral 和 bundle enrollment token。

# 交互式部署(提示设置)
python3 deploy.py install master --public-url http://192.168.1.10:9210

# 非交互式部署(使用默认值)
python3 deploy.py install master --public-url http://192.168.1.10:9210 -y

首次安装需要 --public-url。也可以通过 MASTER_PUBLIC_URL 环境变量提供:

MASTER_PUBLIC_URL=http://192.168.1.10:9210 python3 deploy.py install master -y

使用 --no-bootstrap 跳过自动创建用户和 bundle:

python3 deploy.py install master --no-bootstrap

部署完成后会显示生成的 Worker 和 Client 安装命令。starter bundle 的默认有效期为 24 小时。

如需为其他用户创建 enrollment 凭据:

capown-master tokens create <username>

2. 准备数据目录

mkdir -p ~/.capown/master/data

3. 构建并运行

cd master/

# 使用默认配置构建(国际镜像)
DOCKER_BUILDKIT=0 docker compose build

# 或使用中国镜像
DOCKER_BUILDKIT=0 \
  APT_MIRROR=mirrors.tuna.tsinghua.edu.cn \
  PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
  docker compose build

# 启动容器
CAPOWN_MASTER_CONFIG="$HOME/.capown/master/config.toml" \
  CAPOWN_MASTER_DATA="$HOME/.capown/master/data" \
  docker compose up -d

# 检查状态
docker compose logs master

4. 验证

curl http://127.0.0.1:9210/health

端口模式(Docker)。 容器内的 Master 始终监听 0.0.0.0:9210。 Docker 默认将其发布到主机的 0.0.0.0:9210,因此同一网络的 Worker 可通过 http://<host-ip>:9210 访问。请确保主机防火墙允许入站 TCP 9210。 如需使用不同的主机侧端口(例如 9210 已被占用),可在运行 deploy.pydocker compose up 前设置 CAPOWN_HOST_PORT

CAPOWN_HOST_PORT=9211 python3 deploy.py install master

这会在主机上发布 0.0.0.0:9211,而容器内部仍监听标准的 9210 端口。 如果使用了非默认主机端口,则在运行 capown-master healthcapown-master start 时也需要设置相同的环境变量。

如果将 Master 端口保持为仅本地访问(用于 Nginx/反向代理配置),可在部署前设置 CAPOWN_BIND_HOST=127.0.0.1

5. 管理 CLI

部署 Master 后,使用 capown-master 管理服务:

capown-master status
capown-master health
capown-master logs

所有可用命令参见用户指南

Worker 部署

Worker 控制进程始终作为原生 OS 服务在宿主机上运行。使用容器执行后端时, 会额外创建一个托管的 Docker 容器用于任务隔离。deploy.py 脚本会自动处理 这两个步骤。

宿主机执行后端(Linux)

任务直接在宿主机系统上运行。适用于不需要 Docker 的可信机器。

1. 编写配置文件

创建 ~/.capown/worker/config.toml

[worker]
execution_mode = "host"
worker_name = "<unique-worker-name>"
master_url = "https://your-server.com/v1"
workspace = "/"
max_runtime = 86400
idle_timeout = 600
reconnect_interval = 5

enrollment_token = "cown_enroll_xxx"

2. 安装应用副本

mkdir -p ~/.capown/worker/app
cp -r ../shared ~/.capown/worker/app/
cp -r ../worker ~/.capown/worker/app/
cp ../worker/requirements.txt ~/.capown/worker/app/

3. 虚拟环境(由 uv 管理)

部署脚本会自动使用 uv 创建虚拟环境:

# uv 会自动安装,无需手动配置 Python
python3 deploy.py install worker

运行部署脚本时,uv 会先安装到 ~/.capown/tools/uv/(如果 PATH 中尚不存在), 然后 uv 会下载 Python 3.12,并在 ~/.capown/worker/venv/ 中创建包含所有依赖的 虚拟环境。

为 uv 操作使用镜像:

CAPOWN_UV_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
  python3 deploy.py install worker

4. 安装 systemd 服务

创建 ~/.config/systemd/user/capown-worker.service

[Unit]
Description=CapOwn Worker
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.capown/worker/venv/bin/python -m worker.daemon
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target

然后启用并启动:

systemctl --user daemon-reload
systemctl --user enable --now capown-worker

# 启用 linger 以使服务在开机时自动启动
sudo loginctl enable-linger $USER

宿主机执行后端(Windows)

1. 编写配置文件

与 Linux 宿主机模式相同,但放在 %USERPROFILE%\.capown\worker\config.toml

2. 安装应用副本

mkdir "$env:USERPROFILE\.capown\worker\app" -Force
Copy-Item ..\shared "$env:USERPROFILE\.capown\worker\app\" -Recurse
Copy-Item ..\worker "$env:USERPROFILE\.capown\worker\app\" -Recurse
Copy-Item ..\worker\requirements.txt "$env:USERPROFILE\.capown\worker\app\"

3. 虚拟环境(由 uv 管理)

部署脚本会自动创建虚拟环境:

python deploy.py install worker

uv 和 Python 3.12 自动管理。

4. 创建计划任务

# 删除已有任务(如有)
schtasks /Delete /TN CapOwnWorker /F

# 创建新任务
schtasks /Create `
  /TN CapOwnWorker `
  /SC ONLOGON `
  /TR "$env:USERPROFILE\.capown\worker\venv\Scripts\python -m worker.daemon" `
  /RL LIMITED `
  /F

# 启动任务
schtasks /Run /TN CapOwnWorker

同机 Master + Worker

当 Master 和 Worker 运行在同一台主机上时,将 Worker 配置为通过 localhost 连接:

# worker/config.toml
[worker]
execution_mode = "container"  # 或 "host"
worker_name = "local-worker"
master_url = "http://127.0.0.1:9210"
# ...

配置 Nginx

公网 Master 若要同时支持 CLI/skill 与 MCP,需要两条独立入口:

用途 对外 URL 示例 后端路径 客户端如何配置
REST / CLI / skill / Worker SSE / enrollment https://api.example.net/v1/... /api/.../health CLI:master_url = "https://api.example.net/v1"
MCP Streamable HTTP https://api.example.net/mcp /mcp MCP Host:url = "https://api.example.net/mcp"

说明:

  • Master 进程上 REST 挂在 /api/*,MCP 挂在根路径 /mcp(不在 /api 下)。
  • CLI 把路径拼在 master_url 后面(例如 master_url + "/api/workers"),因此带 /v1 前缀的 master_url 很常见。
  • 只配置 location /v1/ 不会自动暴露公网 https://.../mcp;MCP 需要单独 location(或等价映射)。
  • Origin 校验只比较 scheme/host/port,不含 pathpublic_url 应写成纯 origin,例如 https://api.example.net,不要写成 https://api.example.net/v1

将以下内容合并到你的 HTTPS 服务端配置块中:

# CLI / skill / Worker / enrollment:对外前缀 /v1 → 后端根路径
location /v1/ {
    proxy_pass http://127.0.0.1:9210/;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Worker SSE 需要禁用缓冲
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

# 可选:健康检查
location = /v1/health {
    proxy_pass http://127.0.0.1:9210/health;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

# MCP Streamable HTTP:单独 location,缓冲/超时与 REST 不同
location /mcp {
    proxy_pass http://127.0.0.1:9210/mcp;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Connection '';
    chunked_transfer_encoding on;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

然后重新加载:sudo nginx -t && sudo systemctl reload nginx

Master 侧 Origin 相关配置示例:

[master]
public_url = "https://api.example.net"
  • 浏览器类 MCP 客户端会带 Origin,须与 public_url 的 scheme/host/port 一致。
  • 非浏览器 MCP 客户端通常省略 Origin,仅用 client bearer token 认证。
  • 未配置 public_url 时,所有带 Origin 的 MCP 请求返回 403。

可选:若希望 MCP 也挂在 /v1 下,可增加更具体的 location /v1/mcp,将 proxy_pass 指到后端 /mcp,MCP Host 则填写 https://api.example.net/v1/mcp。 仍建议与 REST 分开写 location,以便单独设置 Streamable HTTP 的缓冲与超时。

工具、认证与客户端示例见 MCP 指南

安全

  • 双 Token 机制:Worker Token(Worker 身份)和 Client Token(派遣权限)相互独立
  • 全出站网络:Worker 不暴露任何入站端口
  • 路径穿越防护:所有文件操作通过 realpath 验证强制遵守 workspace 边界
  • 容器隔离:Master 和 Worker 均在 Docker 容器中以非 root 用户运行
  • 命令超时:长时间运行的命令会被自动终止
  • 无硬编码密钥:Token 从本地配置文件或环境变量覆盖加载
  • Master 端口暴露:默认情况下 Docker 将 Master 发布到 0.0.0.0:9210 以便局域网快速上手。生产环境中请使用防火墙,或设置 CAPOWN_BIND_HOST=127.0.0.1 并通过 Nginx/反向代理暴露。
  • MCP Origin 校验:带 Origin 的 MCP 请求必须与配置的 public_url 完全匹配;客户端 Token 仍用于每个 MCP 请求的身份验证。

构建系统

Docker 构建要求

在 Docker 默认桥接网络没有 DNS 解析的机器上(常见于云虚拟机),两个标志必须使用:

标志 原因
DOCKER_BUILDKIT=0 BuildKit 的 --network=host 不可靠;旧版构建器可将主机网络透传到中间容器
--network=host 让构建容器使用主机的网络栈,以便 apt-getpip 访问外部仓库

ARG 作用域(Dockerfile)

FROM 之前声明的 ARG 仅在 FROM 指令中可见。要在 RUN 步骤中使用, 需要在 FROM 之后重新声明(不带默认值):

ARG APT_MIRROR=deb.debian.org
FROM ${PYTHON_IMAGE}
ARG APT_MIRROR          # 重新声明以引入作用域
RUN sed -i "s|http://deb.debian.org|http://${APT_MIRROR}|g" ...

sudo 和环境变量

sudo 默认会剥离大部分环境变量。使用 sudo 运行 docker compose build 时, APT_MIRROR 等环境变量无法传递到 docker-compose 进程。两种解决办法:

  • 显式传递:sudo -E env APT_MIRROR=... docker compose build
  • 或直接使用 docker build 并通过 --build-arg 传递

镜像配置

构建参数 默认值(国际) 中国示例
PYTHON_IMAGE python:3.12-slim (保持默认,Docker Hub 可用)
APT_MIRROR deb.debian.org mirrors.tuna.tsinghua.edu.cn
PIP_INDEX_URL https://pypi.org/simple https://pypi.tuna.tsinghua.edu.cn/simple

切换为中国镜像,在构建前设置环境变量:

export DOCKER_BUILDKIT=0
export APT_MIRROR=mirrors.tuna.tsinghua.edu.cn
export PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
docker compose build

代码变更后重新构建

cd <project-root>
DOCKER_BUILDKIT=0 docker build --no-cache --network=host \
  --build-arg APT_MIRROR=mirrors.tuna.tsinghua.edu.cn \
  --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
  -t capown-master -f master/Dockerfile .
cd master/ && docker compose up -d
# Worker 同理

故障排查

构建失败:"Undetermined Error"(apt-get)

构建容器无法访问 Debian 仓库。三种解决方法:

  1. 使用 DOCKER_BUILDKIT=0 docker build --network=host(旧版构建器 + 主机网络)
  2. 通过 --build-arg APT_MIRROR=... 使用更接近服务器的镜像
  3. 检查 APT_MIRROR 构建参数是否在 Dockerfile 中的 FROM 之后重新声明(ARG 作用域规则)

构建失败:日志中显示"deb.debian.org"即使已设置镜像

--build-arg 的值未传递到 RUN 指令。最常见的原因是 ARG 在 FROM 之前声明, 但未在构建阶段内部重新声明。参见上文构建系统部分中的"ARG 作用域"。

Worker 无法连接到 Master

  • 验证 Master 可达:curl <MASTER_URL>/health
  • 检查 worker token 是否与 Master 配置一致
  • 确保出站 HTTPS 未被防火墙阻止

任务已派遣但无结果 / Worker 未显示"executing task"日志

  • 检查目标 worker 是否在线:GET /api/workers
  • 验证 worker SSE 连接是否活跃(Master 日志显示 "broker: node X connected")
  • 检查 worker 日志:
  • 容器模式:docker compose logs worker
  • Linux 宿主机模式:journalctl --user -u capown-worker -f
  • Windows 宿主机模式:schtasks /Query /TN CapOwnWorker
  • SSE 换行符不匹配sse-starlette 使用 \r\n\r\n(CRLF,符合 SSE 规范)分隔事件。如果 worker 按 \n\n(仅 LF)分割流,事件将永远无法被解析。守护进程必须使用 \r\n\r\n 作为事件分隔符,或先规范化换行符。
  • 同机 Worker:建议使用 master_url = "http://127.0.0.1:9210" 以避免通过公网 IP / NAT 路径产生 SSE 流问题。
  • 阻塞型 HTTP 客户端urllib.request.urlopen().read() 可能会在 uvicorn 提供的 SSE 流上无限挂起。请使用支持流式的异步 HTTP 客户端(httpxaiohttp)。