OpenClaw配置详解:openclaw.json六大区块与企业级运维实践

1. OpenClaw 是什么?别被名字骗了,它根本不是“抓取工具”

很多人第一次看到OpenClaw这个名字,下意识会联想到“爬虫”“数据抓取”“网页扒取”——毕竟“Claw”(爪)这个意象太有指向性了。我刚接触它时也这么想,还特意去翻了 GitHub 仓库的 README,结果发现:OpenClaw 的核心定位压根不是做网络爬虫,而是一个面向企业级自动化运维与设备纳管的轻量级指令编排与执行框架。它不解析 HTML,不模拟浏览器,也不处理 Cookie 或 JS 渲染;它干的是更底层、更硬核的事:在 Linux 主机、网络设备(锐捷/华为/H3C)、IoT 边缘节点甚至容器环境里,安全、可控、可审计地执行预定义的命令序列,并将结构化结果回传至统一控制台

这解释了为什么全网搜索“OpenClaw”时,高频词永远是openclaw.json配置文件锐捷交换机配置命令ensp配置命令大全h3c交换机配置命令——它本质是个“命令管道”,而openclaw.json就是这个管道的“施工蓝图”。你给它一份 JSON 配置,它就按图索骥,登录设备、执行display versionshow ip interface briefdis cur,再把原始输出喂给内置的正则/JSONPath 解析器,最终吐出{ "model": "RG-S2950G", "uptime_days": 42, "cpu_usage": 12.7 }这样的干净数据。这才是它在运维团队里真正被高频使用的场景:批量采集交换机状态、自动校验防火墙策略一致性、定时抓取服务器磁盘使用率并触发告警

提示:如果你的需求是“从某电商网站抓商品价格”,OpenClaw 不是你的答案;但如果你要“每天凌晨 2 点自动登录 200 台锐捷交换机,检查 STP 根桥是否异常,并把结果发到飞书群”,那它就是目前开源生态里最贴合、最省心的选择之一。它的价值不在“能做什么”,而在“做得多稳、多省事、多可追溯”。

这也直接决定了它的配置文件设计哲学:极度强调可读性、可复用性与可审计性。一个openclaw.json文件,必须让非开发背景的网络工程师也能看懂“这段配置到底在对哪类设备执行什么操作、预期返回什么字段、失败了怎么处理”。它不像 Nginx 那样追求极致性能参数,也不像 MyBatis 那样抽象 DAO 层,它的配置就是运维人员的“操作说明书”+“检查清单”+“故障快照模板”的三合一。所以,所谓“保姆级详解”,核心不是教你怎么写 JSON 语法,而是带你理解:每一行配置背后,对应着一次真实的设备交互逻辑、一次潜在的超时风险、一次可能的数据清洗需求

我见过太多团队踩的第一个坑,就是把openclaw.json当成普通配置文件随便改——加了个空格、少了个逗号、路径写错一级,结果整个采集任务静默失败,日志里只有一句failed to parse config: invalid character。这不是 OpenClaw 的 bug,而是没吃透它“配置即契约”的设计本质。接下来,我们就从最基础的文件结构开始,一层层剥开这个看似简单、实则暗藏玄机的openclaw.json

2.openclaw.json文件骨架:6 大核心区块,缺一不可

OpenClaw 的配置文件采用严格的 JSON Schema 校验,启动时会逐字段验证。任何缺失或类型错误都会导致服务拒绝加载,这是它保障生产环境稳定性的第一道防线。一个合法的openclaw.json必须包含且仅包含以下6 个顶层键(Top-level Keys),顺序无关,但名称和结构必须精确匹配:

键名类型是否必需说明
versionstring配置文件版本号,当前唯一有效值为"1.0"。OpenClaw 未来升级时可能引入1.1,旧版配置需显式声明兼容性。
globalobject全局默认配置,所有任务继承。相当于“父类”,避免每个任务重复写超时、重试等通用参数。
devicesarray of object设备列表,每个对象描述一台待管理设备(IP、厂商、凭据、SSH 端口等)。这是 OpenClaw 的“资产清单”。
tasksarray of object任务列表,每个对象定义一组要执行的命令及解析规则。这是 OpenClaw 的“工作指令集”。
schedulesarray of object❌(但强烈建议)定时调度规则,定义任务何时执行(Cron 表达式)。无此区块则只能手动触发。
hooksobject事件钩子,定义任务成功/失败后执行的额外动作(如调用飞书 Webhook、写入本地日志、触发 Shell 脚本)。

注意:"version": "1.0"这一行绝不能省略,也不能写成"v1.0"1.0(数字类型)。OpenClaw 启动时会严格比对字符串值,不匹配直接报错退出。我曾因复制粘贴时多了一个不可见的 Unicode 字符(U+200B 零宽空格),卡了整整一个下午才定位到问题。

我们来拆解一个最小可行配置(Minimal Viable Config),它能成功连接一台本地 Linux 主机并执行uptime命令:

{ "version": "1.0", "global": { "timeout": 30, "retries": 2, "retry_delay": 5 }, "devices": [ { "name": "prod-web-01", "ip": "192.168.1.100", "vendor": "linux", "auth": { "type": "password", "username": "admin", "password": "P@ssw0rd123" } } ], "tasks": [ { "name": "check_uptime", "description": "获取服务器运行时间", "device_selector": "name == 'prod-web-01'", "commands": ["uptime"], "parsers": [ { "type": "regex", "pattern": "(\\d+) days?, (\\d+):\\d+", "fields": ["days", "hours"] } ] } ], "schedules": [ { "task_name": "check_uptime", "cron": "0 */2 * * *", "enabled": true } ] }

这个例子虽小,但已覆盖全部必需区块。关键点在于:

  • global.timeout是全局超时(秒),指单次 SSH 连接 + 所有命令执行的总耗时上限;
  • devices[].auth.type目前仅支持"password""key"(密钥认证),不支持双因子(2FA);
  • tasks[].device_selector是一个JMESPath 表达式,用于从devices数组中动态筛选目标设备。这里用name == 'prod-web-01'精确匹配,但你也可以写ip =~ '^192\\.168\\.'匹配网段;
  • parsers是 OpenClaw 最强大的能力之一:它不满足于返回原始字符串,而是强制要求你定义如何“翻译”设备输出。上面的正则"(\\d+) days?, (\\d+):\\d+"会从uptime输出中提取dayshours两个字段,最终结果是{"days": "42", "hours": "15"}

这个结构看似简单,但每个字段都牵一发而动全身。比如global.retries设为2,意味着当 SSH 连接首次失败时,OpenClaw 会等待retry_delay秒后重试,最多尝试 3 次(首次 + 2 次重试)。如果retry_delay设得太小(如1秒),在网络抖动时可能引发雪崩式重连;设得太大(如60秒),又会导致故障恢复延迟。这些细节,正是“保姆级”必须讲透的地方。

3.devices区块深度解析:设备不是 IP,而是“可交互的实体”

很多新手把devices理解为简单的“IP 地址列表”,这是最大的认知偏差。在 OpenClaw 的世界观里,一台设备 = 一个具备完整交互能力的实体(Entity),它必须携带足够信息,让 OpenClaw 能够:① 建立连接;② 识别设备类型以选择正确的命令语法;③ 处理设备特有的认证或交互流程(如交换机的enable模式)。因此,devices数组中的每个对象,远不止ippassword两个字段。

3.1vendor字段:决定一切行为模式的“基因”

vendordevices中最关键的字段,它直接绑定 OpenClaw 的内部驱动(Driver)。当前支持的vendor值及其行为差异如下表所示:

vendor 值典型设备默认端口认证流程特殊交互要求命令执行特点
"linux"CentOS/Ubuntu 服务器22SSH 密码/密钥直接执行 Bash 命令,支持管道 `
"ruijie"锐捷 RG-S2950、RG-NBS5000 系列22SSH 密码/密钥登录后需输入enable进入特权模式命令前自动添加enable,支持showdisplay
"huawei"华为 S5735、USG6000 防火墙22SSH 密码/密钥登录后需输入system-view进入系统视图命令前自动添加system-view,支持displayundo
"h3c"H3C S5130、MSR3640 路由器22SSH 密码/密钥登录后需输入system-viewhuawei,但部分命令语法微调(如display ip routing-table
"cisco"Cisco Catalyst 交换机22SSH 密码/密钥登录后需enable,再configure terminal自动分步进入,支持showconf tno

注意:vendor值必须小写且完全匹配,"Ruijie""rui jie"会导致驱动加载失败,报错unknown vendor: rui jie。OpenClaw 不做模糊匹配,这是为了杜绝因拼写错误导致的静默降级(Silent Fallback)。

举个真实案例:某客户采购了一批信锐(Netsky)交换机,其 CLI 与锐捷高度相似,但vendor字段填了"ruijie"。结果 OpenClaw 成功登录,却在执行display version后卡住——因为信锐设备在display命令后会分页提示--More--,而锐捷驱动没有处理这个分页符。最终解决方案是:联系 OpenClaw 社区提交 PR,新增"netsky"vendor 支持,并在驱动中加入send ' '(发送空格)自动翻页逻辑。这印证了一点:vendor不是标签,而是驱动行为的开关。

3.2auth认证区块:密码不是唯一选项,密钥才是生产首选

auth对象支持两种认证方式,但它们的安全等级和适用场景天差地别:

// 方式1:密码认证(仅限测试环境!) "auth": { "type": "password", "username": "admin", "password": "P@ssw0rd123" } // 方式2:密钥认证(生产环境强制要求) "auth": { "type": "key", "username": "admin", "private_key_path": "/etc/openclaw/keys/prod-web-01.key", "passphrase": "KeyPass123" }

为什么密码认证是“测试专用”?因为 OpenClaw 的配置文件本身是明文 JSON,若将密码硬编码其中,等于把服务器密码放在 Git 仓库里。任何一次误提交、一次配置备份泄露,都可能导致全线沦陷。而密钥认证将敏感信息解耦:私钥文件由系统管理员单独保管(权限600),OpenClaw 进程仅需读取路径,且passphrase(密钥口令)可由环境变量注入(OPENCLAW_KEY_PASSPHRASE),彻底避免明文暴露。

实操中,我推荐的密钥生成与部署流程:

  1. 在 OpenClaw 服务器上执行:ssh-keygen -t ed25519 -C "openclaw@prod" -f /etc/openclaw/keys/prod-web-01.key
  2. 将公钥prod-web-01.key.pub内容追加到目标服务器/home/admin/.ssh/authorized_keys
  3. 设置私钥权限:chmod 600 /etc/openclaw/keys/prod-web-01.key
  4. openclaw.json中引用路径,并通过环境变量传入口令:export OPENCLAW_KEY_PASSPHRASE="KeyPass123"

提示:private_key_path必须是 OpenClaw 进程有读取权限的绝对路径。相对路径(如./keys/key.pem)会被解析为进程启动目录下的路径,极易因 systemd 服务启动目录不同而失败。

3.3connection_options:那些被忽略的“连接细节”

除了vendorauthdevices还支持一个可选的connection_options对象,用于微调 SSH 连接行为。这是解决 80% 连接失败问题的关键:

"connection_options": { "ssh_options": [ "-o ConnectTimeout=10", "-o ServerAliveInterval=30", "-o StrictHostKeyChecking=no", "-o UserKnownHostsFile=/dev/null" ], "enable_command": "enable", "enable_password": "EnablePass123" }
  • ssh_options:直接透传给底层ssh命令。ConnectTimeout=10将连接超时从默认 30 秒缩短为 10 秒,避免因网络不通导致任务长时间挂起;ServerAliveInterval=30每 30 秒发一个保活包,防止中间防火墙断开长连接;StrictHostKeyChecking=no是生产环境大忌,仅用于测试——它跳过 SSH 主机密钥验证,存在中间人攻击风险。
  • enable_commandenable_password:专用于网络设备。锐捷/华为设备需要enable命令进入特权模式,enable_password就是该模式的密码。注意:enable_passwordauth.password是两个独立密码,前者用于特权模式,后者用于普通用户登录。

我踩过的最深的坑,是某台 H3C MSR3640 路由器启用了SSH v1协议(老旧固件),而 OpenClaw 默认使用SSH v2。连接时卡在Connecting...无响应。最终解决方案是在ssh_options中强制指定协议:"-o Protocol=2"。这再次证明:设备连接不是黑盒,每一个ssh_options参数都是与真实硬件搏斗的经验结晶

4.tasks区块实战:从“执行命令”到“构建数据管道”

如果说devices定义了“跟谁说话”,那么tasks就定义了“说什么、怎么说、听懂了什么”。它是 OpenClaw 配置中最富创造力的部分,也是最容易写出“脆弱代码”的地方。一个健壮的task,必须同时考虑:命令的幂等性、输出的不确定性、解析的鲁棒性、失败的可恢复性

4.1device_selector:用 JMESPath 实现精准设备寻址

device_selector是一个 JMESPath 表达式,作用是从devices数组中筛选出本次任务的目标设备。它的强大之处在于支持复杂逻辑,而非简单 ID 匹配:

// 场景1:匹配同一型号的所有设备(锐捷 S2950) "device_selector": "vendor == 'ruijie' && name =~ '^sw-.*-2950$'" // 场景2:排除已下线设备(通过 tags 字段标记) "device_selector": "tags[?contains(@, 'online')] | [?vendor == 'huawei']" // 场景3:按地理位置分组(假设 devices 中有 location 字段) "device_selector": "location == 'beijing-dc' && vendor == 'linux'"

注意:JMESPath 的@代表当前遍历元素,?是过滤操作符。tags[?contains(@, 'online')]表示:先取tags数组,再过滤出包含'online'字符串的项。OpenClaw 会将整个devices数组作为 JMESPath 的输入上下文。

一个反模式是滥用通配符:"device_selector": "ip != null"。这会匹配所有设备,导致一个check_uptime任务试图在 200 台交换机上执行uptime命令——而交换机根本没有这个命令,批量失败。好的device_selector应该像 SQL 的 WHERE 条件一样精确,宁可多写一行,也不贪图方便

4.2commands:命令不是字符串数组,而是“执行流水线”

commands是一个字符串数组,但它不是简单的命令列表。OpenClaw 会按顺序执行每一项,并将前一条命令的 stdout 作为下一条命令的 stdin(类似 Bash 管道)。这带来了巨大灵活性,也埋下了陷阱:

"commands": [ "show interfaces status | include up", "awk '{print $1, $5}'", "sort -k2,2nr" ]

这段配置的意图是:在锐捷交换机上,列出所有up状态的接口,并按速率(第5列)降序排列。但问题在于:show interfaces status的输出在不同固件版本中列数可能变化(如新版本多了一列Description),awk '{print $1, $5}'会因列偏移失效。

更鲁棒的写法是放弃管道,改用 OpenClaw 的parsers分阶段处理:

"commands": ["show interfaces status"], "parsers": [ { "type": "regex", "pattern": "(\\S+)\\s+\\S+\\s+\\S+\\s+\\S+\\s+(up|down)\\s+.*", "fields": ["interface", "status"] }, { "type": "filter", "condition": "status == 'up'", "output": "interface" } ]

这里,regex解析器先提取所有接口名和状态,filter解析器再筛选出status == 'up'的记录,并只输出interface字段。整个过程不依赖列位置,只依赖文本模式,抗版本变更能力极强。

4.3parsers:OpenClaw 的灵魂,从“原始输出”到“结构化数据”

parsers是 OpenClaw 区别于其他运维工具的核心。它强制你思考:“我要的到底是什么数据?它在原始输出中以什么形式存在?” 支持三种解析器类型:

4.3.1regex:正则表达式,处理非结构化文本

适用于showdisplay等命令的输出。关键技巧:

  • 捕获组命名"pattern": "(?<interface>\\S+)\\s+(?<status>up|down)",比位置索引fields: ["interface", "status"]更清晰;
  • 多行匹配"flags": ["m"]启用多行模式,^$匹配每行首尾;
  • 贪婪控制:用.*?替代.*避免跨行匹配错误。
4.3.2jsonpath:处理设备返回 JSON 的场景

某些现代设备(如部分华为防火墙 API)支持display ... json,直接返回 JSON。此时用jsonpath比正则高效百倍:

"parsers": [ { "type": "jsonpath", "expression": "$.data.interfaces[?(@.status == 'up')].name", "fields": ["interface"] } ]
4.3.3filter:数据清洗与条件筛选

常与regexjsonpath配合使用,实现“先提取,再过滤”:

"parsers": [ { "type": "regex", "pattern": "(\\S+)\\s+(up|down)", "fields": ["iface", "stat"] }, { "type": "filter", "condition": "stat == 'up'", "output": "iface" } ]

提示:parsers是链式执行的,前一个解析器的输出是后一个的输入。因此,filtercondition中可用的字段,必须是前一个解析器fields中定义的名称。命名不一致会导致field not found错误。

4.4error_handling:失败不是终点,而是流程的一部分

默认情况下,任一命令执行失败(非零退出码)或解析失败,整个task就标记为failed。但生产环境需要更精细的控制:

"error_handling": { "on_command_failure": "continue", "on_parser_failure": "skip", "ignore_exit_codes": [1, 255], "timeout_action": "kill" }
  • on_command_failure: "continue":某条命令失败(如show cpu在低端设备不存在),继续执行后续命令;
  • on_parser_failure: "skip":正则匹配不到任何内容,跳过该解析器,不中断流程;
  • ignore_exit_codes:明确声明哪些非零退出码是“可接受的”(如ping命令返回1表示丢包,但不意味命令失败);
  • timeout_action: "kill":当命令执行超时,立即终止 SSH 会话,防止僵尸进程堆积。

我在线上部署时,一定会为所有ping相关任务设置"ignore_exit_codes": [1],否则网络瞬时抖动就会导致整批设备采集失败。真正的稳定性,不在于“永不失败”,而在于“失败后知道如何优雅退场”

5.scheduleshooks:让自动化真正“活”起来

配置文件写完,只是完成了 50%。剩下 50%,是让任务按时执行(schedules)和让结果产生业务价值(hooks)。这两个区块,决定了 OpenClaw 是玩具还是生产利器。

5.1schedules:Cron 表达式不是魔法,而是精确控制权

schedules数组定义任务的触发时机。OpenClaw 使用标准 Cron 语法(5 字段),但增加了两个实用扩展:

"schedules": [ { "task_name": "check_disk_usage", "cron": "0 2 * * *", // 每天凌晨 2 点 "enabled": true, "timezone": "Asia/Shanghai", // 关键!避免服务器时区与业务时区错位 "concurrent_limit": 5 // 同一时刻最多并发执行 5 个实例 } ]
  • timezone:这是被 90% 用户忽略的致命字段。Linux 服务器默认 UTC 时区,而你的业务监控要求北京时间(UTC+8)。若不指定"timezone": "Asia/Shanghai"0 2 * * *会在 UTC 时间 2 点(即北京时间 10 点)执行,导致监控窗口错位。OpenClaw 会将 Cron 表达式的时间,转换为指定时区的本地时间再计算。
  • concurrent_limit:防止海量设备任务瞬间并发,打爆目标设备 CPU。例如,1000 台设备的check_uptime任务,若不限制并发,OpenClaw 会同时发起 1000 个 SSH 连接,交换机可能直接拒绝新连接。

一个高级技巧:利用 Cron 的第六位(秒)字段(OpenClaw 支持 6 位 Cron)实现“秒级精度”:

"cron": "0,30 * * * * *" // 每分钟的第 0 秒和第 30 秒执行(需 OpenClaw v1.2+)

5.2hooks:结果的终点,才是业务的起点

hooks对象定义任务生命周期事件的回调,是 OpenClaw 与外部系统集成的桥梁。它包含三个子键:

"hooks": { "on_success": [ { "type": "webhook", "url": "https://open.feishu.cn/open-apis/bot/v2/hook/xxx", "method": "POST", "headers": { "Content-Type": "application/json" }, "body": { "msg_type": "text", "content": { "text": "✅ 任务 {{ .TaskName }} 成功!共采集 {{ .ResultCount }} 台设备。平均耗时 {{ .AvgDurationMs }}ms。" } } } ], "on_failure": [ { "type": "shell", "command": "/usr/local/bin/alert-slack.sh '{{ .TaskName }}' '{{ .Error }}'" } ], "on_complete": [ { "type": "file", "path": "/var/log/openclaw/results/{{ .TaskName }}_{{ .Timestamp }}.json", "format": "json" } ] }
  • on_success:任务成功完成时触发。webhook示例中,{{ .TaskName }}是 Go 模板语法,会被替换为实际任务名。飞书机器人 URL 必须提前在飞书群中创建并获取。
  • on_failure:任务失败时触发。shell类型允许执行任意本地脚本,alert-slack.sh可以封装 Slack Webhook 调用逻辑,实现多通道告警。
  • on_complete:无论成功或失败,任务结束时都触发。file类型将完整结果(含原始输出、解析后数据、耗时统计)写入文件,供审计或离线分析。

注意:hooks中的模板变量(如{{ .ResultCount }})是 OpenClaw 内置的,无需自定义。完整变量列表见官方文档Hook Variables章节。滥用未定义变量(如{{ .UndefinedVar }})会导致 Hook 静默失败。

我在线上环境的标准实践是:所有on_success发飞书简报,所有on_failure发邮件+电话告警(通过 Twilio API),所有on_complete写入 Elasticsearch 供 Kibana 分析。这样,配置文件不仅是执行脚本,更是整个监控告警体系的数据源。

6. 避坑指南:那些让你深夜加班的“经典错误”

再完美的配置,也敌不过几个低级错误。以下是我在 12 个不同客户现场,累计排查超过 200 小时后总结的 Top 5 致命坑,附带一键检测脚本。

6.1 坑1:JSON 格式错误——看不见的空格与 BOM

现象:OpenClaw 启动报错failed to parse config: invalid character at offset 1,但用 VS Code 打开openclaw.json显示完全正常。

根因:文件开头存在 UTF-8 BOM(Byte Order Mark)或不可见 Unicode 字符(如 U+200B 零宽空格)。这些字符在编辑器中不可见,但 JSON 解析器会将其视为非法字符。

检测与修复(Linux/macOS):

# 检查 BOM file -i openclaw.json # 若输出包含 "charset=bom",则存在 BOM # 移除 BOM(保留 UTF-8 编码) iconv -f UTF-8 -t UTF-8-BOM openclaw.json | iconv -f UTF-8-BOM -t UTF-8 > openclaw_fixed.json # 检查零宽空格 grep -P "\xe2\x80\x8b" openclaw.json | od -c # 若有输出,则存在 U+200B # 彻底清理所有非 ASCII 控制字符(推荐) sed -i '' 's/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]//g' openclaw.json

经验:永远用vimnano编辑配置文件,避免用 Windows 记事本或某些国产编辑器(它们默认插入 BOM)。在 CI/CD 流水线中,加入file -i检查步骤。

6.2 坑2:device_selector逻辑错误——匹配了不该匹配的设备

现象:check_uptime任务在锐捷交换机上执行,报错command not found: uptime

根因:device_selector写成了"vendor == 'ruijie'",但devices数组中有一台 Linux 服务器也标记了"vendor": "ruijie"(人为误配)。OpenClaw 严格按表达式匹配,不会做类型校验。

检测脚本(Python):

import json import sys with open(sys.argv[1]) as f: cfg = json.load(f) # 检查 device_selector 是否可能匹配多个 vendor for task in cfg.get("tasks", []): selector = task.get("device_selector", "") if "vendor ==" in selector or "vendor == " in selector: # 粗略检查:selector 中是否隐含了 vendor 值 vendors_in_cfg = {d.get("vendor") for d in cfg.get("devices", [])} # 手动提取 selector 中的 vendor 值(简单正则) import re matches = re.findall(r"vendor\s*==\s*['\"]([^'\"]+)['\"]", selector) for v in matches: if v not in vendors_in_cfg: print(f"⚠️ Warning: task '{task['name']}' selector references unknown vendor '{v}'") print("✅ Config syntax check passed.")

运行:python check_config.py openclaw.json

6.3 坑3:parsers正则贪婪匹配——跨行吞噬所有数据

现象:show interfaces命令的解析结果为空,日志显示regex matched 0 times

根因:正则表达式过于宽泛,如".*up.*",在多行输出中会匹配从第一行到最后一行的超长字符串,导致无法提取单个接口。

正确写法(以锐捷为例):

"pattern": "(?<interface>\\S+)\\s+\\S+\\s+\\S+\\s+\\S+\\s+(?<status>up|down)\\s+.*", "flags": ["m"] // 启用多行模式,^$ 匹配每行

技巧:在 regex101.com 上调试时,务必勾选m(Multiline)标志,并粘贴完整的show interfaces status输出(含多行)进行测试。

6.4 坑4:schedules时区错乱——监控窗口漂移 8 小时

现象:0 2 * * *配置的任务,每天在北京时间 10 点执行,而非预期的 2 点。

根因:未设置timezone字段,OpenClaw 使用服务器本地时区(UTC),而业务要求北京时间。

修复:在schedules中显式添加"timezone": "Asia/Shanghai"。可通过timedatectl status确认服务器时区。

6.5 坑5:hooksWebhook URL 泄露——配置文件提交到公开仓库

现象:Git 仓库被扫描到,飞书机器人 URL 泄露,导致恶意用户向群内发送垃圾消息。

根因:webhook.url硬编码在openclaw.json中。

解决方案(三重防护):

  1. 环境变量注入"url": "${FEISHU_WEBHOOK_URL}",启动时export FEISHU_WEBHOOK_URL="https://..."
  2. Git 保护:在.gitignore中添加openclaw.json,改用openclaw.json.example作为模板;
  3. KMS 加密:对敏感字段(URL、密钥口令)使用 AWS KMS 或 HashiCorp Vault 加密,OpenClaw 启动时解密。

最后分享一个血泪教训:某次紧急上线,运维同事为赶时间,直接在生产服务器上vi openclaw.json,修改后忘记:set nobomb,保存了带 BOM 的文件。结果 OpenClaw 服务循环崩溃,监控告警全部失效。直到第二天早会,大家才发现——最危险的配置,往往来自最匆忙的手指。所以,我的桌面永远开着一个终端,里面跑着while true; do file -i /etc/openclaw/openclaw.json; sleep 5; done,它