引言
最近, OpenClaw 可用说是遍地开花。
从最初的小范围讨论, 到 GitHub 上的持续增长, 再到各个社区里不断刷屏, 越来越多的人开始把它当成下一代 AI Agent 基础设施来看待。有人在惊叹它的能力, 有人在研究它的架构, 也有人开始焦虑——担心自己会不会错过这一波。
但说实话, 技术浪潮从来不会因为焦虑而停下。
那么既然打不过那就加入, 本文主要讲解如何在本地通过 Docker 来部署一个 openClaw...
一、编译 Docker 镜像
Docker 的下载安装就不展开了, 这里直接问 AI 或者查阅 官网 就行.
1.1 构建镜像
这边直接使用 OpenClaw 官方 提供的构建脚本来
- 先把
OpenClaw仓库拉到本地来
git clone https://github.com/openclaw/openclaw.git
- 执行构建脚本: 进入仓库并执行构建镜像脚本
docker-setup.sh
cd openclaw
./docker-setup.sh
⌛️ 等待构建...
1.2 配置 OpenClaw
上面脚本, 在构建完成后, 会出现一个可交互命令, 我们需要根据提示完成相关基础配置:
- 首先是安全告知: 提示风险, 这边选择
Yes开始
- 配置模式选择: 这边有两种安装模式分别是
QuickStart(快速开始)和Manual(手动), 这里我们选择QuickStart(快速开始), 它们两点区别就是如果选择Manual(手动)很多默认配置信息都要我们进行配置、确认(配置起来会更繁琐点, 要填写的内容更多)
这边如果我们之前构建过镜像并且有过配置, 则会在 ~/.openclaw 内生成一份缓存。那么到这一步就会有提示「是否复用、或者重置」, 具体效果没试过, 了解下即可。
- 模型配置(
Model/auth provider): 我这边打算使用CodeX订阅账号, 所以选择了openAI, 如果没有可直接跳过, 后续手动配置即可
下面选择鉴权方式: 这里我选的是 OpenAI Codex (ChatGPT OAuth) (Browser sign-in)
浏览器登录鉴权: 这里会吐出一个鉴权的链接, 直接复制到浏览器, 按照提示完成登录即可
登录鉴权成功后这边会, 会重定向回来, 这时直接把 URL 复制到终端中, 并回车即可
校验通过则会让选择默认模型, 这边我直接选择最新的 Gpt-5.4
- 接下来会让选择频道以及网页搜索配置, 这边我先直接跳过「
Skip for now」
Skill配置: 直接选择No先跳过
Enable hooks?不知道干嘛的, 直接空格选择Skilp for now, 会车跳过
- 接下来等待完成即可
- 最后这边会直接运行容器, 我们可以直接通过
docker ps来查看
在我们进行配置的时候其实镜像已经构建完成, 后面的配置其实是运行容器并执行了什么初始化命令。
二、尝试访问
在输出日志(往上翻)中可以看到 OpenClaw 的 Web 页面访问信息
但是当你真的在浏览器访问 http://127.0.0.1:18789/#token=xxxxxxxx 会发现好像并不能登录
会发现抛 pairing required 错误, 这是因为 OpenClaw Gateway 会对访问的浏览器/设备进行权限控制, 当未经授权的浏览器/设备访问时系统会抛出 disconnected (1008): pairing required 错误。
这是 OpenClaw 的安全配对机制在起作用, 有点类似于 SSH 的已知主机验证, 确保只有授权过的设备能访问你的网关。这是一种 零信任 的安全模型, 确保每个连接设备都是经过验证的。
核心原理: OpenClaw 采用基于设备的访问控制模型, 当任何客户端(浏览器、CLI、手机 App 或 Node 节点)首次连接到 Gateway 时:
- 设备识别:
Gateway会先生成唯一的设备身份标识 - 请求创建: 会创建待审批的配对请求(
Pending Request) - 连接挂起: 接下来连接会被挂起, 等待管理员进行批准
- 超时断开: 当等待批准的请求超过
30秒未被批准, 请求则会失效, 需要客户端再次发起连接请求
那么问题也就很明显了, 下面我们来将我们的设备添加到 OpenClaw 可信名单中:
- 进入容器内部
docker ps # 查看当前容器, 目前是查看容器 ID
docker exec -it def1c5e769b0 bash # 进入容器内
# | | |
# | | └─ 在容器内执行的命令(启动 bash shell)
# | └─ 容器 ID / 名称(目标运行中的容器)
# └─ 参数组合:
# -i:保持标准输入(可交互)
# -t:分配伪终端(TTY),用于终端显示
- 在终端中执行以
openclaw devices list来查看设备列表信息: 如下所示,Pending (1)列表则是目前挂起的设备连接请求, 也是等待我们批准的可信设备列表。若Pending (1)列表为空, 则说明请求已过期, 需刷新浏览器重新触发配对
$ openclaw devices list
🦞 OpenClaw 2026.3.14 (unknown) — We ship features faster than Apple ships calculator updates.
Pending (1)
┌─────────────────┬───────────────┬──────────┬──────────────────────────────────────────────────────┬────────────┬──────────┬────────┐
│ Request │ Device │ Role │ Scopes │ IP │ Age │ Flags │
├─────────────────┼───────────────┼──────────┼──────────────────────────────────────────────────────┼────────────┼──────────┼────────┤
│ e82d56fxxxxxd86 │ 5acccccccce76 │ operator │ operator.admin, operator.approvals, operator. pairing│ 172.25.0.1 │ just now │ │
└─────────────────────────────────┴──────────┴──────────────────────────────────────────────────────┴────────────┴──────────┴────────┘
Paired (1)
┌──────────────────────────┬────────────┬────────────────────────────────────────────────────────────────────────────────────────┬────────────┬────────────┐
│ Device │ Roles │ Scopes │ Tokens │ IP │
├──────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────────────────────┼────────────┼────────────┤
│ b71c1232132132137330c1 │ operator │ operator.admin, operator.read, operator.write, operator.approvals, operator. pairing │ operator │ │
└──────────────────────────┴────────────┴────────────────────────────────────────────────────────────────────────────────────────┴────────────┴────────────┘
- 批准指定设备: 复制批准的
Request ID(上表中的第一列)例如4f9db1bd-a1cc-4d3f-b643-2c195262464e, 并执行openclaw devices approve [Request ID]来批准设备
$ openclaw devices approve 4f9db1bd-a1cc-4d3f-b643-2c195262464e
# 成功信息:
✓ Approved device 4f9db1bd-a1cc-4d3f-b643-2c195262464e (browser)
Access granted. Device can now connect to Gateway.
- 最后选择重新连接, 进入
OpenClaw开始聊天
- 本以为这样就行了, 但是如上图所示, 居然还要进行
CodeX授权
三、CodeX 授权
直接根据官方文档 Config-Snippet-Codex 进行配置...
- 重新进入容器内部
docker ps # 查看当前容器, 目前是查看容器 ID
docker exec -it def1c5e769b0 bash # 进入容器内
# | | |
# | | └─ 在容器内执行的命令(启动 bash shell)
# | └─ 容器 ID / 名称(目标运行中的容器)
# └─ 参数组合:
# -i:保持标准输入(可交互)
# -t:分配伪终端(TTY),用于终端显示
- 如下官方给出两个授权登录的命令
# Run Codex OAuth in the wizard
openclaw onboard --auth-choice openai-codex
# Or run OAuth directly
openclaw models auth login --provider openai-codex
- 这里我用的是第二种方式: 鉴权方式和上文构建镜像配置模型的鉴权方式是一样的, 都是通过浏览器链接来完成鉴权; 执行
openclaw models auth login --provider openai-codex将命令返回的链接在浏览器进行打开并进行授权
登录鉴权成功后这边会, 会重定向回来, 这时直接把 URL 复制到终端中, 并回车即可
- 最后容器会重启
- 重启后重新访问
OpenClaw能够进行正常对话, 就算大功告成咯
四、目录
OpenClaw 的 Home 目录在 ~/.openclaw 下, 下面是其目录结构、以及每个目录的大体作用
~/.openclaw
.
|-- agents # 每个 Agent 的运行态数据(状态 + 配置 + 会话)
| `-- main # 默认 agent(agentId = main)
| |-- agent
| | |-- auth-profiles.json # 模型/API 认证信息(API Key / OAuth 等)
| | `-- models.json # 当前 agent 可用模型配置(provider / model 列表)
| `-- sessions
| |-- *.jsonl # 对话历史(按 sessionId 存储,JSONL 逐条消息)
| `-- sessions.json # 会话索引/元数据(session 生命周期、映射关系)
|-- canvas
| `-- index.html # Web UI 前端入口(本地可视化界面)
|
|-- completions # Shell 自动补全脚本
| |-- openclaw.bash # bash 补全
| |-- openclaw.fish # fish 补全
| |-- openclaw.ps1 # PowerShell 补全
| `-- openclaw.zsh # zsh 补全
|
|-- cron
| `-- jobs.json # 定时任务配置(类似 agent 的“自动执行计划”)
|
|-- devices # 设备配对(多端登录/控制)
| |-- paired.json # 已信任设备列表
| `-- pending.json # 待确认设备(pairing 流程中)
|
|-- identity # 当前节点/设备身份
| |-- device-auth.json # 设备认证信息(token / 密钥)
| -- device.json # 设备基本信息(nodeId、名称等)
|-- logs # 日志目录
| -- config-audit.jsonl # 配置变更审计日志(谁改了什么配置)
|-- openclaw.json # ⭐ 主配置文件(最核心:模型/网关/安全/渠道等) :contentReference[oaicite:0]{index=0}
|-- openclaw.json.bak* # 配置文件自动备份(历史版本回滚用)
|-- update-check.json # 更新检查缓存(版本信息、更新时间等)
`-- workspace # ⭐ Agent“灵魂层”(提示词 + 行为定义)
|-- AGENTS.md # 多 Agent 路由/策略(如何分配任务)
|-- BOOTSTRAP.md # 启动提示词(初始化上下文)
|-- HEARTBEAT.md # 周期性检查/自检逻辑
|-- IDENTITY.md # Agent 身份(名字、人设、角色)
|-- SOUL.md # 性格/语气/风格(核心人格定义)
|-- TOOLS.md # 工具使用规范(如何调用工具/API)
`-- USER.md # 用户画像(偏好、背景,让 agent 更懂你)
而我们上文配置的模型信息就存在 .openclaw/agents/main/agent/auth-profiles.json 中, 下面是具体的内容:
$ cat .openclaw/agents/main/agent/auth-profiles.json
{
"version": 1,
"profiles": {
"openai-codex:default": {
"type": "oauth",
"provider": "openai-codex",
"access": "ey*******************uYM",
"refresh": "rt_GVwk*******ns",
"expires": 112111112336656
}
},
"usageStats": {
"openai-codex:default": {
"errorCount": 0,
"lastUsed": 17712132312312386
}
}
}