mcpField
O
openclaw-backup

openclaw-backup

github.com/bhagyamudgal云与 DevOps298 次安装3 天前更新
代码仓库

关于 openclaw-backup

openclaw-backup 是备份当前机器或指定主机上 OpenClaw 安装的技能,面向需要保存并核验其状态、数据库、会话和配置的维护者。它通过分步检查、清单和恢复说明降低遗漏风险。

主要功能

  1. 01检测 OpenClaw 状态目录和数据库
  2. 02对 SQLite 数据库创建并核验快照
  3. 03生成官方归档和原始归档
  4. 04按需单独归档工作区
  5. 05收集服务元数据并生成校验清单
  6. 06可选异机复制并核验校验和

适用场景

  1. 01备份当前机器上的 OpenClaw 安装
  2. 02通过 SSH 备份远程主机
  3. 03检查归档是否包含会话记录
  4. 04为异机备份验证访问控制和文件校验

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bhagyamudgal/skills --skill openclaw-backup

安装后在 Claude Code 中输入/openclaw-backup确认已加载。

附带文件references/restore-template.mdreferences/sqlite-snapshot.md

详细介绍

每个步骤都以一道关卡结束。关卡是一项会生成证据的检查。未运行的关卡就视为未通过。这项技能旨在防范一种隐蔽故障:归档写入顺利、验证也通过,结果却缺少你需要的内容。

输入

  • 无。备份当前机器上的 OpenClaw 安装。
  • 主机。传入 user@host,并在每条命令前加上你的 SSH 调用。其他步骤完全相同。

尽可能自动检测。只询问备份目标位置(默认为 ~/backups/<date>-preflight),以及是否要拉取一份副本到本机。

步骤 0:预检

STATE_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"
[ -d "$STATE_DIR" ] || { echo "FAIL: no OpenClaw state dir at $STATE_DIR"; exit 1; }

openclaw --version
node --version                      # v22+ carries node:sqlite, needed in Step 3
du -sh "$STATE_DIR"
df -h "$STATE_DIR"
find "$STATE_DIR" -name '*.sqlite' -not -path '*/node_modules/*' | sort

每次运行都使用 find 查找数据库。OpenClaw 会在不同版本间迁移数据库。2026.7 将记忆数据库从 memory/main.sqlite 移到了 agents/<id>/agent/openclaw-agent.sqlite,因此硬编码路径会悄无声息地找不到任何内容。

定位工作区,它可能位于状态目录之外。检查配置中的 OPENCLAW_WORKSPACE_DIR 和 agents.defaults.workspace。状态目录之外的工作区是单独的归档来源。将其路径记录为 WORKSPACE_DIR;如果它位于状态目录内,并且原始归档已包含它,则留空。

检查主机以确定网关的运行方式。它可能是 systemd 用户单元(例如 openclaw-gateway.service)、systemd 系统单元、pm2、Docker 或 launchd。用户单元的每条命令都需要使用 systemctl --user。普通的 systemctl 会报告“unit not found”,看起来像是服务已停止,实际上服务仍在写入。

只有在可用空间至少为状态目录大小的 2 倍,且数据库列表非空时,才算通过此步骤。

步骤 1:从 --help 读取功能

openclaw backup --help
openclaw backup create --help

--help 是此安装版本的事实依据。docs.openclaw.ai 文档介绍了一个已发布的构建版本可能并不具备的 backup sqlite 子命令,因此文档网站描述的功能可能并不存在于该二进制文件中。

只有在记录了子命令列表后,才算通过此步骤。如果存在 sqlite,优先使用它而不是步骤 3,并在报告中说明。

步骤 2:选择停机模式

询问用户。默认采用零停机模式。步骤 3 会以事务方式快照数据库;数据库是唯一无法承受在线复制的部分。

模式代价
零停机(默认)写入原始归档期间,正在改写的文件可能不完整。数据库另行处理。
短暂停机停机数分钟,该时间段内的消息会丢失。所有产物均处于静止状态。

在停止运行中的网关之前,立即调用 preflight-mutations,并提供准确的主机、服务管理器及名称、停止和重启操作、预计停机时间、当前进程和健康状态、恢复命令,以及用户对短暂停机的批准。停止服务前,必须遵循其结果约定。零停机运行无需经过此关卡。

停止服务后,在归档前使用 pgrep -af openclaw 确认进程已退出,并在之后确认服务已恢复且运行正常。

步骤 3:快照所有 SQLite 数据库

加载 ${CLAUDE_SKILL_DIR}/references/sqlite-snapshot.md 并按其说明操作。该文件包含 VACUUM INTO 脚本,并解释了在线 WAL 数据库为何需要使用该脚本。

只有在每个数据库的源文件和快照都报告 integrity_check = ok,且计数显示为 N/N 时,才算通过此步骤。任一数据库未通过其中一项检查,都必须停止运行。报告失败的数据库及其返回的信息。

步骤 4:官方归档

cd "$HOME" && openclaw backup create --verify --output "$BACKUP_DIR/official"

大型安装需要数分钟。请在后台运行并轮询状态。

此归档会排除正在变动的文件:sessions、logs 和 delivery queues 下的 .jsonl、.log、.json、.tmp、.sock、.pid 文件。会话记录是 .jsonl 文件,因此接下来要执行步骤 5。

只有在运行结束时出现 Archive verification: passed,并且你记录了报告中要用的 Skipped N volatile files 计数,才算通过此步骤。没有这条验证信息,就视为归档未经验证。

步骤 5:原始归档,保存会话记录的归档

mkdir -p "$BACKUP_DIR/raw"
tar --use-compress-program="zstd -3 -T0" \
    --exclude='*/node_modules' \
    --warning=no-file-changed \
    -cf "$BACKUP_DIR/raw/openclaw-state-raw.tar.zst" \
    -C "$(dirname "$STATE_DIR")" "$(basename "$STATE_DIR")"
echo "EXIT=$?"

node_modules 可重新安装,且通常占总量的三分之一,因此会被排除。其他内容全部保留。步骤 4 丢弃的易变文件正是本步骤的重点。

然后生成证据:

LISTDIR=$(mktemp -d "$BACKUP_DIR/.listings-XXXXXXXX") || exit 1
zstd -t "$BACKUP_DIR/raw/openclaw-state-raw.tar.zst"
tar --use-compress-program="zstd -d" -tf "$BACKUP_DIR/raw/openclaw-state-raw.tar.zst" > "$LISTDIR/rawlist.txt"
LISTING_EXIT=$?
wc -l < "$LISTDIR/rawlist.txt"
grep -c 'sessions/.*\.jsonl' "$LISTDIR/rawlist.txt"
grep -c 'node_modules' "$LISTDIR/rawlist.txt"
rm -rf -- "$LISTDIR"

仅当 zstd -t 通过、列表命令的退出码为 0、在有会话历史记录的安装中会话 .jsonl 数量大于零,且 node_modules 数量为零时,本步骤才算通过。.jsonl 数量为零或 node_modules 数量不为零,都表示排除模式有误。修正后重新运行。记录 tar 的退出状态:0 表示干净通过,1 表示在报告中记录热读取警告,2 或更高则本步骤失败。

步骤 5.5:工作区归档

当 WORKSPACE_DIR 为空时,跳过本步骤:工作区已保存在原始归档中。

mkdir -p "$BACKUP_DIR/workspace"
tar --use-compress-program="zstd -3 -T0" \
    --warning=no-file-changed \
    -cf "$BACKUP_DIR/workspace/openclaw-workspace.tar.zst" \
    -C "$(dirname "$WORKSPACE_DIR")" "$(basename "$WORKSPACE_DIR")"
echo "EXIT=$?"

然后生成证据:

LISTDIR=$(mktemp -d "$BACKUP_DIR/.listings-XXXXXXXX") || exit 1
zstd -t "$BACKUP_DIR/workspace/openclaw-workspace.tar.zst"
tar --use-compress-program="zstd -d" -tf "$BACKUP_DIR/workspace/openclaw-workspace.tar.zst" > "$LISTDIR/workspacelist.txt"
LISTING_EXIT=$?
wc -l < "$LISTDIR/workspacelist.txt"
rm -rf -- "$LISTDIR"

仅当 zstd -t 通过、列表命令的退出码为 0,且列表非空时,本步骤才算通过。记录 tar 的退出状态:0 表示干净通过,1 表示在报告中记录热读取警告,2 或更高则本步骤失败。

步骤 6:元数据

将以下各项保存到 meta/:

  • 服务单元文件及其 drop-in 目录。覆盖项位于 drop-in 目录中。记录服务管理器。对于 systemd,将单元目录记录为 UNIT_DIR:即包含单元文件的目录,drop-in 位于 <name>.d 下。对于 pm2、Docker 或 launchd,不存在单元目录:将定义文件归档到 meta/service-def/,保留其基本文件名,将其当前路径记录为 SERVICE_DEF_PATH,并记录服务管理器。模板会根据记录的管理器进行恢复。
  • 单元引用的环境文件。
  • openclaw --version、node --version、全局 npm 软件包。
  • 监听端口、正在运行的 OpenClaw 进程、crontab。
  • 每个状态子目录的 du -sh 结果,用于检查之后恢复的大小。

仅当上述每一项都已保存到 meta/,或已在报告中注明不可用并说明原因时,本步骤才算通过。

步骤 7:清单和 RESTORE.md

cd "$BACKUP_DIR" && find . -type f ! -name MANIFEST.sha256 -print0 \
  | sort -z | xargs -0 sha256sum > MANIFEST.sha256
chmod -R go-rwx "$BACKUP_DIR"

应用权限变更。这些归档包含 API 令牌、消息配对数据和 OAuth 刷新令牌。

将 ${CLAUDE_SKILL_DIR}/references/restore-template.md 渲染为 $BACKUP_DIR/RESTORE.md,并填入步骤 0 中的实际路径、服务名称、单元目录和数据库列表。

仅当 MANIFEST.sha256 列出每个产物、备份目录的权限模式为 0700,且渲染后的 RESTORE.md 不再包含任何 <PLACEHOLDER> 标记时,本步骤才算通过。

步骤 8:异机复制

与受保护内容位于同一磁盘上的备份能防范配置错误,但无法应对磁盘损坏。如果用户希望将副本保存到其他位置,请完成此步骤。

在运行 rsync 之前,请从接收系统确认目标位置启用了静态加密、仅预期的接收方账户可以访问,并且有明确的保留期限和经过测试的删除路径。首次传输前,请将目标主机密钥与已知可信值核对,避免因主机名输入错误或首次连接被拦截而将副本导向其他位置。目标位置缺少上述任一控制措施时,必须阻止传输。

在运行 rsync 前一刻,使用这些证据、准确的源主机和目标主机及路径、所含制品清单和凭据敏感性、接收方、保留期限和删除路径、当前目标状态、校验和及访问控制回读结果,以及用户对异机复制的批准,调用 preflight-mutations。复制前,先执行其结果契约。

rsync -avh --partial -e ssh <source> <destination>

根据清单在接收端进行验证:

grep -v ' \./official/' MANIFEST.sha256 > /tmp/check.sha256   # if official/ was not pulled
sha256sum -c /tmp/check.sha256    # macOS: shasum -a 256 -c

确认校验和输出涵盖非空文件列表后,才能将其视为通过。校验器收到空列表时,会在未检查任何内容的情况下报告成功。

校验和不匹配时,应将该传输卡标记为已失效。保留其 failed 结果和观察到的目标端部分状态,作为不可更改的历史记录。如果传输或回读情况不明确,请将其标记为 reconcile-required,并在规划其他写入前解决该确切文件的问题。每次重试前,都要重新读取确切的源文件和目标端部分文件,并重新检查接收系统的加密、有效访问权限、保留期限和经过测试的删除控制措施。创建一张新卡,仅限于这一个不匹配文件和一次可恢复的 rsync --partial 传输,并附上当前防护措施和预期的校验和回读结果。仅在当前结果为 ready 时重试;随后,在进行任何后续尝试前,将该卡标记为已完成,并记录其权威结果。

复制后,重新检查接收系统的加密和有效访问控制。如果其中任一项与预检证据不符,请保留并报告该副本为敏感的部分状态。复制批准不授权删除。应单独生成补偿性删除卡,并注明确切目标、观察到的故障、删除操作和不存在性回读结果。仅在获得新的明确确认且当前预检结果为 ready 后删除。

只有在每个已检查文件均报告 OK、静态加密仍处于启用状态、有效访问权限仍仅限于已批准的接收方账户,并且保留期限和删除路径仍可用时,才算通过此步骤。只有按照上述新建卡片重试契约处理后,不匹配文件才可解除阻止。安全控制失败时,必须阻止完成,同时保留敏感的部分状态,或单独将其删除。--partial 可让新的传输恢复进行。

不拉取官方归档是合理的。其内容是原始归档的子集。请在报告中说明这一省略。

步骤 9:报告

OPENCLAW BACKUP: <host or "local">

Install:  OpenClaw <version>, state dir <path> (<size>)
Service:  <unit/manager>, <running|stopped during backup>
Mode:     <zero-downtime | brief stop>

Artifacts (<total size>, mode 0700):
  official/<name>.tar.gz     <size>   verification: <passed|NOT VERIFIED>
  raw/<name>.tar.zst         <size>   <N> entries, <M> session transcripts
  workspace/<name>.tar.zst   <size>   <N> entries (omit when the workspace sits inside the state dir)
  sqlite/                    <size>   <X>/<X> databases, integrity ok source + snapshot
  meta/                      <size>   unit + drop-ins, env, inventory
  MANIFEST.sha256 + RESTORE.md

Official archive skipped <N> volatile files, covered by the raw archive.

VERIFIED:  <what was run, and the evidence each produced>
ASSUMED:   <what was inspected but not executed>
NOT DONE:  restore has not been rehearsed against this backup

VERDICT: <BACKUP COMPLETE | INCOMPLETE, reason>

只有在步骤 0-8 中每个“只有在……时,才算通过此步骤”的条件,都连同证据列在 VERIFIED 下,或连同未执行的原因列在 ASSUMED 下时,才算通过此步骤。只有全部条件均已验证,才能标记 BACKUP COMPLETE。

以下两项声明须保持准确:

  • 校验和未经验证的备份应标记为 INCOMPLETE。
  • 在实际针对临时目标执行恢复之前,恢复状态应保持为 NOT DONE。运行备份只能证明归档存在,不能证明它们可以恢复。

评论

支持 Markdown