1. 从一次容器重启说起:OpenClaw 容器化部署到底难在哪
OpenClaw 是一个可以自托管的 AI 智能体网关,它能用一个 Gateway 把飞书、企业微信、个人微信等消息通道统一接进来,再配合技能系统和定时任务,让 AI 真正跑在你的服务器上。适合谁?适合想 7x24 挂机、又不想把数据交给第三方托管的自托管新手。但很多人第一次容器化部署时,卡点不在“装不上”,而在“装上了跑不起来”——容器一重启,会话丢了;Chrome 起不来,浏览器自动化直接报错;API Key 填了,请求却 401。
我自己在 2c2g 的机器上反复折腾过几轮,最典型的一次是:容器重启后 OpenClaw gateway 起来了,但浏览器工具一直报SingletonLock相关错误,日志里全是Failed to launch chrome。排查半天才发现,是上一次容器退出时 Chrome 的锁文件没清理,新进程以为已有实例在跑,直接拒绝启动。这类坑,官方文档不会逐条写,只能靠踩。
这篇是《永久免费 OpenClaw 部署》的续篇,聚焦容器化部署里的典型报错与配置陷阱。我会交付可复制的 Docker Compose 配置、环境变量清单、逐步验证动作,并说明怎么把 endpoint 和 Base URL 统一改到 TaoToken 的 API 通道,让 Key 管理不再散落各处。全文按“问题场景 → 前置准备 → 可复制配置 → 验证请求 → 错排查 → 通道统一”的顺序展开,你可以按需跳读。
先说结论:容器化部署 OpenClaw 的核心矛盾,是状态持久化和进程生命周期。容器本身是无状态的,但 OpenClaw 的会话、记忆、浏览器 profile 全都要落盘。你把它们放在容器内,重启就丢;放在挂载卷里,又要处理权限和锁文件。下面一步步来。
2. TaoToken 前置:把 Key 和 Base URL 收口到统一通道
在讲容器配置之前,先把 API 通道这件事理清楚。OpenClaw 要调 LLM,就得配OPENAI_API_BASE和OPENAI_API_KEY。很多人一开始用某家免费额度,跑着跑着限速了,又换一家,结果配置文件里散落着好几套 Key 和地址,排查问题时根本不知道当前生效的是哪个。
我的做法是:把所有模型请求统一走 TaoToken 的 API 通道。TaoToken 提供兼容 OpenAI 协议的接口,Base URL 固定为https://taotoken.net/api,你只需要一个 Key,就能在多个模型之间切换。这样 OpenClaw 的openclaw.json里只保留一套 endpoint 配置,换模型只改 Model ID,不动地址。
具体怎么拿 Key:访问 TaoToken 官网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_medium=csdn&utm_campaign=rewrite&utm_content=,API Keys 管理页在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。创建时建议给 Key 起个能识别的名字,比如openclaw-docker,方便后面轮换。
拿到 Key 后,OpenClaw 侧需要配三个东西:Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api,注意不要带末尾斜杠,也不要带/v1——OpenClaw 的 OpenAI 兼容层会自己拼路径。API Key 就是刚才创建的那串。Model ID 填你在 TaoToken 模型列表里看到的名称,比如gpt-4o或claude-3-5-sonnet这类。如果你不确定当前有哪些模型可用,可以打开模型对话页https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=先试一条消息,确认通道通了再写进配置。
这里有个容易忽略的点:OpenClaw 的openclaw.json里,模型供应商配置和环境变量是两套东西。你可以把apiKey写成${OPENAI_API_KEY},然后在容器的环境变量里注入真实值。这样配置文件可以进 Git,Key 不会泄露。下面第 3 节的 Compose 配置里,我会把OPENAI_API_BASE和OPENAI_API_KEY都列进 environment 段。
如果你后面要跑长期编码或 Agent 任务,可以考虑 TaoToken 的 Coding Plan,入口在https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。它适合那种需要持续调用、不想每次手动换 Key 的场景。不过对于本文的容器化部署验证,先用按量 Key 就够了。
3. 可复制配置:Docker Compose + 环境变量清单
这一节是全文的核心,直接给你能跑的配置。我假设你已经有一台 Linux 主机,装好了 Docker 和 Docker Compose。目录结构建议这样:
openclaw-docker/ ├── docker-compose.yml ├── .env ├── data/ │ ├── openclaw/ # 挂载到容器 /root/.openclaw │ └── workspace/ # 挂载到容器 /root/.openclaw/workspace └── config/ └── openclaw.json # 挂载到容器 /root/.openclaw/openclaw.json先看docker-compose.yml。这里我用的是官方镜像思路,如果你自己构建镜像,把image换成你的构建标签即可。
version: "3.8" services: openclaw: image: openclaw/gateway:latest container_name: openclaw-gateway restart: unless-stopped ports: - "18789:18789" # Gateway 端口 - "18792:18792" # Browser Relay 端口(有头模式才需要) environment: - OPENAI_API_BASE=https://taotoken.net/api - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN} - TZ=Asia/Shanghai volumes: - ./data/openclaw:/root/.openclaw - ./data/workspace:/root/.openclaw/workspace - ./config/openclaw.json:/root/.openclaw/openclaw.json:ro shm_size: "1gb" # Chrome 无头模式需要,否则容易崩 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:18789/health"] interval: 30s timeout: 10s retries: 3几个关键点解释一下。shm_size必须给够,Chrome 无头模式默认用/dev/shm,容器默认只有 64MB,页面一复杂就崩,报Target closed或Session closed。给 1GB 基本够用。restart: unless-stopped保证宿主机重启后容器自动拉起,但注意这也会让“锁文件没清理”的问题在重启后立刻暴露,所以第 5 节要专门处理。
然后是.env文件,不要提交到 Git:
OPENAI_API_KEY=sk-你的TaoTokenKey OPENCLAW_GATEWAY_TOKEN=自己生成一串随机字符串OPENCLAW_GATEWAY_TOKEN可以用openssl rand -hex 32生成。这个 token 是节点接入和远程控制用的,别用弱口令。
接着是config/openclaw.json。这是 OpenClaw 的主配置,我挑和容器化最相关的部分:
{ "models": { "providers": { "openai": { "baseUrl": "${OPENAI_API_BASE}", "apiKey": "${OPENAI_API_KEY}", "model": "gpt-4o" } } }, "browser": { "enabled": true, "executablePath": "/root/.cache/ms-playwright/chromium-1208/chrome-linux64/chrome", "headless": true, "noSandbox": true, "defaultProfile": "openclaw" }, "session": { "dmScope": "per-channel-peer", "maintenance": { "mode": "enforce", "pruneAfter": "30d", "resetArchiveRetention": "1d" } }, "memorySearch": { "provider": "openai" } }注意baseUrl写的是${OPENAI_API_BASE},OpenClaw 启动时会读环境变量替换。executablePath指向 Playwright 装的 Chromium,路径里的版本号chromium-1208可能随版本变化,你要在容器里ls /root/.cache/ms-playwright/确认一下实际目录名。noSandbox: true在容器里基本是必须的,否则 Chrome 会因为权限问题起不来。
如果你用 Cline MCP 或 Codex 这类工具连 OpenClaw,配置里同样要写全三件套:Base URL 填https://taotoken.net/api,Key 填 TaoToken 的 Key,Model ID 填具体模型名。三件套缺一个,请求就会 401 或 404。
4. 验证请求:从容器启动到第一条消息
配置写好后,按顺序验证,别跳步。第一步,启动容器:
docker compose up -d docker compose logs -f openclaw日志里看到Gateway listening on 18789就算起来了。如果卡在Waiting for browser...,说明 Chrome 启动有问题,先看第 5 节。
第二步,验证 Gateway 健康检查:
curl -s http://localhost:18789/health返回{"status":"ok"}即可。如果返回 401,说明OPENCLAW_GATEWAY_TOKEN没配对,检查.env和容器环境变量是否一致。
第三步,验证模型通道。OpenClaw 有个命令行可以直接发消息:
docker exec -it openclaw-gateway openclaw agent --to main --message "你好,测试一下"如果返回正常文本,说明 TaoToken 的 Base URL 和 Key 都生效了。如果报401 Unauthorized,去 TaoToken 控制台确认 Key 没过期、额度没用完。如果报model not found,检查openclaw.json里的model字段是不是 TaoToken 支持的 Model ID。
第四步,验证浏览器工具。进容器执行:
docker exec -it openclaw-gateway openclaw browser open --profile openclaw --url https://example.com docker exec -it openclaw-gateway openclaw browser snapshot --refs aria第二条命令应该返回页面的文本和元素结构。如果报Failed to launch chrome,看下一节。
第五步,验证状态持久化。重启容器:
docker compose restart重启后再次执行第三步的发消息命令,如果之前的会话还在(openclaw sessions list能看到),说明挂载卷生效了。这一步很多人会漏,等到生产环境重启才发现会话全丢。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
这一节对照真实报错,逐条给排查路径。第一个,401 Unauthorized。最常见的原因是 Key 写错或 Base URL 带了多余路径。检查openclaw.json里baseUrl是不是https://taotoken.net/api,不要写成https://taotoken.net/api/v1。另外确认.env里的OPENAI_API_KEY没有引号、没有空格。如果用的是 TaoToken 的 Key,去 API Keys 页面确认状态是 active。
第二个,local proxy failed。这个报错通常出现在容器网络配置有问题时。OpenClaw 内部会起一个本地代理转发请求,如果容器 DNS 解析不了taotoken.net,就会报这个。排查方法:
docker exec -it openclaw-gateway curl -v https://taotoken.net/api如果 curl 也失败,说明容器网络不通,检查宿主机 DNS 和 Docker 的dns配置。如果 curl 通但 OpenClaw 报错,检查openclaw.json里有没有多余的proxy字段,把它删掉。
第三个,reading choices相关报错,完整信息通常是Cannot read properties of undefined (reading 'choices')。这是模型返回体不符合预期导致的。原因可能是 Base URL 指向了一个不兼容 OpenAI 协议的端点,或者 Model ID 填错导致返回了错误结构。确认 Base URL 是https://taotoken.net/api,Model ID 是 TaoToken 模型列表里的名称。如果还不行,用模型对话页https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=单独测一下这个模型,确认通道本身没问题。
第四个,OAuth 相关报错。如果你在 OpenClaw 里配了需要 OAuth 的通道(比如某些企业应用),报OAuth token expired或invalid_grant,说明 refresh token 失效了。这类问题在容器化场景下更常见,因为容器重启后时间戳可能跳变。解决办法是重新走一遍授权流程,并把 token 的存储路径也挂载出来,别放在容器内。
第五个,Chrome 锁文件问题。报错长这样:Failed to launch chrome: SingletonLock exists。原因是上次容器退出时 Chrome 没正常关闭,锁文件残留。解决办法是在容器启动脚本里加一行清理:
rm -rf /root/.openclaw/browser/openclaw/user-data/Singleton*你可以把这行写进docker-compose.yml的entrypoint覆盖,或者写个start.sh在启动 OpenClaw 前执行。我试过在 Compose 里用command覆盖,但官方镜像的 entrypoint 会先跑,所以更稳的做法是挂载一个自定义脚本进去。
第六个,pairing required。这是节点接入时的报错,说明设备还没配对。去 Gateway 的device/pending.json里找到配对请求,批准后移到paired.json。如果你用 CC Switch 或类似工具管理多套配置,记得每套配置的 Gateway Token 要一致,否则配对会反复失败。
6. 语义一致 CTA:把通道收口后,下一步做什么
配置跑通、报错排完,你会发现真正省心的地方在于:所有模型请求都走同一个 Base URL,Key 只有一套,换模型只改 Model ID。这就是把 endpoint 收口到 TaoToken 的价值。后面无论你是加新通道、装新技能,还是接节点,都不用再动 API 配置。
如果你还在验证阶段,建议先去模型对话页https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=把要用的模型逐个测一遍,确认可用再写进openclaw.json。如果你要长期跑编码或 Agent 任务,Coding Plan 入口在https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,适合需要稳定调用的场景。Key 管理在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。Claude Code 相关的 Anthropic 兼容配置,参考https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。
最后留一个我踩过的坑:容器化部署时,别把openclaw.json直接写在镜像里。用挂载卷覆盖,这样改配置不用重新构建镜像。但挂载时注意文件权限,容器内是 root 跑的,宿主机上的文件如果属主不对,OpenClaw 可能读不了。用chown -R 1000:1000 ./config或者直接在 Compose 里指定user都能解决。跑起来之后,先别急着加通道,把本文的验证步骤走一遍,确认模型、浏览器、持久化三样都正常,再往上叠功能。