引言
最近, OpenClaw 可用说是遍地开花。
从最初的小范围讨论, 到 GitHub 上的持续增长, 再到各个社区里不断刷屏, 越来越多的人开始把它当成下一代 AI Agent 基础设施来看待。有人在惊叹它的能力, 有人在研究它的架构, 也有人开始焦虑------担心自己会不会错过这一波。
但说实话, 技术浪潮从来不会因为焦虑而停下。
那么既然打不过那就加入, 本文主要讲解如何在本地通过 Docker 来部署一个 openClaw...
一、编译 Docker 镜像
Docker 的下载安装就不展开了, 这里直接问 AI 或者查阅 官网 就行.
1.1 构建镜像
这边直接使用 OpenClaw 官方 提供的构建脚本来
- 先把
OpenClaw仓库拉到本地来
sh
git clone https://github.com/openclaw/openclaw.git
- 执行构建脚本: 进入仓库并执行构建镜像脚本
docker-setup.sh
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 可信名单中:
- 进入容器内部
sh
docker ps # 查看当前容器, 目前是查看容器 ID
docker exec -it def1c5e769b0 bash # 进入容器内
# | | |
# | | └─ 在容器内执行的命令(启动 bash shell)
# | └─ 容器 ID / 名称(目标运行中的容器)
# └─ 参数组合:
# -i:保持标准输入(可交互)
# -t:分配伪终端(TTY),用于终端显示

- 在终端中执行以
openclaw devices list来查看设备列表信息: 如下所示,Pending (1)列表则是目前挂起的设备连接请求, 也是等待我们批准的可信设备列表。若Pending (1)列表为空, 则说明请求已过期, 需刷新浏览器重新触发配对
sh
$ 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]来批准设备
sh
$ 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 进行配置...
- 重新进入容器内部
sh
docker ps # 查看当前容器, 目前是查看容器 ID
docker exec -it def1c5e769b0 bash # 进入容器内
# | | |
# | | └─ 在容器内执行的命令(启动 bash shell)
# | └─ 容器 ID / 名称(目标运行中的容器)
# └─ 参数组合:
# -i:保持标准输入(可交互)
# -t:分配伪终端(TTY),用于终端显示
- 如下官方给出两个授权登录的命令
sh
# 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 下, 下面是其目录结构、以及每个目录的大体作用
sh
~/.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 中, 下面是具体的内容:
sh
$ 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
}
}
}