# openclaw 升级与维护运维手册(bk02) > 主机:**bk02** / `xuan-asus-nj`(Debian 12 bookworm,`192.168.3.14`,tailscale `100.115.195.192`) > 组件:OpenClaw Gateway(用户级 systemd)+ tailscale serve(HTTPS 入口) > 版本:OpenClaw `2026.8.1` → **`2026.9.4`**;运行 Node `/usr/bin/node 22.23.1` → **nvm `v26.8.2`** > 更新:2026-09-16(本次为实测记录,含命令、证据与踩坑) > > ⚠️ 本文不写明文口令。凭据位置见 §7。 --- ## 1. 架构总览 ``` 浏览器 / App ↓ https://bk02.baiji-algieba.ts.net (tailscale serve,443 终止 TLS) ↓ 转发到本机回环 bk02: node 进程 127.0.0.1:18789 (openclaw gateway) ↓ 存储:~/.openclaw/state/openclaw.sqlite(共享状态) ~/.openclaw/agents//agent/openclaw-agent.sqlite(每 agent 会话/记忆) ``` | 项 | 值 | |---|---| | 服务单元 | `openclaw-gateway.service`(**用户级** systemd,`systemctl --user`) | | 监听 | `127.0.0.1:18789`(+ `[::1]:18789`),不直接对外 | | 对外入口 | `gateway.tailscale.mode = serve` → `https://bk02.baiji-algieba.ts.net` | | 启动命令 | `/home/yangxuan/.nvm/versions/node/v26.8.2/bin/node --max-old-space-size=3913 /dist/index.js gateway --port 18789` | | 插件 | 8 个 enabled:dingtalk-connector、feishu、memory-core、ollama、openclaw-weixin、searxng 等 | | 状态目录 | `~/.openclaw`(本次清理前 2.6G,清理后 1.5G) | --- ## 2. 本次升级:2026.8.1 → 2026.9.4 ### 2.1 阻塞点:Node 版本(先踩后解) `openclaw update` 直接拒绝,原文: ``` Node 22.23.1 at /usr/bin/node is too old for openclaw@2026.9.4. The requested package requires >=24.16.0 <25 || >=26.1.0 ``` 关键点:**gateway 服务实际用的是系统 `/usr/bin/node`(22.23.1)**,而 nvm 里的 `v25.9.0` **也不被支持**(要求排除整个 25.x)。 | Node | 版本 | 满足 2026.8.1 | 满足 2026.9.4 | |---|---|---|---| | 系统 `/usr/bin/node`(升级前在用) | 22.23.1 | ✅ | ❌ | | nvm | v25.9.0 | ✅ | ❌(25.x 被排除) | | nvm | **v26.8.2**(本次采用) | — | ✅ | ### 2.2 执行步骤(可复现) ```bash # 1) 装 Node 26(用户级,不动系统 node —— 同机还有 VS Code Server 等依赖它) export NVM_DIR=$HOME/.nvm; . $NVM_DIR/nvm.sh nvm install 26 # → v26.8.2 nvm alias default 26 # 让新 shell 与 gateway 版本一致 # 2) 全局安装新版本(必须放行 install scripts,否则原生模块不构建,见 §3.1) nvm use 26 npm i -g openclaw@2026.9.4 \ --allow-scripts=openclaw,@google/genai,koffi,tree-sitter-bash,protobufjs # 3) 用官方命令重建服务定义,让 gateway 切到 Node 26 systemctl --user stop openclaw-gateway openclaw daemon install # 自动检测并替换不支持的 Node,见下 ``` `openclaw daemon install` 会自己发现并修掉旧 Node,原文输出: ``` Node 22.23.1: node:sqlite truncates TEXT at embedded NUL (nodejs/node#61954); use 24.16+/26.1+ Replacing unsupported Gateway service Node 22.23.1 (/usr/bin/node) with ~/.nvm/versions/node/v26.8.2/bin/node Previous unit backed up to: ~/.config/systemd/user/openclaw-gateway.service.bak ``` > **顺带修掉一个数据隐患**:Node 22 的 `node:sqlite` 存在「TEXT 遇内嵌 NUL 被截断」的已知 bug(nodejs/node#61954)。 > 升级前每条含空字符的消息都可能被静默截断 —— 换到 Node 26 后不再发生(历史已截断的数据无法自动还原)。 ```bash # 4) 同步插件到同版本(doctor 会逐个点名) openclaw plugins update feishu openclaw plugins update @openclaw/searxng-plugin@2026.9.4 openclaw plugins update @openclaw/deepseek-provider@2026.9.4 openclaw gateway restart ``` ### 2.3 验收证据(实测) | 验证项 | 结果 | |---|---| | 版本 | `OpenClaw 2026.9.4 (3a9d69d)` | | 运行 Node | `/proc//exe → v26.8.2/bin/node` | | 服务状态 | `active`,`NRestarts=0` | | 启动日志 | `[gateway] ready`、`[tailscale] serve enabled: https://bk02.baiji-algieba.ts.net/` | | 插件 | 6→8 个加载,`feishu`/`searxng`/`deepseek` 均 `2026.9.4` | | 远端首页 | HTTP/2 **200**,ttfb ≈ **0.139s** | | 前端资源 | 压缩后 **348KB**(原始 1387KB,Brotli),9 个资源并发 **0.16–0.79s** | | WS 端点 | **200** | | 数据完整性 | 12 个 agent 全在、36 个 SQLite 库、自动完成 v16/v17 状态迁移 | --- ## 3. 踩坑清单(复现时必读) ### 3.1 npm 11 会静默拦下 install scripts 首次 `npm i -g openclaw@2026.9.4` 虽然「成功」,但这些脚本**没执行**: ``` openclaw (postinstall: postinstall-bundled-plugins.mjs) koffi (install: cnoke.cjs --prebuild) ← 原生模块 tree-sitter-bash (install: node-gyp-build) ← 原生模块 protobufjs / @google/genai ``` → **必须带 `--allow-scripts=...` 重装**,否则运行时才暴露缺模块。 ### 3.2 服务里的 Node 路径是硬编码的 `ExecStart` 记录的是绝对路径与具体 Node 版本目录。手工改 systemd 容易漏(`PATH` 环境变量里也含版本号),**优先用 `openclaw daemon install` 重建**,它会连带更新 `PATH`、保留原有 `Environment=` 注入。 ### 3.3 两个命令需要显式 `--force` | 命令 | 不加 force 的表现 | |---|---| | `openclaw gateway stop` | 拒绝:「This stops the operator's running gateway service… re-run with `--force`」 | | `openclaw plugins uninstall ` | 交互确认;非交互环境需 `--force`(**没有** `--non-interactive` 这个参数) | --- ## 4. 存储结论:只能用 SQLite(不能换 PG/MySQL) 官方文档 `llms-full.txt` 原文: > **SQLite remains the supported runtime store.** Preparation for PostgreSQL should improve the existing store owners and their tests **before adding a driver or configuration option**. 即 PG 支持**连驱动和配置项都还没有**,仅处于前瞻设计阶段。旁证: | 检查 | 结果 | |---|---| | 官方文档 `mysql` / `mariadb` 命中 | **0 次 / 0 次** | | 官方文档 `postgres` 命中 | 6 次,全在「Preparing for another database backend」一节 | | 代码里 PostgreSQL/MySQL 字样来源 | **SQL 语法高亮方言**(CodeMirror / kysely dialect)与报错文案,**非存储后端** | | 实际驱动 | `node:sqlite`(Node 内置,无外部依赖) | | 存储位置 | `state/openclaw.sqlite` + `agents//agent/openclaw-agent.sqlite`(共 36 个库) | **但是**:本机 docker 里的 pgsql / mysql **可以作为 agent 的工具数据源**(配置里 `"MySQL":{"enabled":true}` + `sql-toolkit`),这与「openclaw 自身存储」是两层,互不影响。 > 结论:想提升存储层,**升级 Node 比换数据库更实在**(§2.2 的 NUL 截断 bug 就是典型)。 --- ## 5. 清理历史版本配置 / 缓存 / 残留 ### 5.1 官方清理入口 | 目标 | 命令 | 备注 | |---|---|---| | 迁移「回滚原始文件」 | `openclaw update cleanup --dry-run` → 停机后 `openclaw update cleanup` | 官方专用于清理 upgrade 残留 | | agent 库 VACUUM | `openclaw doctor --session-sqlite compact --session-sqlite-all-agents` | 需停机 | | 共享状态库压缩 | `openclaw doctor --state-sqlite compact --json` | 需停机,会设置 `auto_vacuum=INCREMENTAL` | | 列表/删除历史会话 | `openclaw sessions` | | | 继承文件迁移 | `openclaw doctor --fix` | 会归档为 `<源>.migrated..` | | 卸载插件(含目录) | `openclaw plugins uninstall --force` | | 停机维护的官方推荐顺序: ```bash openclaw backup create --verify # 先备份(必做) openclaw gateway stop --force openclaw doctor --session-sqlite compact --session-sqlite-all-agents openclaw doctor --state-sqlite compact --json openclaw gateway start ``` ### 5.2 本次清理成效(实测) | 项目 | 手段 | 释放 | |---|---|---| | npm 缓存 | `npm cache clean --force` | **1.7 GB** | | 旧版 Node 25(含 openclaw 2026.8.1) | `nvm uninstall 25.9.0` | **1.5 GB** | | `memory-lancedb`(disabled 插件) | `openclaw plugins uninstall memory-lancedb --force` | **950 MB** | | 旧版本 UI 资源缓存 | 核对当前 build 引用后删旧 hash 目录 | **28 MB** | | SQLite 空闲页 | 上述两个 compact | 2.9 MB | | 重复 skill 目录 | 全量比对后移出 | 20 KB | | 验证失败的备份包 | 删除 | 378 MB | **根分区 26G/109G (26%) → 24G/109G (23%)**;`~/.openclaw` 2.6G → 1.5G。 共享状态库 compact 实测输出(可作判据基线): ```json { "before": { "autoVacuum": 0, "dbSizeBytes": 15339520, "freelistPages": 435 }, "after": { "autoVacuum": 2, "dbSizeBytes": 12771328, "freelistPages": 0 }, "reclaimedBytes": 2568192, "integrityCheck": "ok" } ``` ### 5.3 不能动的东西(官方设计,删了会出问题) | 路径 | 为什么保留 | |---|---| | `openclaw.json.bak` + `.bak.1`~`.bak.4` | 官方**配置备份环**:任何配置写入都会轮转(`--fix` 亦然) | | `openclaw.json.last-good` | 解析失败时的自动恢复源 | | `openclaw.json.pre-update` | 升级前备份 | | `agents/*/agent/*.sqlite` | 当前会话/记忆数据 | | `~/.openclaw/.git` | 配置备份仓库(见 §6) | ### 5.4 边界:`update cleanup` 拒绝清理的那 525MB `agents/*/session-sqlite-import-archive/` 下有 654 个 `*.imported-*`(约 **525MB**),是 2026-08-31 会话从 JSONL 迁入 SQLite 时的归档。官方 cleanup **拒绝清理**: ``` Candidates: 0 bytes; verification required: 550782825; protected: 0; blocked: 0 原因: historical-manifest-without-import-proof ``` - `doctor --session-sqlite validate` / `dry-run` 均返回 `0 target(s)`:没有待导入的遗留源 - `compact` 报告 `archived-unreferenced-jsonl=0`:openclaw 认为这些归档**仍被清单引用** - 独立验证:`session_transcript_archives` 表用 **`archive_blob` BLOB 把内容存在库内**,全表**不引用外部文件路径** ⇒ 这些 JSONL 确如文档所述「**not runtime fallbacks**」(非运行时依赖),**删除不影响运行**,但会**永久失去降级回旧 JSONL 版本的能力** **结论:暂不清理**(保留 525MB 换历史恢复能力)。若将来确认不需要降级,可手动删除该目录 —— 但官方不背书,删前务必备份迁移凭证 `session-sqlite-migration-runs/`。 --- ## 6. 备份、配置仓库与回滚 ### 6.1 备份 ```bash openclaw backup create --verify --output ~/openclaw-backups ``` ⚠️ 若 workspace 下存在**仅大小写不同**的重复目录(本次为 `skills/Obsidian` 与 `skills/obsidian`),`--verify` 会因 *portable path collision* **失败**。处理方式: ```bash diff -r skills/obsidian skills/Obsidian # 确认内容一致(本次仅 .clawhub/origin.json 的安装元数据不同) mv skills/Obsidian ~/openclaw-backups/removed-skills/ # 移出而非删除 ``` ### 6.2 配置仓库(Gitea) | 项 | 值 | |---|---| | 仓库 | `~/.openclaw`(工作区内的 git 仓库,分支 `314`) | | remote | `https://gitea.climbcube.cn/yangxuan/openclaw-config.git` | | 自动提交 | `auto-commit-config.sh`,每 6 小时 `git add -A` + commit + push,无变更则跳过 | | 提交信息 | `auto: sync OpenClaw config <时间>` / `auto: agent DB backup <日期>` | **体积治理(本次)**:`.git` 曾达 199M / 249 次提交。根因**不是** SQLite(`.gitignore` 已忽略 `*.sqlite`),而是 workspace 里的大数据文件被自动提交并推送: ``` 90.2 MB workspace-juaner/data/私聊_王芳.json 36.9 MB workspace-juaner/data/私聊_王芳.jsonl 11.7 MB agents/*/session-sqlite-import-archive/*.imported-* ``` ⚠️ **隐私提示**:`.gitignore` 原未忽略 `workspace-*/data/`,导致私聊内容进入 git 历史并推送到 Gitea。 已加固 `~/.openclaw/.gitignore`: ```gitignore workspace-*/data/ agents/*/session-sqlite-import-archive/ ``` 并 `git rm -r --cached`(保留本地文件)使既有大文件脱离跟踪,后续提交不再增长。**历史重写(filter-repo)未做**,如需彻底清除需另行评估(会与 remote 冲突,需 force push)。 ### 6.3 回滚 ```bash # 服务定义 cp ~/.config/systemd/user/openclaw-gateway.service.bak ~/.config/systemd/user/openclaw-gateway.service nvm install 25.9.0 && nvm exec 25.9.0 npm i -g openclaw@2026.8.1 systemctl --user daemon-reload && systemctl --user restart openclaw-gateway ``` > 注意:本次已删除 nvm `v25.9.0`(1.5G)与 `memory-lancedb`,**回滚需重新下载**;`~/openclaw-backups/` 内的验证备份(351MB,不含 workspace)仍可恢复数据。 --- ## 7. 凭据与密钥位置(不含明文) | 用途 | 位置 | |---|---| | gateway 认证 | `~/.openclaw/openclaw.json` → `gateway.auth`(password 模式) | | 机主登录 | 由机主掌握;本机 `~` 用户 `yangxuan` | | 模型 / 渠道密钥 | `~/.openclaw/.env` 与 `openclaw.json` 的 `secrets` 段(systemd 以 `OPENCLAW_SERVICE_MANAGED_ENV_KEYS` 注入) | | 备份包 | `~/openclaw-backups/*.tar.gz`(含凭据,勿外发) | --- ## 8. 遗留观察点 1. **`.git` 仍为 199M** —— 索引清理只阻止未来增长,历史未重写。 2. **525MB 迁移归档保留**(§5.4),如需释放需人工决策。 3. **skill 重名冲突 5 条**(`weather`/`obsidian`/`blogwatcher`/`mcporter`/`baidu-text-translate`):workspace 覆盖 bundled,属**设计内优先级行为**,非错误,可不管。 4. **gateway 重启频率**:升级前曾出现单日 5 次重启(2026-09-15),重启后 20 秒内 RPC 会达 1.5–4.4s(冷启动),稳态 0 次慢调用。若再遇「打开很慢」,先查是否落在重启窗口。 5. **链路**:wit01 ↔ bk02 走 DERP 中继(`MappingVariesByDestIP: true`,对称 NAT),实测首屏 0.16–0.79s,服务端本身 < 10ms。