1. 零刻/群晖/Macmini 上 Docker 部署 OpenClaw 到底难在哪
OpenClaw 是一个可以跑在自己硬件上的多 Agent 协作网关,简单说就是:你给它一个 Docker 环境,它帮你把飞书、企业微信、Telegram 这些渠道接进来,再按账号和会话把消息路由到不同的 Agent 上。适合谁?适合手里有零刻 mini 主机、群晖 NAS、Macmini 这类常年开机设备,又想让多个机器人各干各的活、互不串线的人。
我这次把三类设备都跑了一遍,最深的感受是:部署本身不难,难的是权限、挂载路径和多 Agent 路由这三件事。群晖因为 Docker 版本和目录权限的问题,坑最多;Macmini 走 localhost 最省心;零刻 mini 主机本质是 Linux,思路和群晖接近但少了套件层的干扰。
先说清楚整体链路。OpenClaw 官方仓库里带了docker-compose.yml和docker-setup.sh,但直接跑脚本在群晖上大概率报 BUILDKIT 相关错误,手动编译打包后又常常卡在「启动不了、进不去配置页」。核心原因是两个:一是 workspace 目录在容器首次启动前根本不存在,权限给不上去;二是 OpenClaw 默认只允许 localhost 访问控制台,你用局域网 IP 打开就会被安全策略拦下。
多用户多 Agent 这块,很多人第一反应是「多开几个账号不就行了」,其实不是。channels.<channel>.accounts只决定这个渠道挂了几个账号,agents.list才决定系统里有几个真正独立的 Agent,bindings决定某个账号最终进哪个 Agent,而session.dmScope只管私聊历史怎么分桶。这四者混在一起,就会出现「明明配了两个机器人却还是串线」的经典问题。
下面我按「前置准备 → 可复制配置 → 验证请求 → 报错排查 → 统一鉴权」的顺序拆开讲,配置片段都能直接抄。模型和鉴权通道我统一走 TaoToken,一个 Key 管多个模型,省得每个 Agent 单独配一遍上游。
2. TaoToken 前置准备:统一 Key 与 API 通道
在动手改 OpenClaw 配置之前,先把模型通道准备好。OpenClaw 的openclaw.json里models.providers需要填baseUrl、apiKey和模型列表,如果你每个 Agent 都去接不同上游,配置会非常乱。用 TaoToken 的好处是:一个 API Key 就能覆盖 DeepSeek、豆包、Qwen 这些模型,OpenClaw 里只配一个 provider 就够。
第一步,去官网注册并拿到 Key。地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册后在控制台创建 API Key。控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。Key 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,创建后复制保存,后面填进openclaw.json的apiKey字段。
第二步,确认 Base URL。TaoToken 的 API 端点是https://taotoken.net/api,注意这个地址后面不加 UTM 参数,直接写进配置即可。OpenClaw 里api字段填openai-completions,因为 TaoToken 兼容 OpenAI 的 completions 协议,这样 OpenClaw 不需要额外适配。
第三步,想先验证模型通不通,可以用模型对话页快速测一下:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。在这里选一个模型发一句话,能正常返回就说明 Key 和通道没问题,再去配 OpenClaw 会少走很多弯路。
如果你后面要长期跑编码类 Agent,或者想让多个 Agent 共享额度,可以看下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各语言的调用示例,配 OpenClaw 时对照着填字段就行。
这里提醒一句:OpenClaw 的openclaw.json对字段很敏感,多一个逗号、少一个引号都会导致容器起不来。建议每次改完配置先本地用 JSON 校验工具过一遍,再重启容器。我踩过的坑就是手改配置时漏了个括号,结果排查了半小时才发现是语法问题。
3. 可复制配置:docker-compose 与多 Agent 路由
这一节是全文核心,配置片段都能直接抄。先给群晖/零刻的docker-compose.yml关键改动。官方默认用${OPENCLAW_CONFIG_DIR}变量,群晖上建议直接写死绝对路径,避免变量解析出问题。
services: openclaw-gateway: build: . image: openclaw:local volumes: - /volume2/docker_m2/openClaw/openclaw-data:/home/node/.openclaw - /volume2/docker_m2/openClaw/openclaw-data/workspace:/home/node/.openclaw/workspace ports: - "18789:18789" restart: unless-stopped openclaw-cli: build: . image: openclaw:local volumes: - /volume2/docker_m2/openClaw/openclaw-data:/home/node/.openclaw - /volume2/docker_m2/openClaw/openclaw-data/workspace:/home/node/.openclaw/workspace注意openclaw-gateway和openclaw-cli两个服务的挂载路径都要改,只改一个会出现 CLI 读不到配置的情况。Macmini 上路径换成/Users/你的用户名/OpenClaw/openclaw-data即可,其余一致。
编译打包命令,群晖上必须带DOCKER_BUILDKIT=1:
sudo DOCKER_BUILDKIT=1 docker-compose up -d --build打包完成后容器可能起不来,这是正常的,因为还没初始化配置文件。先删掉这两个容器,用临时容器跑一次 onboard:
sudo docker run -it --rm \ -v "/volume2/docker_m2/openClaw/openclaw-data":/home/node/.openclaw \ openclaw:local \ node dist/index.js onboard初始化完会自动退出,这时openclaw-data里就有openclaw.json了。接着给 workspace 补权限:
sudo chown -R 1000:1000 /volume2/docker_m2/openClaw/openclaw-data/workspace sudo chmod -R 777 /volume2/docker_m2/openClaw/openclaw-data/workspace群晖还需要在openclaw.json里改网关绑定和跨域参数,否则局域网 IP 打不开控制台:
"gateway": { "bind": "lan", "controlUi": { "allowedOrigins": [ "http://127.0.0.1:18789", "http://localhost:18789" ], "dangerouslyAllowHostHeaderOriginFallback": true, "allowInsecureAuth": true, "dangerouslyDisableDeviceAuth": true } }这三个dangerously开头的参数只建议在纯局域网、自己能物理接触设备的情况下用。如果要对公网开放,请改成指定域名或 IP,别图省事。
接下来是多 Agent 路由配置,这是最容易配错的部分。以企业微信自建应用wecom-app为例,一份可直接抄的模板:
{ "agents": { "defaults": { "workspace": "~/.openclaw/workspace" }, "list": [ { "id": "agent-name-1", "default": true, "workspace": "~/.openclaw/workspace-agent-name-1" }, { "id": "agent-name-2", "workspace": "~/.openclaw/workspace-agent-name-2" } ] }, "session": { "dmScope": "per-account-channel-peer" }, "bindings": [ { "agentId": "agent-name-1", "match": { "channel": "wecom-app", "accountId": "account-name-1" } }, { "agentId": "agent-name-2", "match": { "channel": "wecom-app", "accountId": "account-name-2" } } ], "channels": { "wecom-app": { "defaultAccount": "account-name-1", "accounts": { "account-name-1": { "enabled": true, "webhookPath": "/wecom-app", "token": "your-account-1-token", "encodingAESKey": "your-account-1-encoding-aes-key", "corpId": "your-corp-id", "corpSecret": "your-account-1-corp-secret", "agentId": 1000002 }, "account-name-2": { "enabled": true, "webhookPath": "/wecom-app-bot2", "token": "your-account-2-token", "encodingAESKey": "your-account-2-encoding-aes-key", "corpId": "your-corp-id", "corpSecret": "your-account-2-corp-secret", "agentId": 1000004 } } } } }重点看三件事:accounts里定义了两个渠道账号,agents.list里定义了两个独立 Agent,bindings把账号路由到对应 Agent。注意channels.wecom-app.agentId是渠道自己的字段,和bindings[].agentId不是一回事,别混。
模型 provider 配置,统一走 TaoToken:
"models": { "mode": "merge", "providers": { "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKey": "你的TaoToken Key", "api": "openai-completions", "models": [ { "id": "deepseek-chat", "name": "DeepSeek Chat", "contextWindow": 128000, "maxTokens": 16000 }, { "id": "Doubao-Seed-2.0-lite", "name": "Doubao Seed 2.0 Lite", "contextWindow": 256000, "maxTokens": 128000 } ] } } }, "agents": { "defaults": { "model": { "primary": "taotoken/deepseek-chat" }, "models": { "taotoken/deepseek-chat": { "alias": "DeepSeek" }, "taotoken/Doubao-Seed-2.0-lite": { "alias": "Doubao" } }, "workspace": "/home/node/.openclaw/workspace" } }飞书多 Agent 同理,channels.feishu.accounts里配多个 bot,每个 bot 对应一个bindings条目即可。
4. 验证请求:从网关令牌到多 Agent 路由实测
配置改完,重启容器,然后验证。群晖上打开http://你的群晖IP:18789,Macmini 上打开http://localhost:18789。第一次会要求输入网关令牌,令牌在openclaw-data/openclaw.json的auth.token字段里:
"auth": { "mode": "token", "token": "72a83e3764346ffd1d8e71d8f0eaafe47ce948da55cb853916962f50beec6c81" }复制这串 token 填进去点连接。如果出现pairing required,说明设备还没授权,在终端执行:
docker exec -it openclaw-openclaw-gateway-1 node dist/index.js devices approve注意容器名要和你实际启动的一致,群晖上可能是openclaw-openclaw-cli-1或带版本号的名字,用docker ps确认一下。如果报gateway token mismatch,直接带上令牌强制执行:
docker exec -it openclaw-openclaw-gateway-1 node dist/index.js devices approve --token 你的网关令牌登录进去后,先验证模型通道。在对话界面发一句「你好,你现在用的是哪个模型」,能正常返回就说明 TaoToken 的 Key 和 Base URL 配对了。如果返回报错,去openclaw.json检查baseUrl是不是https://taotoken.net/api,apiKey有没有多余空格。
接着验证多 Agent 路由。给account-name-1对应的机器人发消息,看回复是不是来自agent-name-1;再给account-name-2发,确认走的是agent-name-2。判断方法很简单:两个 Agent 的 workspace 不同,你可以在各自 workspace 里放一个标识文件,让 Agent 读出来告诉你。
验证多用户隔离,用两个不同账号私聊同一个机器人,看历史记录会不会串。session.dmScope设成per-account-channel-peer后,每个账号的私聊历史是独立分桶的,不会互相污染。如果发现串了,八成是dmScope没配对,或者bindings里accountId写错了。
最后验证渠道接入。飞书插件安装命令:
docker exec -it openclaw-openclaw-gateway-1 npx -y @larksuite/openclaw-lark-tools install微信插件:
docker exec -it openclaw-openclaw-gateway-1 npx -y @tencent-weixin/openclaw-weixin-cli@latest install安装完扫码登录,然后在bindings里把微信账号绑到指定 Agent。微信插件默认绑main,想换 Agent 就改accounts.json里的accountId,再在bindings里加对应条目。
5. 本篇常见报错排查:401、proxy failed、choices 为空
部署过程中我遇到的报错基本集中在几类,逐个说。
401 unauthorized:模型请求返回 401,先查apiKey是不是复制时带了空格,再确认baseUrl是不是https://taotoken.net/api。如果 Key 没问题,去 TaoToken 控制台看下额度是否用完。还有一种情况是openclaw.json里models.providers的 provider 名字和agents.defaults.model.primary里的前缀不一致,比如 provider 叫taotoken,primary 却写成godx-api/deepseek-chat,就会鉴权失败。
local proxy failed:这个报错通常出现在渠道配置里带了proxy字段但代理地址不可达。OpenClaw 的 Telegram 配置里有proxy选项,如果你不需要代理,直接删掉这个字段。需要的话确认地址和端口正确,且容器网络能访问到。
reading choices 报错 / choices 为空:说明请求发出去了但返回体里没有choices字段,一般是模型 ID 写错了。去 TaoToken 文档页确认模型 ID 的准确拼写,比如deepseek-chat不能写成DeepSeek-Chat。另外api字段必须是openai-completions,写成别的协议 OpenClaw 解析不了返回体。
OAuth / device identity 报错:control ui requires device identity (use HTTPS or localhost secure context),这是浏览器安全策略导致的。解决办法是用 localhost 访问,或者在群晖上开启dangerouslyAllowHostHeaderOriginFallback和allowInsecureAuth。如果还不行,用devices approve命令手动授权。
BUILDKIT 报错:群晖上直接跑./docker-setup.sh会报这个,改成手动编译:
sudo DOCKER_BUILDKIT=1 docker-compose up -d --build容器启动后自动退出:openclaw-openclaw-cli-1自动退出是正常的,它只负责初始化。如果 gateway 也退出,看日志:
docker logs openclaw-openclaw-gateway-1大概率是openclaw.json语法错误,用 JSON 校验工具过一遍。
权限报错无法写入 workspace:初始化后 workspace 目录才生成,这时补权限:
sudo chown -R 1000:1000 /volume2/docker_m2/openClaw/openclaw-data/workspace sudo chmod -R 777 /volume2/docker_m2/openClaw/openclaw-data/workspaceheartbeat 消耗 token 过多:默认 heartbeat 会在同一个 session 里反复读HEARTBEAT.md,改成隔离 session:
"heartbeat": { "every": "30m", "isolatedSession": true, "lightContext": true, "target": "none", "directPolicy": "allow" }isolatedSession让 heartbeat 在没有历史记录的独立 session 里跑,lightContext不注入AGENTS.md、MEMORY.md这些 bootstrap 文件,请求体能从几十 k 降到 10k 左右。前提是你的HEARTBEAT.md写得够明确,告诉它读哪个文件干什么。
6. 统一鉴权收尾:用 TaoToken 管住多 Agent 的模型通道
多 Agent 跑起来之后,最烦的是每个 Agent 都要单独配模型和 Key。我的做法是全部走 TaoToken 一个 provider,agents.defaults.model.primary指向taotoken/deepseek-chat,其他 Agent 需要不同模型时,在agents.list里单独覆盖model字段即可,Key 和 Base URL 不用重复填。
这样改的好处是:换模型只改一处,加 Agent 只加bindings和agents.list条目,模型通道始终统一。如果你后面要接 Claude Code 这类编码工具,TaoToken 也有对应的接入方式,文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,Base URL 和 Key 的填法和 OpenClaw 一致。
最后给个实用技巧:改openclaw.json之前先备份一份,尤其是让低智商模型帮你改配置的时候,它很容易把 JSON 结构改坏导致容器起不来。我现在的习惯是每次改完先docker exec进去用node -e "JSON.parse(require('fs').readFileSync('/home/node/.openclaw/openclaw.json'))"校验一遍,通过了再重启。多 Agent 路由验证也一样,别一次配五个,先配两个跑通,确认不串线了再往上加。