部署教程
VPS 部署 OpenClaw:Docker 安装、飞书接入与备份恢复实测
在 VPS 上用官方 Docker 镜像部署 OpenClaw,通过 SSH 隧道管理,接入飞书长连接与群白名单,并记录容器重建、冷备份恢复的实测结果。
开始前
电脑关机后,助手还要继续接收消息、保留对话,OpenClaw 的 Gateway 就需要一个长期在线的地方。VPS 很适合承担这个角色:服务器保存配置和工作区,电脑通过浏览器管理,日常直接在飞书里给机器人发消息。
购买前先分清两笔开销。VPS 负责运行 OpenClaw;如果接入云端模型,推理仍由模型服务商完成,通常另有调用费用。把 Gateway 放到自己的服务器,也不代表消息从此不会离开这台机器,交给云端模型的内容依然会发往对应服务商。
本文采用官方 Docker 镜像,后台通过 SSH 隧道访问,不要求域名,也不需要先折腾反向代理。2026 年 10 月 3 日,我们在一台 Debian 13 VPS 上验证了这条部署路径。下面的命令固定使用 OpenClaw 2026.9.8。
VPS 怎么选,钱该花在哪里
单人使用、主要调用云端模型,我会从 2 核、4 GB 内存的月付机器起步。这个配置是给系统、Gateway 和更新留余量的选购建议,不是官方最低要求。浏览器任务、多个会话、本地推理的开销要另算,不能凭一个空闲时的内存数字决定配置。
| 准备用它做什么 | 建议从哪里起步 | 购买前确认什么 |
|---|---|---|
| 单人聊天,调用云端模型 | 2 vCPU、4 GB 内存、40 GB SSD | 模型 API 能正常访问,磁盘还有镜像与备份空间 |
| 加入浏览器任务或更多并行工作 | 4 vCPU、8 GB 内存,再按任务增加 | 浏览器和工具的峰值占用,升级是否方便 |
| 同一台 VPS 上运行本地模型 | 根据模型、量化和上下文单独估算 | 模型权重、KV cache、推理速度,以及是否需要 GPU |
不要把“源码构建需要多少内存”当成“运行需要多少内存”。当前官方 Docker 文档要求本地源码构建至少有 6 GB RAM,小机器可以拉取官方预构建镜像,省掉编译过程。本文采用的就是后者。
网络要同时考虑两段:你到 VPS 的管理连接,VPS 到模型服务、软件仓库和消息平台的出站连接。只有第一段速度快,模型请求照样可能超时。把测试范围缩成实际要用的服务,比盯着下载测速图更有用;即使 API 域名返回 HTTP 200,也还要用自己的凭据发一次真实请求。
如果还没有机器,可以先看这两家:
雨云云服务器:想用中文控制台和文档,可以从通用云服务器 RCS 中选。它支持 Debian、Ubuntu,也提供国内和海外区域。接入哪家模型服务,就先确认该服务在所选区域可用;不要把游戏云或只有面板权限的产品当成普通 VPS 下单。推荐码为 KuZhuJi。
注册推荐码:KuZhuJi
Evoxt 虚拟机:需要比较不同地区的部署位置,可以看它的 Debian、Ubuntu 虚拟机。官网列有多个区域,也提供每周异地备份。每周一次的服务商备份无法替代自己在重要更新前做的备份。
我更建议先月付,装好后跑自己的任务,再决定是否长期续费。初次部署用不到住宅 IP,也不必为了 OpenClaw 单独购买高防套餐。真正需要核对的是系统控制权限、可用内存、磁盘余量,以及模型服务的地区与账号限制。
这次测试用了什么机器
测试机是 4 vCPU、约 8 GB 内存、40 GB 磁盘,系统为 Debian 13.7,Docker 29.8.1、Compose v5.5.1。官方镜像内实际运行 Node.js 24.21.0,不需要再在宿主机安装 Node。
| 检查项目 | 实际结果 |
|---|---|
| 镜像 | ghcr.io/openclaw/openclaw:2026.9.8,镜像修订 fc23bc8 |
| 空闲资源 | 未配模型和消息频道、浏览器工具关闭,后台已连接;约 30 秒内六次采样,内存均为 977.7 MiB |
| 后台鉴权 | 受保护的 /control-ui-config.json:无 token、错误 token 均返回 401,正确 token 返回 200;浏览器登录成功 |
| 容器重建 | 使用 --force-recreate 重建后,工作区校验文件保留 |
| 飞书插件 | 官方 @openclaw/feishu@2026.9.8 安装成功,Gateway 正常加载 |
| 冷备份恢复 | 将 Compose、.env 和完整状态目录恢复到同机独立目录;Gateway 健康,工作区文件与一台已配对设备保留,飞书插件仍可加载 |
这次没有填入模型 API Key 或飞书应用凭据,因此没有验证模型回答、飞书消息收发和忙时资源占用。后文给出接入步骤及验收方法,不能把安装成功当成机器人已经能回复。
官方镜像在这台机器上报告的大小约 4.96 GB,此外还有插件、数据库、日志与备份。40 GB 磁盘是部署建议,实际余量要看 VPS 上还运行了什么。
在 Debian 上准备 Docker
以下安装命令适用于 Debian 12、13 的新机器。如果 VPS 已经装好 Docker,直接检查版本即可;不要重复安装,更不要为了这篇教程清空现有容器。Ubuntu 用户使用 Docker 的 Ubuntu 安装说明,不要照抄 Debian 仓库地址。
先用有 sudo 权限的普通账号通过 SSH 登录。新机器的云防火墙先允许自己的管理地址访问 SSH,保持现有 SSH 会话,测试新连接能成功后再收紧规则。本方案不需要向公网放行 18789。
sudo apt update
sudo apt install -y ca-certificates curl openssl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF_DOCKER
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF_DOCKER
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo docker version
sudo docker compose version这些包和仓库地址来自 Docker 官方 Debian 安装说明。已经安装其他 Docker 或 containerd 软件包的机器,应先按该文档处理冲突包。
下面继续用 sudo docker 操作,无需把普通用户加入 Docker 组。OpenClaw 容器本身以镜像内的 node 用户运行。
把状态留在宿主机上
在普通账号的家目录创建部署目录:
mkdir -p ~/openclaw/state
cd ~/openclaw
sudo chown -R 1000:1000 state
sudo chmod 700 state
umask 077
printf 'OPENCLAW_GATEWAY_TOKEN=%s\n' "$(openssl rand -hex 32)" > .env
chmod 600 .env官方镜像使用 UID 1000。state 必须让这个 UID 能写入,首次启动会在里面创建配置和数据库。宿主机登录账号的 UID 如果不是 1000,后面的配置文件可以用 sudo tee 写入,再把属主设回 1000。
保存 compose.yaml:
services:
openclaw:
image: ghcr.io/openclaw/openclaw:2026.9.8
init: true
restart: unless-stopped
env_file:
- .env
environment:
HOME: /home/node
OPENCLAW_STATE_DIR: /home/node/.openclaw
OPENCLAW_CONFIG_PATH: /home/node/.openclaw/openclaw.json
OPENCLAW_WORKSPACE_DIR: /home/node/.openclaw/workspace
OPENCLAW_DISABLE_BONJOUR: "1"
TZ: Asia/Shanghai
volumes:
- ./state:/home/node/.openclaw
ports:
- "127.0.0.1:18789:18789"
command: ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789"]
cap_drop:
- NET_RAW
- NET_ADMIN
security_opt:
- no-new-privileges:true
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "node", "dist/docker-healthcheck.js"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s这里有两处容易混淆的监听设置。--bind lan 让 Gateway 在容器网络内接受连接;127.0.0.1:18789:18789 则让 Docker 只在宿主机回环地址发布端口。它们配合使用,SSH 隧道才能从宿主机接进容器,又不用把后台开放到公网。
不要把端口简写成 18789:18789。Docker 发布端口时可能绕过 UFW 的常规规则,不能只看 UFW 显示“已开启”就认为后台没有暴露。
接着保存 state/openclaw.json。如果使用终端直接创建,保留下面 heredoc 标记两侧的单引号:
sudo tee state/openclaw.json >/dev/null <<'EOF_CONFIG'
{
"gateway": {
"mode": "local",
"bind": "lan",
"port": 18789,
"auth": {
"mode": "token",
"token": {
"source": "env",
"provider": "default",
"id": "OPENCLAW_GATEWAY_TOKEN"
},
"rateLimit": {
"maxAttempts": 10,
"windowMs": 60000,
"lockoutMs": 300000
}
},
"controlUi": {
"allowedOrigins": [
"http://127.0.0.1:18789",
"http://localhost:18789"
]
}
},
"session": {
"dmScope": "per-channel-peer"
},
"tools": {
"profile": "messaging",
"deny": [
"group:automation",
"group:runtime",
"group:fs",
"sessions_spawn",
"sessions_send"
],
"fs": {
"workspaceOnly": true
},
"exec": {
"security": "deny",
"ask": "always"
},
"elevated": {
"enabled": false
},
"sessions": {
"visibility": "agent"
},
"agentToAgent": {
"enabled": false
}
},
"browser": {
"enabled": false,
"extensionRelay": {
"allowLegacyAuth": false
}
},
"memory": {
"search": {
"enabled": false
}
}
}
EOF_CONFIG
sudo chown 1000:1000 state/openclaw.json
sudo chmod 600 state/openclaw.jsonGateway token 引用 .env 中的值。后台登录 token、模型 API Key、飞书 App Secret 是不同的凭据,不能互相替代。
这份配置从消息用途起步,禁用了命令执行、文件读写和自动化工具,也关闭了浏览器工具与语义记忆检索,没有挂载宿主机的 Docker socket。先把模型和消息接通,再按实际任务增加权限。容器隔离与 OpenClaw 的工具沙箱是两回事,把程序装进 Docker 不会自动启用工具沙箱。
启动后先看健康状态
在部署目录运行下面的命令,检查容器和 Gateway 的状态:
sudo docker compose config --quiet
sudo docker compose pull
sudo docker compose run --rm --no-deps openclaw \
node dist/index.js config validate
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=100 openclaw首次启动会检查状态目录、准备数据库和加载插件。此时容器可能显示 Up,但 HTTP 服务还没准备好。等状态变为 healthy 后再检查:
curl -fsS http://127.0.0.1:18789/healthz
sudo docker compose exec openclaw node dist/index.js health --json
sudo docker compose exec openclaw node dist/index.js security audit/healthz 成功只说明进程已经监听。模型没配好时,Gateway 同样可以健康运行。还要完成模型接入和一次真实对话,才能判断助手是否可用。
日志会提醒 Gateway 在容器内绑定了非回环地址。结合 docker compose ps 和 ss -lnt 检查宿主机的实际发布地址,不要为了消掉提示把容器内的 lan 改成 loopback,也不要把鉴权关掉。
用 SSH 隧道打开后台
下面这条命令在自己的电脑上运行,替换服务器账号和 IP,终端保持打开:
ssh -o ExitOnForwardFailure=yes -N \
-L 127.0.0.1:18789:127.0.0.1:18789 USER@VPS_IP然后在电脑浏览器访问 http://127.0.0.1:18789/。这个地址通过 SSH 转发到 VPS,不是让电脑运行一份 OpenClaw。
在 VPS 的部署目录中获取登录 token:
sudo docker compose exec openclaw \
node dist/index.js gateway auth-token --show把输出填进登录页的 Gateway secret。这个命令会显示凭据,只在自己的终端使用,不要连同输出贴到论坛或工单。
如果页面出现设备待批准提示,先检查请求,再批准当前浏览器:
sudo docker compose exec openclaw node dist/index.js devices list
sudo docker compose exec openclaw \
node dist/index.js devices approve REQUEST_ID不要习惯性批准列表里的所有请求。Docker 转发后的连接不一定被 Gateway 当成直接回环连接,所以有 token 之后仍可能需要设备批准。
如果本机 18789 已被其他程序占用,可以把隧道的本地端口改为 28789,同时在 gateway.controlUi.allowedOrigins 中加入 http://127.0.0.1:28789,随后访问新地址。远端端口仍是 18789。
接入模型,再发第一条消息
在 VPS 上运行交互式模型配置:
sudo docker compose exec openclaw \
node dist/index.js configure --section model按向导选择自己已有账号的服务商、认证方式和模型。它需要交互式终端,别加 -T。有些服务商会要求安装对应的官方 provider 插件,按向导和该服务商的官方 OpenClaw 文档完成即可。
完成后检查目录和默认模型:
sudo docker compose exec openclaw node dist/index.js models list
sudo docker compose exec openclaw node dist/index.js models status如果配置的不是自己想用的模型,先从 models list 中确认完整名称,再设置:
sudo docker compose exec openclaw \
node dist/index.js models set PROVIDER/MODEL_ID模型名称以当前服务商目录为准,使用账号实际可调用的模型。不要只凭旧教程里的名称判断接口仍然可用。
在后台发送一句简单问题,确认它返回完整回答,然后观察日志。models status 能发现凭据和路由问题,但不加 --probe 时不等于已经发过模型请求。--probe 会产生真实请求,当前版本还要求独占状态目录;已经运行的 Docker 部署,先用后台对话验收更直观。
如果凭据使用环境变量引用,把对应变量保存在 Compose 使用的 .env 中,再重建容器让新环境生效:
sudo docker compose up -d --force-recreate openclaw仅在 SSH 终端里 export 一个变量,不代表 Compose 容器就能读取它。修改 .env 后单纯 docker compose restart 也不会重新导入环境变量。
把助手接进飞书
飞书接入采用 WebSocket 长连接:Gateway 主动连接飞书,消息沿这条连接送到 VPS。选这条路线,不需要域名、HTTPS 回调地址或内网穿透,18789 也继续只监听宿主机回环地址。服务器仍须能访问飞书的出站网络。飞书接入说明、飞书官方 SDK 的长连接说明
这里要创建的是带机器人能力的企业自建应用。飞书群里那种只有 Webhook 地址的“自定义机器人”,不能代替这套应用凭据和事件订阅。
先建应用,拿到 App ID 和 App Secret
进入 飞书开放平台,创建企业自建应用。在应用内启用机器人能力,从“凭证与基础信息”获取 App ID、App Secret。App ID 通常以 cli_ 开头;App Secret 是密钥,留在自己的配置和备份里。
在“权限管理”中按应用身份开通消息收发所需权限。先验收文字聊天,权限按用途选:
| 要做什么 | 在权限管理或事件配置中核对什么 |
|---|---|
| 接收用户私聊 | 接收用户发给机器人的单聊消息权限 |
| 在群里回应 @ 机器人 | 接收群聊中 @ 机器人的消息事件权限 |
| 让机器人回复 | 以应用身份发送消息,权限标识 im:message:send_as_bot |
| 收发图片、文件 | 再增加获取、上传图片或文件资源的权限 |
添加接收消息事件时,平台也会提示它需要的接收权限。按提示开通并检查发布后的权限状态。普通聊天用不到整套通讯录、云盘和文档管理权限,不用一次导入文档、云盘等功能的权限。
在 VPS 上安装插件、填写凭据
本文固定使用与 Gateway 同版的官方插件。先执行:
sudo docker compose exec openclaw \
node dist/index.js plugins install @openclaw/feishu@2026.9.8
sudo docker compose exec openclaw \
node dist/index.js channels login --channel feishu向导选择手动接入,国内飞书选 feishu,填写刚取得的 App ID、App Secret。先限制为自己私聊使用,群聊暂时关闭。lark 对应国际版,不能因为界面看起来相似就混用凭据或 API 域名。
当前向导也支持扫码自动创建机器人,缺少插件时会自动安装;国内飞书扫码没有反应,可以退回手动方式。
再配置长连接、事件和发布范围
回到飞书应用的“事件与回调”,选择使用长连接接收事件,添加 接收消息 im.message.receive_v1。OpenClaw 端的连接方式保持 websocket。
如果平台提示应用尚未建立长连接,先确认 Gateway 正在运行、凭据已保存,查看容器日志中的飞书连接状态,再回平台保存。不要在这个时候临时改成 Webhook 或开放后台端口。
在“版本管理与发布”创建版本,提交并完成所需审批。把自己的账号放入应用可用范围,确认版本已经发布生效,再去飞书找机器人。新增权限或事件后,也要确认变更已在发布版本中生效。还要同时确认长连接在线、自己的账号有权使用应用。
服务器上检查频道状态,并持续看日志:
sudo docker compose exec openclaw \
node dist/index.js channels status --probe
sudo docker compose logs -f --tail=100 openclaw先给机器人发一条私聊消息。采用 dmPolicy: "pairing" 时,未知用户会收到配对码,在 VPS 核对并批准自己的请求:
sudo docker compose exec openclaw node dist/index.js pairing list feishu
sudo docker compose exec openclaw \
node dist/index.js pairing approve feishu YOUR_CODE这与浏览器的 devices approve 是两套配对。扫码创建流程可能已经把自己的 open_id 写入允许列表;使用 allowlist 时,应检查允许的用户,而不是等一个不会出现的配对码。模型已经配置好、私聊能收到完整回答,才算飞书到模型这一段接通。
群聊先只放行一个群
私聊通过后,把机器人加入测试群。将以下设置合并到现有的 channels.feishu 中,保留向导生成的账号和凭据;oc_替换为自己的群ID 要换成真实群 ID:
{
"connectionMode": "websocket",
"dmPolicy": "pairing",
"groupPolicy": "allowlist",
"groupAllowFrom": ["oc_替换为自己的群ID"],
"requireMention": true,
"groupSessionScope": "group_sender",
"configWrites": false,
"renderMode": "raw",
"streaming": { "mode": "off" },
"typingIndicator": false,
"resolveSenderNames": false,
"tools": {
"doc": false,
"chat": false,
"wiki": false,
"drive": false,
"bitable": false,
"perm": false
}
}这个起步设置让普通回答使用消息文本,关闭流式卡片、输入中提示和姓名查询,也关闭文档等工作区工具。configWrites: false 限制频道里的配置修改。之后需要卡片、姓名或文档操作时,再分别打开相应功能并开通权限;文档操作还要检查前面全局的 tools.profile 与工具限制。
群 ID 是 oc_...,用户的 open_id 是 ou_...,不要混填。群 ID 可以在群设置中查看;用户 ID 可以通过待批准的私聊配对记录核对。当前版本的 groupAllowFrom 放的是允许使用的群;如果还要限制群内谁能使用,在对应 groups.<群ID>.allowFrom 填用户 ID。
requireMention: true 让群里的普通聊天不触发机器人,测试时直接 @ 它,不要只 @ 全体成员。groupSessionScope: "group_sender" 按群内发送者区分上下文;这有助于避免同事的对话混在一起,但不能拿它代替不同客户、不同组织之间的独立 Gateway。
保存后运行以下检查,再在测试群 @ 机器人发一句话:
sudo docker compose exec openclaw node dist/index.js config validate
sudo docker compose exec openclaw \
node dist/index.js channels status --probe除非确实希望它收到群里所有消息,否则不必为第一次接入开放所有群或授予读取全部群消息的权限。
已经用 Telegram 的读者
Telegram 可以作为另一条入口,默认 long polling 也不需要公开回调。通过 @BotFather 创建机器人,把 TELEGRAM_BOT_TOKEN 加入 .env,保留原有 Gateway token,然后执行:
sudo docker compose up -d --force-recreate openclaw
sudo docker compose exec openclaw \
node dist/index.js channels add --channel telegram --use-env
sudo docker compose exec openclaw node dist/index.js pairing list telegram
sudo docker compose exec openclaw \
node dist/index.js pairing approve telegram YOUR_CODE先给机器人发私聊,拿到配对码后再批准。服务器需要访问 Telegram 的出站网络,飞书的用户配对和群白名单也不会自动套用到 Telegram。
备份要带上状态,也要带上启动环境
只保存 openclaw.json,恢复不了全部对话、配对和凭据。当前版本使用 SQLite 保存重要状态,在线运行时直接复制数据库文件可能得到不一致的备份。官方备份命令能处理数据库快照;对个人部署,下面这种短暂停机的完整目录备份也容易检查。官方备份说明
在 VPS 上执行:
cd ~/openclaw
backup_file="$HOME/openclaw-$(date +%Y%m%d-%H%M%S).tar.gz"
umask 077
sudo docker compose stop
if sudo tar -czf "$backup_file" compose.yaml .env state; then
sudo chmod 600 "$backup_file"
else
sudo docker compose start
echo '备份失败,服务已重新启动;请检查磁盘与权限。' >&2
exit 1
fi
sudo docker compose start
sudo tar -tzf "$backup_file" >/dev/null
printf '备份文件:%s\n' "$backup_file"归档同时包含 Compose、.env 和 state。这样恢复时不会只拿到了引用,却把真正的环境变量凭据留在旧机器。把文件通过 SSH 取回,并存到受保护的备份位置;长期留在同一台 VPS 上,机器到期或磁盘故障时会一起丢失。
在新机器准备好 Docker 后,把备份解压到新目录,再启动:
mkdir -p ~/openclaw-restored
cd ~/openclaw-restored
sudo tar -xzf /path/to/openclaw-backup.tar.gz
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
curl -fsS http://127.0.0.1:18789/healthz解压到一套空目录,先检查自己的工作区文件、模型配置,并用 devices list 核对已配对设备,再把它作为日常实例使用。同一台机器演练恢复时,先停掉原实例,避免争抢 18789;不要把两个 Gateway 指向同一个正在写入的状态目录。
更新也沿用这个顺序:先备份,明确要升到哪个版本,改镜像标签,再 pull 和 up -d。新版本可能迁移数据库,回退时需要恢复与旧镜像匹配的状态,不能只把镜像标签改回去。
出问题时,按现象找原因
先从日志和健康状态判断故障位置,再对照下面的现象处理。
| 现象 | 先查什么 | 怎么处理 |
|---|---|---|
| 容器 Up,浏览器却连接重置 | 是否仍在首次检查、加载插件 | 看日志和健康状态,等待 ready 后再访问 |
| 日志出现 EACCES | state 目录与文件的 UID、权限 | 让 UID 1000 可写;不要用 chmod 777 掩盖问题 |
| VPS 本机健康检查成功,电脑打不开 | SSH 隧道是否仍在运行,本地端口是否冲突 | 检查隧道启动错误和访问端口 |
| 登录后显示待批准设备 | 浏览器设备请求 | 核对 devices list 后批准对应请求 |
| 后台在线,聊天返回认证或模型错误 | 模型凭据、默认模型、地区可用性 | 看 models status 与日志,再发一次真实对话 |
| .env 改了,程序仍读不到新值 | 容器是否重建 | 使用 up -d --force-recreate |
| 飞书找不到自建应用机器人 | 是否启用机器人、发布审批、应用可用范围 | 让自己的账号进入发布版本的可用范围 |
| 飞书私聊不回应,日志也没有消息事件 | 长连接、im.message.receive_v1、消息权限是否生效 | 核对开放平台与 Gateway 的频道状态 |
| 飞书收到消息却被忽略 | 私聊策略或群白名单、是否直接 @ 机器人 | 检查 pairing list feishu,区分 ou_ 用户 ID 与 oc_ 群 ID |
| 飞书能收到消息,但回复失败 | 发送消息权限、模型凭据、卡片相关错误 | 先用普通消息回复验证,再开启卡片 |
| 更新后反复退出 | 配置、数据库迁移、磁盘和内存 | 保留状态目录与日志,修复原因或恢复匹配的备份 |
