本文记录一次完整的 OpenClaw 部署过程:
使用 Ubuntu Server 24.04,以 Docker Compose 管理 OpenClaw,将服务部署到一台内网主机,再通过另一台反向代理主机对外提供 HTTPS 访问。

文中的以下信息均已脱敏:

  • 安装路径
  • 内网 IP
  • 对外域名
  • 宿主机发布端口

但是部署逻辑、命令顺序、踩坑过程都保留了,照着改成自己的值即可复现。


一、部署目标

目标架构如下:

  • OpenClaw 运行在一台 Ubuntu Server 主机上
  • 使用 Docker Compose 管理
  • 数据目录固定在自定义路径下
  • 服务只监听一个宿主机端口
  • 前面放一台独立的反向代理主机
  • 外部通过 HTTPS 域名访问
  • Gateway 只允许可信反代访问,避免被局域网其他机器直接绕过反代访问

二、环境信息

本文部署环境:

  • 系统:Ubuntu Server 24.04
  • Docker:Docker Engine + Docker Compose v2
  • OpenClaw:官方仓库 Docker 方案
  • 运行方式:Docker Compose
  • 反向代理:另一台局域网主机负责 HTTPS 终止和 WebSocket 转发

脱敏后的示例变量如下:

INSTALL_DIR=/opt/docker/openclaw
CONFIG_DIR=/opt/docker/openclaw/data/config
WORKSPACE_DIR=/opt/docker/openclaw/data/workspaceHOST_IP=192.168.100.10
REVERSE_PROXY_IP=192.168.100.20
HOST_PORT=10443PUBLIC_DOMAIN=openclaw.example.com

实际部署时,把这些替换成自己的值。


三、最终拓扑

最终结构如下:

浏览器
↓ HTTPS / WSS
https://openclaw.example.com

反向代理主机(REVERSE_PROXY_IP)
↓ 反代到
http://HOST_IP:HOST_PORT

OpenClaw Gateway(Docker 容器内固定监听 18789)

四、为什么选择 Docker Compose

OpenClaw 官方本身就提供 Docker 方式,适合以下场景:

  • 希望安装与宿主机环境隔离
  • 不想在宿主机直接安装整套运行依赖
  • 后续只想通过 docker compose up / stop / restart 管理
  • 想明确掌控数据目录与容器生命周期

对我来说,Docker Compose 的优势主要在于:

  • 安装目录固定
  • 数据可持久化
  • 重建容器不会丢配置
  • 后续维护简单

五、准备工作

先安装基础组件:

apt update
apt install -y git curl screen

如果系统尚未安装 Docker 和 Docker Compose,需要先安装它们。


六、拉取 OpenClaw 仓库

mkdir -p /opt/docker
cd /opt/docker
git clone https://github.com/openclaw/openclaw.git
cd /opt/docker/openclaw

七、创建自定义数据目录

mkdir -p data/config data/workspace

这里的目的很明确:
不要把配置散落在默认目录,而是明确固定在安装路径下。


八、准备 .env

先写一份 .env

cat > .env <<'EOF'
OPENCLAW_CONFIG_DIR=/opt/docker/openclaw/data/config
OPENCLAW_WORKSPACE_DIR=/opt/docker/openclaw/data/workspace
OPENCLAW_GATEWAY_PORT=10443
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_TZ=Asia/Tokyo
EOF

这里有一个非常重要的坑,后面会专门讲:

只提前写 .env 还不够。
官方 setup.sh 运行时,会优先读取当前 shell 环境变量,再把值回写到 .env
如果你只是手工写了 .env,却没有在执行脚本时传入环境变量,脚本仍可能按默认值运行,并覆盖你写的内容。


九、删除 bridge 端口映射,只保留 Gateway 端口

官方当前 docker-compose.yml 里通常还会保留一个历史 bridge 端口映射,但当前版本实际上已经不再使用 TCP bridge。

所以可以直接删掉那一行,只保留 Gateway 端口:

sed -i '/OPENCLAW_BRIDGE_PORT/d' docker-compose.yml

确认结果:

grep -n 'OPENCLAW_GATEWAY_PORT\|OPENCLAW_BRIDGE_PORT' docker-compose.yml

正常情况下应只剩下一行:

"${OPENCLAW_GATEWAY_PORT:-18789}:18789"

这行没有问题。它的含义是:

  • 左边:宿主机端口
  • 右边:容器内端口
  • 如果环境变量 OPENCLAW_GATEWAY_PORT 有值,就用它
  • 如果没有,就回退到默认 18789

例如:

10443:18789

表示宿主机监听 10443,容器内部仍监听 18789


十、正确执行安装脚本

错误思路

很多人会这样做:

./scripts/docker/setup.sh

这样做不一定会吃到你手工写进去的 .env 端口值

正确思路

应该在执行安装脚本时,直接把环境变量传进去:

OPENCLAW_CONFIG_DIR=/opt/docker/openclaw/data/config \
OPENCLAW_WORKSPACE_DIR=/opt/docker/openclaw/data/workspace \
OPENCLAW_GATEWAY_PORT=10443 \
OPENCLAW_GATEWAY_BIND=lan \
OPENCLAW_TZ=Asia/Tokyo \
./scripts/docker/setup.sh

这一步非常关键。
因为官方脚本会把当前环境变量当作来源,再写回 .env


十一、安装过程中的选择建议

执行 ./scripts/docker/setup.sh 后,会进入一个交互式流程。

1. 是否继续(个人使用 / 多用户提示)

选:

  • Yes

因为这里本质是在确认你知道它默认更偏向个人使用场景。


2. Setup mode

选:

  • QuickStart

原因:

  • 先把服务装起来
  • 后续再补配置
  • 不需要一开始把所有功能都配满

3. Model/auth provider

如果只是先把网关跑通,可以选:

  • Skip for now

因为 provider 后面可以再配,不影响 Docker 主服务先启动。


4. Filter models by provider

选:

  • All providers

这一步只是模型筛选器,不是必须项。


5. Search provider

选:

  • Skip for now

Web Search 后面单独配置即可,不影响当前安装。


6. Configure skills now?

选:

  • No

先跑通服务,不在 onboarding 阶段展开额外依赖。


7. Hooks

选:

  • Skip for now

这些都不是基础启动必须项。


十二、一个容易误判的点:/app/home/node/.openclaw

安装日志中会看到类似:

WORKDIR /app
COPY package.json ...
RUN pnpm ...

这不是路径异常。

/app 是什么?

这是Docker 镜像构建阶段的工作目录。
它是容器镜像内部的构建目录,不是宿主机安装路径。

/home/node/.openclaw 是什么?

这是容器运行时的配置目录。
OpenClaw 会把宿主机的自定义目录挂载到这里。

所以这两类路径完全不是一回事:

  • /app:构建镜像时用
  • /home/node/.openclaw:运行服务时用

十三、SSH 断线怎么办

第一次构建很慢,中途如果 SSH 断开,前台构建通常就中断了。

所以强烈建议在 screentmux 中执行。

screen

启动:

screen -S openclaw

在里面执行安装:

cd /opt/docker/openclaw
OPENCLAW_CONFIG_DIR=/opt/docker/openclaw/data/config \
OPENCLAW_WORKSPACE_DIR=/opt/docker/openclaw/data/workspace \
OPENCLAW_GATEWAY_PORT=10443 \
OPENCLAW_GATEWAY_BIND=lan \
OPENCLAW_TZ=Asia/Tokyo \
./scripts/docker/setup.sh

临时离开但不中断任务:

Ctrl + A,然后按 D

重新接回:

screen -r openclaw

如果只是想共享查看:

screen -x openclaw

区别:

  • screen -r:接回会话
  • screen -x:共享附加进去

十四、安装完成后的关键输出

安装成功后,一般会看到类似:

  • Gateway 已启动
  • 生成了 token
  • 提示 dashboard 地址
  • 显示 docker compose logs -f openclaw-gateway
  • 显示 health 检查命令

此时不要急着结束,还需要继续做一件事:

检查实际发布的宿主机端口是不是你想要的那个。


十五、如果安装后端口仍然是默认值

可能会出现这种情况:

docker compose ps

输出类似:

0.0.0.0:18789->18789/tcp

这说明脚本还是按默认值跑了,没有用你想要的宿主机端口。

修正方法

先改 .env

sed -i 's/^OPENCLAW_GATEWAY_PORT=.*/OPENCLAW_GATEWAY_PORT=10443/' .env
grep '^OPENCLAW_GATEWAY_PORT=' .env

然后强制重建容器:

docker compose up -d --force-recreate openclaw-gateway

再检查:

docker compose ps

正常结果应类似:

0.0.0.0:10443->18789/tcp

十六、健康检查

确认服务是否真正起来:

curl -fsS http://127.0.0.1:10443/healthz
curl -fsS http://127.0.0.1:10443/readyz

正常返回:

{"ok":true,"status":"live"}
{"ready":true}

这时就说明:

  • 端口正确
  • 容器已运行
  • Gateway 已就绪

十七、配置反代相关参数

如果你的 OpenClaw 不只是本机访问,而是要通过反向代理给域名提供服务,那么必须补以下配置:

  • gateway.mode=local
  • gateway.bind=lan
  • gateway.controlUi.allowedOrigins
  • gateway.trustedProxies

示例:

docker compose run --rm openclaw-cli config set --batch-json '[
{"path":"gateway.mode","value":"local"},
{"path":"gateway.bind","value":"lan"},
{"path":"gateway.controlUi.allowedOrigins","value":["https://openclaw.example.com","http://192.168.100.10:10443","http://127.0.0.1:10443"]},
{"path":"gateway.trustedProxies","value":["192.168.100.20"]}
]'

然后重启:

docker compose restart openclaw-gateway

十八、为什么要配 allowedOriginstrustedProxies

这不是可有可无。

gateway.controlUi.allowedOrigins

用于限制允许访问 Control UI 的来源。

如果你要通过浏览器从域名访问,就必须把自己的 HTTPS 域名放进去。

gateway.trustedProxies

当前面还有反向代理时,要告诉 OpenClaw:

哪台代理是可信的。

这样它才会正确处理:

  • X-Forwarded-For
  • X-Forwarded-Proto

十九、反向代理需要满足哪些条件

反向代理至少应满足以下条件:

  • 反代到 http://HOST_IP:HOST_PORT
  • 支持 WebSocket upgrade
  • 正确传递并覆盖 X-Forwarded-For
  • 正确传递 X-Forwarded-Proto
  • 对外只开放域名入口
  • 宿主机网关端口不应被其他来源直接访问

示例 Nginx 配置核心段:

location / {
proxy_pass http://192.168.100.10:10443;
proxy_http_version 1.1; proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

二十、防火墙建议

最稳的策略是:

  • 只允许反代主机访问 OpenClaw 主机的宿主机端口
  • 其他来源全部拒绝

例如用 UFW:

ufw allow from 192.168.100.20 to any port 10443 proto tcp
ufw deny 10443/tcp
ufw reload
ufw status numbered

二十一、第一次网页登录为什么会失败

第一次打开 https://openclaw.example.com 后,可能会看到连接失败。

常见原因有两个:

1. 没填 token

Web 页面里:

  • WebSocket URL 应填:
    wss://openclaw.example.com
  • Gateway Token 填安装时生成的 token
  • Password 留空

如果忘了 token:

grep '^OPENCLAW_GATEWAY_TOKEN=' .env

2. pairing required

这是第一次浏览器设备接入时常见情况,不是故障。

先查看待批准设备:

docker compose run --rm openclaw-cli devices list

会看到类似:

  • Pending (1)
  • 一个 Request ID

然后批准:

docker compose run --rm openclaw-cli devices approve <request-id>

批准后回到网页刷新,再连接即可。


二十二、设备配对记录说明

OpenClaw 不是传统的“账号系统”,更接近:

  • 一个 Gateway
  • 一组已配对设备
  • 每个设备有角色和 scopes

这意味着:

  • 同一浏览器、同一设备后续通常可以直接继续用
  • 换浏览器、清缓存、换设备,可能会出现新的 pairing 请求
  • 旧的设备记录可以删除

二十三、删除多余设备记录

查看设备:

docker compose run --rm openclaw-cli devices list

删除某个设备:

docker compose run --rm openclaw-cli devices remove <device-id>

需要注意的是:

  • 有些记录可能是初始化阶段生成的内部配对记录
  • 有些是你实际网页登录时产生的
  • 如果一个设备正在活跃连接,删掉后它可能再次出现

所以做法很简单:

  1. 先确认哪个是当前有效设备
  2. 再删掉多余设备
  3. 重新 devices list 检查结果

二十四、安装是否成功的判断标准

我认为判断是否真正完成,不看某一条日志,而看以下几项是否全部满足:

1. 容器状态正常

docker compose ps

看到:

  • healthy

2. 健康检查通过

curl -fsS http://127.0.0.1:10443/healthz
curl -fsS http://127.0.0.1:10443/readyz

3. 宿主机端口正确

看到:

0.0.0.0:10443->18789/tcp

4. 域名网页可以打开

浏览器可访问:

https://openclaw.example.com

5. WebSocket 正常连接

页面状态显示 OK,不再报 token 或 pairing 错误。


二十五、日常管理命令

后续真正常用的命令只有这些:

cd /opt/docker/openclawdocker compose up -d openclaw-gateway
docker compose stop openclaw-gateway
docker compose restart openclaw-gateway
docker compose logs -f openclaw-gateway

健康检查:

curl -fsS http://127.0.0.1:10443/healthz
curl -fsS http://127.0.0.1:10443/readyz

查看设备:

docker compose run --rm openclaw-cli devices list

批准新设备:

docker compose run --rm openclaw-cli devices approve <request-id>

删除旧设备:

docker compose run --rm openclaw-cli devices remove <device-id>

二十六、这次部署中最关键的几个坑

这次实际部署里,最容易踩坑的点有这些:

1. 以为写 .env 就够了

不够。
setup.sh 运行时优先看当前环境变量,再回写 .env

所以正确方式是:

在执行 setup.sh 时就把变量传进去。


2. 看到 /app 以为路径错了

不是。
那只是构建镜像阶段的工作目录。


3. SSH 断线导致前台构建中断

长时间构建一定要放到 screentmux 里跑。


4. 安装后端口还是默认值

这通常不是 OpenClaw 没启动,而是容器仍按默认端口发布。
.env 后强制重建容器即可。


5. 域名能打开但 Connect 报错

多数情况不是服务坏了,而是:

  • token 没填
  • pairing 还没批准

6. 设备列表里出现看不懂的已配对设备

有些是初始化阶段自动生成的,不一定是异常登录。


二十七、结论

这次部署最终达成了这些目标:

  • OpenClaw 跑在 Ubuntu Server 上
  • 使用 Docker Compose 管理
  • 数据目录固定在自定义路径
  • 宿主机只发布一个网关端口
  • 通过反代主机对外提供 HTTPS / WSS
  • 配置了可信反代与允许来源
  • Control UI 可正常登录
  • 设备配对机制正常
  • 日常维护只需要极少量命令

对我来说,这种部署方式的优点很明显:

  • 路径清晰
  • 结构清晰
  • 维护成本低
  • 不依赖宿主机额外的复杂运行环境
  • 后续扩展或迁移也更容易

如果只是个人使用,这套方案已经足够稳定。


二十八、附:一套最短可复用流程

最后把最核心的步骤压缩成一版:

mkdir -p /opt/docker
cd /opt/docker
git clone https://github.com/openclaw/openclaw.git
cd /opt/docker/openclawmkdir -p data/config data/workspacesed -i '/OPENCLAW_BRIDGE_PORT/d' docker-compose.ymlOPENCLAW_CONFIG_DIR=/opt/docker/openclaw/data/config \
OPENCLAW_WORKSPACE_DIR=/opt/docker/openclaw/data/workspace \
OPENCLAW_GATEWAY_PORT=10443 \
OPENCLAW_GATEWAY_BIND=lan \
OPENCLAW_TZ=Asia/Tokyo \
./scripts/docker/setup.shdocker compose run --rm openclaw-cli config set --batch-json '[
{"path":"gateway.mode","value":"local"},
{"path":"gateway.bind","value":"lan"},
{"path":"gateway.controlUi.allowedOrigins","value":["https://openclaw.example.com","http://192.168.100.10:10443","http://127.0.0.1:10443"]},
{"path":"gateway.trustedProxies","value":["192.168.100.20"]}
]'docker compose restart openclaw-gatewaycurl -fsS http://127.0.0.1:10443/healthz
curl -fsS http://127.0.0.1:10443/readyz

Leave a Reply

Your email address will not be published. Required fields are marked *