OpenClaw本地部署指南:飞书智能体的可控调度引擎
1. OpenClaw 是什么,以及为什么值得本地部署
OpenClaw 不是一个广为人知的开源明星项目,它没有出现在 GitHub Trending 榜单上,也没有被主流技术媒体反复报道。但如果你最近在深度探索 AI 工作流自动化、特别是围绕飞书(Feishu)生态构建个人或小团队智能体(Agent)时,OpenClaw 这个名字大概率已经悄悄出现在你的终端日志里、GitHub Star 清单中,或者某位同事发来的 Slack 截图里。它不是一个“大模型”,也不是一个“聊天界面”,而是一个轻量级、可嵌入、面向飞书场景的技能调度与上下文编排引擎——你可以把它理解成飞书生态里的“Make.com + Zapier + 自定义函数”的混合体,但它的核心设计哲学是:所有逻辑必须可审计、可调试、可完全掌控在自己服务器上。
这直接解释了为什么“本地部署”是 OpenClaw 的第一关键词,而非“云托管”或“SaaS 订阅”。我第一次接触 OpenClaw 是在帮一家做跨境 SaaS 的客户做飞书多维表格自动化时。他们需要把销售线索从飞书多维表格自动同步到内部 CRM,同时触发一段基于历史数据的简要分析,并将结果以结构化卡片形式推回飞书群。用飞书自带的“机器人+多维表格联动”能实现前半段,但后半段的“分析”环节,他们拒绝调用任何外部 API——不是因为不信任,而是因为客户数据合规审计要求明确写着:“所有含 PII(个人身份信息)的数据处理环节,不得离开公司内网边界”。当时我们试了 Dify、Ollama 加飞书 Webhook 的组合,链路太长、中间状态不可见、错误日志分散在三个系统里。直到发现 OpenClaw 的skill概念:它把“调用飞书 API”、“读取 PostgreSQL 表”、“执行一段 Node.js 脚本”全部封装成原子化的、带类型签名的“技能”,然后用 YAML 文件定义它们之间的输入输出依赖。整个流程跑在一个 Docker 容器里,数据库连的是内网 PostgreSQL 实例,飞书 Token 存在本地环境变量中——整条链路像一条透明玻璃管,你一眼就能看到数据从哪来、在哪停、往哪去、卡在哪。
这就是 OpenClaw 的真实定位:它不是替代大模型的推理引擎,而是为大模型能力提供“落地接口”和“执行沙盒”的中间件。它的价值不在于“多聪明”,而在于“多可控”。所以当你在热搜词里看到“openclaw 为什么会延迟”,答案往往不是 OpenClaw 本身慢,而是你配置的某个skill在等待外部 HTTP 响应,或者 PostgreSQL 查询没加索引导致SELECT * FROM logs WHERE status = 'pending'扫了全表。它的延迟,是你整个工作流架构的诚实镜像。
关键词里反复出现的Node.js和PostgreSQL并非偶然。OpenClaw 的运行时核心是 Node.js(v18+),它用 Express 提供一个极简的 HTTP 管理端口,所有技能的注册、触发、状态查询都走这个接口;而PostgreSQL则是它唯一的、强制的持久化层——它不用 SQLite(太弱),不用 MySQL(事务语义和 JSONB 支持不如 PG),更不用 MongoDB(它需要强 Schema 来保证技能输入输出的契约)。OpenClaw 的job表里有input_data JSONB字段,output_data JSONB字段,context JSONB字段,这些字段天然适合 PostgreSQL 的 JSONB 操作符(如->>、@>),让你能在数据库层面直接写WHERE input_data->>'user_id' = 'xxx'做精准筛选,这是 MySQL 8.0 的 JSON 函数永远做不到的性能和表达力。
所以,这篇指南的出发点很朴素:不教你如何“安装一个工具”,而是带你亲手搭建一个“可审计、可调试、可随业务演进而重构”的飞书智能体基础设施。它不会承诺“一键部署”,因为真正的可控性,永远诞生于对每一步命令背后意图的理解。接下来,我们将从最底层的环境准备开始,一层一层剥开 OpenClaw 的本地部署逻辑。
2. 环境基石:Node.js 与 PostgreSQL 的“生产级”安装实录
很多教程把“安装 Node.js”和“安装 PostgreSQL”写成两行命令就完事,比如curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt-get install -y nodejs。这在个人笔记本上可能跑得通,但在一台即将承载关键业务工作流的服务器上,这种做法会埋下至少三个雷:版本漂移、权限混乱、路径污染。我见过太多次因为nvm和系统node冲突导致 OpenClaw 启动时报Error: Cannot find module 'express',也见过因为 PostgreSQL 默认监听localhost:5432却没开trust认证,导致 OpenClaw 连接数据库时卡死在connecting...状态长达 30 秒。
2.1 Node.js:选择 LTS 版本并建立稳定路径
OpenClaw 的package.json明确要求"engines": {"node": ">=18.17.0"}。这意味着你不能用 Node.js 16(已 EOL),也不能用最新的 20.x(虽兼容但未经 OpenClaw 官方测试)。我的建议是锁定Node.js 18.20.4(2024 年 7 月最新的 18.x LTS 小版本),它修复了 v18.17.0 中一个影响child_process.spawn的内存泄漏问题,而 OpenClaw 的shell类技能大量依赖此 API。
安装步骤必须绕过包管理器,直接使用官方二进制:
# 创建专用目录,避免污染 /usr/local sudo mkdir -p /opt/nodejs cd /tmp # 下载官方 Linux x64 二进制包(请务必核对官网 checksum) wget https://nodejs.org/dist/v18.20.4/node-v18.20.4-linux-x64.tar.xz tar -xf node-v18.20.4-linux-x64.tar.xz sudo cp -r node-v18.20.4-linux-x64/* /opt/nodejs/ # 创建符号链接,确保全局可用 sudo ln -sf /opt/nodejs/bin/node /usr/local/bin/node sudo ln -sf /opt/nodejs/bin/npm /usr/local/bin/npm # 验证 node -v # 应输出 v18.20.4 npm -v # 应输出 9.8.1(随 Node.js 18.20.4 绑定的版本)提示:为什么不用
nvm?因为nvm是为开发者多版本切换设计的,它通过修改PATH和 shell 函数来生效。而 OpenClaw 作为一个服务,需要由systemd或pm2启动,这些进程不会加载你的.bashrc,nvm对它们完全无效。/usr/local/bin下的硬链接才是服务进程唯一能稳定找到node的路径。
2.2 PostgreSQL:不只是安装,更是初始化与安全加固
OpenClaw 的knex配置默认使用pg驱动,它对 PostgreSQL 的连接参数极其敏感。一个常见的坑是:你按教程装好了 PostgreSQL,psql -U postgres能登录,但 OpenClaw 就是连不上,报错password authentication failed for user "openclaw"。根源往往在pg_hba.conf文件的认证规则上。
以下是我在三台不同客户服务器上验证过的、最稳妥的初始化流程:
# Ubuntu/Debian 系统(CentOS/RHEL 请替换为 yum/dnf) sudo apt update && sudo apt install -y postgresql postgresql-contrib # 启动服务并设为开机自启 sudo systemctl enable postgresql sudo systemctl start postgresql # 切换到 postgres 用户,进入 psql sudo -u postgres psql在psql交互界面中,逐行执行以下命令(不要复制粘贴一整段,因为CREATE DATABASE和CREATE USER的顺序不能错):
-- 1. 创建专用数据库(OpenClaw 会自动建表,无需手动初始化 schema) CREATE DATABASE openclaw_dev ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE template0; -- 2. 创建专用用户,并设置强密码(请替换成你自己的密码!) CREATE USER openclaw WITH PASSWORD 'Your_Strong_Password_123!'; -- 3. 授予数据库所有权(这是 OpenClaw 运行所必需的,它需要 CREATE TABLE 权限) ALTER DATABASE openclaw_dev OWNER TO openclaw; -- 4. 退出 psql \q最关键的一步来了:编辑pg_hba.conf。先找到它的位置:
sudo -u postgres psql -c "SHOW hba_file;"通常输出/etc/postgresql/*/main/pg_hba.conf。用nano或vim编辑它,在文件末尾新增一行:
# TYPE DATABASE USER ADDRESS METHOD host openclaw_dev openclaw 127.0.0.1/32 md5注意:
METHOD必须是md5,不是trust(不安全)也不是peer(只适用于本地 Unix socket)。ADDRESS必须是127.0.0.1/32,明确限定只允许本机 IPv4 连接。OpenClaw 默认配置就是连接127.0.0.1:5432,这个规则完美匹配。
保存后,必须重启 PostgreSQL 服务才能使新规则生效:
sudo systemctl restart postgresql最后,用psql命令行验证连接是否真正成功:
psql -h 127.0.0.1 -U openclaw -d openclaw_dev # 输入密码后,如果看到 openclaw_dev=# 提示符,说明一切正确 # 输入 \q 退出2.3 环境变量与路径检查:一个被严重低估的环节
OpenClaw 启动时会读取一系列环境变量,其中DATABASE_URL是核心。它的格式必须严格为:
postgresql://openclaw:Your_Strong_Password_123!@127.0.0.1:5432/openclaw_dev注意:
- 用户名、密码、主机、端口、数据库名之间用
:、@、/分隔,不能有多余空格; - 密码中如果包含特殊字符(如
@,/,:),必须进行 URL 编码(例如@编码为%40); 127.0.0.1不能写成localhost,因为在某些 DNS 解析异常的服务器上,localhost可能被解析为::1(IPv6),而 PostgreSQL 的pg_hba.conf规则只写了127.0.0.1/32,IPv6 连接会被拒绝。
我建议你创建一个.env文件来集中管理:
echo 'DATABASE_URL=postgresql://openclaw:Your_Strong_Password_123!@127.0.0.1:5432/openclaw_dev' > /opt/openclaw/.env echo 'NODE_ENV=production' >> /opt/openclaw/.env echo 'PORT=3000' >> /opt/openclaw/.env然后在启动 OpenClaw 前,用source命令加载它:
cd /opt/openclaw source .env node dist/index.js这比在systemd服务文件里写一堆Environment=行要清晰得多,也方便你在不同环境(开发/测试/生产)间快速切换。
3. OpenClaw 核心:从源码构建、配置解析到技能注册机制
OpenClaw 的官方 GitHub 仓库(https://github.com/openclaw/openclaw)目前没有发布预编译的dist目录,这意味着你无法直接npm install -g openclaw然后openclaw start。它是一个典型的“源码即产品”项目:你需要git clone,npm install,然后npm run build。这个过程看似繁琐,实则是 OpenClaw 可控性的第一道防线——你清楚地知道,你运行的每一行代码,都来自你本地磁盘上的那个 Git Commit。
3.1 源码获取与构建:理解dist/index.js的生成逻辑
首先,创建一个干净的部署目录:
sudo mkdir -p /opt/openclaw sudo chown $USER:$USER /opt/openclaw cd /opt/openclaw克隆仓库(注意:使用--depth 1只拉最新提交,节省时间和空间):
git clone --depth 1 https://github.com/openclaw/openclaw.git .现在,关键的一步来了:查看package.json里的scripts。你会发现:
"scripts": { "build": "tsc && npm run copy:assets", "copy:assets": "cp -r src/assets dist/assets" }这说明 OpenClaw 是用 TypeScript 编写的,build命令会调用tsc(TypeScript Compiler)将src/下的所有.ts文件编译成dist/下的.js文件。tsc的具体行为由tsconfig.json控制。打开它,你会看到:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020", "DOM"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true } }"target": "ES2020"是重点。它意味着编译后的 JavaScript 代码会使用Promise.allSettled、globalThis等 ES2020 特性。而 Node.js 18.20.4 完全支持 ES2020,所以这个配置是安全的。如果你强行把target改成ES5,虽然也能编译,但生成的代码会臃肿数倍,且knex等依赖库的现代特性可能失效。
执行构建:
npm install npm run build构建完成后,dist/目录结构如下:
dist/ ├── index.js # 入口文件,Express 服务器 ├── services/ │ ├── database.js # 数据库连接池初始化 │ └── skillRegistry.js # 技能注册中心 ├── models/ │ └── job.js # Job 模型定义 └── assets/ └── skills/ # 所有内置技能的 YAML 定义dist/index.js就是你要运行的主程序。它做了三件事:
- 读取
.env文件,初始化DATABASE_URL等环境变量; - 调用
services/database.js,用knex创建一个连接到openclaw_dev数据库的连接池; - 调用
services/skillRegistry.js,扫描dist/assets/skills/目录下的所有.yaml文件,将它们解析为内存中的技能对象。
3.2skills/目录:OpenClaw 的灵魂所在
进入dist/assets/skills/,你会看到几个 YAML 文件,比如feishu-message.yaml、postgresql-query.yaml、shell-command.yaml。每一个文件,都定义了一个“技能”。以feishu-message.yaml为例:
name: feishu-message description: Send a message to a Feishu chat or user input: chat_id: { type: string, required: true } text: { type: string, required: true } output: message_id: { type: string } status: { type: string } handler: ./handlers/feishu-message.js这个 YAML 文件定义了一个契约(Contract):
- 输入:必须提供
chat_id(字符串)和text(字符串); - 输出:会返回
message_id(字符串)和status(字符串); - 执行者:由
./handlers/feishu-message.js这个 JavaScript 文件来实现。
handler字段指向的feishu-message.js文件,其核心逻辑就是调用飞书的message/v4/sendAPI。它会从环境变量中读取FEISHU_APP_ID和FEISHU_APP_SECRET,先换取tenant_access_token,再用这个 token 发送消息。OpenClaw 本身不处理任何飞书认证逻辑,它只负责把“调用飞书 API”这个动作,包装成一个符合契约的、可复用的“积木块”。
这就是 OpenClaw 的精妙之处:它把“集成飞书”这个复杂任务,拆解成了两个独立的、可分别演进的部分:
- 技能定义(YAML):由 OpenClaw 团队维护,定义“能做什么”;
- 技能实现(JS):由你来编写或定制,决定“具体怎么做”。
所以,当你看到热搜词里有“codex对接飞书cli”、“coze工作流对接飞书”,它们的思路和 OpenClaw 是一致的:都是在抽象出一个“发送飞书消息”的能力。但 OpenClaw 的优势在于,这个能力是声明式的(YAML 描述),而不是命令式的(CLI 参数列表)。你可以用同一个feishu-message技能,在不同的工作流中,传入不同的chat_id和text,而不需要重复写一遍 curl 命令。
3.3config/default.yaml:工作流的“蓝图”与执行引擎
OpenClaw 的dist/config/default.yaml是另一个核心文件。它不定义单个技能,而是定义多个技能如何组合成一个完整的工作流(Workflow)。
一个典型的工作流配置如下:
workflows: - name: sync-sales-leads description: Sync new leads from Feishu multi-dimension table to internal CRM trigger: type: feishu.webhook config: event_type: app_ticket steps: - name: fetch-new-leads skill: feishu-table-query input: table_id: "tbl_xxx" filter: "Status = 'New'" - name: enrich-lead-data skill: http-request input: url: "https://api.internal-crm.com/enrich" method: POST body: "{{ $.fetch-new-leads.output }}" - name: send-to-crm skill: http-request input: url: "https://api.internal-crm.com/leads" method: POST body: "{{ $.enrich-lead-data.output }}" - name: notify-success skill: feishu-message input: chat_id: "oc_xxx" text: "✅ Successfully synced {{ $.fetch-new-leads.output.length }} new leads!"这个 YAML 文件描述了一个完整的事件驱动工作流:
- 触发器(trigger):监听飞书应用的
app_ticket事件(这是飞书应用首次安装时推送的凭证,常用来作为工作流的“启动开关”); - 步骤(steps):四个有序执行的步骤,每个步骤调用一个技能,并将上一步的输出(
$.fetch-new-leads.output)作为下一步的输入(body)。
{{ $.xxx.output }}这种语法是 OpenClaw 的模板引擎(基于nunjucks)提供的。它让工作流具备了数据流编排能力,而不仅仅是“技能调用列表”。这也是它区别于简单 Webhook 工具的关键。
当你运行node dist/index.js后,OpenClaw 会:
- 加载
default.yaml; - 为每个
workflow创建一个监听器(对于feishu.webhook,它会在/webhook路径上启动一个 Express 路由); - 当飞书推送事件时,它会解析事件,匹配
trigger.config.event_type,然后启动对应的工作流; - 工作流引擎会按
steps顺序,依次调用skillRegistry中注册的技能,并传递上下文数据。
理解了这个机制,你就明白了为什么 OpenClaw 的“本地部署”如此重要:default.yaml就是你整个业务逻辑的“源代码”。你可以用 Git 管理它,Code Review 它,CI/CD 流水线自动部署它。它不是藏在某个 SaaS 后台里的黑盒配置,而是和你的业务代码一样,是可版本化、可协作、可审计的第一等公民。
4. 飞书集成实战:从应用创建、Token 获取到工作流触发的完整闭环
OpenClaw 的价值,只有在与飞书真正打通后才能体现。这个过程不是简单的“填个 Webhook URL”,而是一套涉及飞书开放平台、OAuth 2.0 授权、Bot 权限、事件订阅的完整体系。很多教程在这里一笔带过,导致读者部署完 OpenClaw,却卡在“怎么让飞书把消息发给它”这一步。
4.1 在飞书开放平台创建应用:选择“企业自建应用”而非“小程序”
登录 飞书开放平台 ,点击右上角“开发者后台”,然后“创建应用”。这里有一个关键选择:
- 应用类型:必须选择“企业自建应用”。
- 应用可见范围:选择“仅本企业可见”(如果你是个人开发者,可以先选“公开”,但生产环境务必改为“仅本企业”)。
为什么不能选“小程序”?因为小程序的权限模型是面向终端用户的,它需要用户主动授权,而 OpenClaw 的工作流(如自动同步多维表格)需要的是后台服务权限,它应该以“应用”的身份,代表企业来访问数据。企业自建应用拥有app_access_token和tenant_access_token,这是调用飞书后台 API(如读取多维表格、发送群消息)所必需的。
创建应用后,你会得到:
- App ID:一个以
cli_xxx开头的字符串; - App Secret:一个很长的随机字符串(务必立即复制保存,页面刷新后将无法再次查看)。
将这两个值,连同你之前设置的DATABASE_URL,一起写入/opt/openclaw/.env:
echo 'FEISHU_APP_ID=cli_xxx' >> /opt/openclaw/.env echo 'FEISHU_APP_SECRET=xxx' >> /opt/openclaw/.env4.2 配置 Bot:赋予它“读取多维表格”和“发送消息”的权限
在应用管理后台,左侧菜单选择“机器人”,然后点击“添加机器人”。填写:
- 机器人名称:例如
OpenClaw-Automation; - 头像:可选;
- 可见范围:勾选“本企业所有成员”。
创建后,你会看到机器人的App ID(和上面的应用 ID 一样)和Verification Token(用于校验 Webhook 请求来源)、Encrypt Key(用于解密飞书推送的加密消息)。Verification Token和Encrypt Key是 OpenClaw 接收飞书事件的“钥匙”。
接下来是最重要的一步:配置权限。点击左侧菜单“权限管理”,然后“添加权限”。你需要勾选:
- 通讯录→
contacts:user:readonly(读取用户信息,用于 @ 某人); - 消息→
im:message:send(发送消息); - 多维表格→
bitable:base:readonly(读取多维表格基础信息); - 多维表格→
bitable:table:readonly(读取具体表格数据); - 多维表格→
bitable:record:readonly(读取具体记录); - 多维表格→
bitable:record:write(写入记录,如果你的工作流需要回写)。
注意:
bitable:base:readonly是必须的,否则 OpenClaw 无法列出你企业下的所有多维表格。很多用户卡在这里,以为只要table:readonly就够了,其实不然。
配置完权限,必须点击右上角的“提交审核”按钮。飞书会进行一个自动审核(通常几秒钟),审核通过后,权限才真正生效。此时,你的机器人就拥有了访问指定数据的合法身份。
4.3 设置 Webhook:让飞书事件精准投递到 OpenClaw
OpenClaw 默认监听http://localhost:3000/webhook。但飞书只能向公网地址发送请求,所以你需要一个内网穿透方案。切记:不要用 ngrok 或其他公共隧道服务,因为它们会暴露你的Verification Token和Encrypt Key。最安全、最可控的方式是使用Cloudflare Tunnel。
首先,在你的服务器上安装cloudflared:
# Ubuntu/Debian curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb sudo dpkg -i cloudflared.deb然后,登录 Cloudflare Dashboard,进入你的域名的 “Access” → “Tunnels”,点击 “Create a tunnel”。按照向导操作,最终你会得到一个cert.pem文件和一个tunnel-id。
创建一个隧道配置文件/opt/openclaw/cloudflared.yml:
tunnel: your-tunnel-id credentials-file: /root/.cloudflared/your-tunnel-id.json ingress: - hostname: webhook.yourdomain.com service: http://localhost:3000/webhook originRequest: httpHostHeader: webhook.yourdomain.com - service: http_status:404在 Cloudflare DNS 设置中,为webhook.yourdomain.com添加一条 A 记录,指向192.0.2.1(Cloudflare 的任意 IP,它会自动代理)。
启动隧道:
cloudflared --config /opt/openclaw/cloudflared.yml tunnel run现在,https://webhook.yourdomain.com就是你的 OpenClaw Webhook 公网入口。
回到飞书开放平台,在“事件订阅”页面:
- 启用事件订阅:打开开关;
- URL:填写
https://webhook.yourdomain.com(注意是https,不是http); - Verification Token:填写你在机器人页面看到的
Verification Token; - Encrypt Key:填写你在机器人页面看到的
Encrypt Key; - 订阅事件:勾选
im.message.receive_v1(接收消息)、bitable.record.create_v1(新建记录)、bitable.record.update_v1(更新记录)等你需要的事件。
点击“验证”,飞书会向你的 URL 发送一个 GET 请求,OpenClaw 会自动响应,完成握手。
4.4 编写第一个工作流:监听多维表格新建记录并发送通知
现在,万事俱备。让我们用一个最简单的例子,验证整个链路。
在/opt/openclaw/dist/config/default.yaml中,添加一个新的workflow:
- name: notify-on-new-record description: Notify admin when a new record is created in a specific bitable trigger: type: feishu.webhook config: event_type: bitable.record.create_v1 steps: - name: get-table-info skill: feishu-table-query input: table_id: "tbl_xxx" # 替换为你的真实多维表格 ID record_id: "{{ $.trigger.payload.event.object_key }}" - name: send-notification skill: feishu-message input: chat_id: "oc_xxx" # 替换为你想通知的群聊 ID text: "🔔 新线索已录入!\n姓名:{{ $.get-table-info.output.fields.姓名 }}\n电话:{{ $.get-table-info.output.fields.电话 }}"这个工作流的意思是:
- 当飞书多维表格中新建一条记录时,触发;
- 第一步,用
feishu-table-query技能,根据event.object_key(即新记录的 ID)去查这条记录的详细信息; - 第二步,用
feishu-message技能,把记录里的“姓名”和“电话”字段,拼成一条通知消息,发送到指定群聊。
要获取table_id和chat_id,你需要:
table_id:打开你的多维表格,URL 里https://[region].feishu.cn/base/[base_id]/table/[table_id]这部分;chat_id:在飞书客户端,右键点击目标群聊,选择“复制群聊 ID”。
保存default.yaml,然后重启 OpenClaw:
cd /opt/openclaw source .env npm run build node dist/index.js现在,去你的多维表格里手动新建一条记录。几秒钟后,你应该就能在目标群聊里看到那条格式化的通知消息。
提示:如果没收到,第一时间检查 OpenClaw 的终端日志。最常见的错误是
feishu-table-query技能找不到table_id,或者feishu-message技能的chat_id格式错误(应该是oc_xxx开头,不是群聊名称)。
5. 生产就绪:进程守护、日志管理与常见故障排查链路
一个能跑通 Demo 的 OpenClaw 和一个能 7x24 小时稳定运行的 OpenClaw,中间隔着一套完整的运维体系。很多用户在本地测试成功后,一放到服务器上就“失联”,问题往往不出在 OpenClaw 本身,而出在进程管理、日志缺失和网络配置上。
5.1 使用 systemd 进行进程守护:告别 nohup 和 &
nohup node dist/index.js &是初学者的权宜之计,它无法处理进程崩溃后的自动重启、无法优雅地停止服务、无法统一管理日志。Linux 的标准答案是systemd。
创建服务文件/etc/systemd/system/openclaw.service:
[Unit] Description=OpenClaw Automation Service After=network.target postgresql.service [Service] Type=simple User=your-username WorkingDirectory=/opt/openclaw EnvironmentFile=/opt/openclaw/.env ExecStart=/usr/local/bin/node dist/index.js Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=openclaw [Install] WantedBy=multi-user.target关键点解析:
After=postgresql.service:确保 PostgreSQL 启动后再启动 OpenClaw,避免因数据库未就绪而启动失败;User=your-username:指定运行用户,绝对不要用 root;EnvironmentFile=:直接加载你的.env文件,比在ExecStart里写一堆--env参数干净;Restart=always:进程崩溃后,systemd会自动重启它;RestartSec=10:崩溃后等待 10 秒再重启,避免频繁崩溃导致雪崩;StandardOutput=journal:将 stdout/stderr 输出到journalctl,这是 Linux 最标准的日志收集方式。
启用并启动服务:
sudo systemctl daemon-reload sudo systemctl enable openclaw sudo systemctl start openclaw验证服务状态:
sudo systemctl status openclaw # 应该显示 active (running)5.2 日志管理:用 journalctl 构建可观测性
systemd的日志是结构化的,journalctl是你的最佳搭档。不要用tail -f /var/log/syslog,那里面信息太杂。
常用命令:
sudo journalctl -u openclaw -f:实时跟踪 OpenClaw 日志(-f表示 follow);sudo journalctl -u openclaw --since "2024-07-01":查看今天的所有日志;sudo journalctl -u openclaw -p err:只看 ERROR 级别日志;sudo journalctl -u openclaw -n 100:查看最近 100 行日志。
OpenClaw 的日志级别很友好,它会在关键节点打日志:
INFO: Workflow 'notify-on-new-record' triggered by event bitable.record.create_v1;DEBUG: Executing skill 'feishu-table-query' with input ...;ERROR: Skill 'feishu-message' failed: Error: Request failed with status code 400。
当遇到问题时,你的第一反应不应该是“OpenClaw 坏了”,而是sudo journalctl -u openclaw -p err --since "5 minutes ago"。90% 的问题,日志里都有明确的错误信息和堆栈。
5.3 故障排查链路:一个真实案例的完整复盘
上周,一位客户报告:“OpenClaw 一直收不到飞书的bitable.record.create_v1事件,但im.message.receive_v1可以收到。” 这是一个典型的、需要系统性排查的问题。我们的排查链路如下:
Step 1:确认飞书端事件是否发出
- 登录飞书开放平台 → “事件订阅” → 查看“事件推送记录”。
- 发现
bitable.record.create_v1的推送状态是Failed,错误信息是Connection refused。 - 结论:飞书根本没连上你的服务器,问题出在网络层。
Step 2:确认 Cloudflare Tunnel 是否健康
- 在服务器上执行
sudo systemctl status cloudflared(假设你用 systemd 管理 tunnel)。 - 发现
cloudflared服务是inactive (dead)。 - 手动启动