Skip to content

Repository files navigation

way - 策略备份

将备份作为持续运营的项目,而非一次性任务。基于 restic 的策略封装。

推荐在所有地方使用策略备份:开发环境、个人电脑、生产服务器。

版本说明

  • v0.5.0+: daemon 模式,支持项目级调度配置
  • v0.4.0: TypeScript 版本,使用 systemd timer,凭证直接写在 YAML
  • v0.3.x: TypeScript 版本,使用 crontab,支持 .env
  • v0.2.x: Bash 版本

设计原理

1. 备份目的

  • 意外修改或删除时,从备份提取
  • 硬盘损毁、机房失联时,从备份重建
  • 需要追溯历史状态时,查阅备份

2. 不备份可重建内容

可重建的内容不备份:docker 镜像、node_modules、缓存、构建产物等。判断标准不是"是否有价值",而是"能否从其他来源恢复"。

3. 备份是项目

备份保护所有项目,其重要性是所有项目的总和。应作为最重要的项目持续运营。

4. 频率匹配变化

备份频率应匹配数据变化频率。高频变化时段多备份,低频时段少备份。

5. 可验证原则

未经验证的备份等于没有备份。定期验证备份可恢复,失败时必须有告警。

6. 定期清理

定期清理旧快照,防止存储膨胀。

7. 同步不等于备份

同步工具(如 Syncthing)会将误操作实时传播到所有节点。真正的备份必须具备版本历史和回滚能力。

8. 备份隔离原则

假设本机被入侵,攻击者不应能通过本机凭证定位或删除备份数据。

v0.5.0 架构升级

  • 使用 daemon 模式替代 systemd timer
  • 支持项目级 schedule 配置(不同项目不同频率)
  • 使用 node-cron 实现精确到分钟的调度
  • systemd service 管理常驻进程(自动重启)

9. 多层冗余原则

单一备份链路存在单点故障风险。应在多个维度建立冗余:

  • 时间周期:高频 + 每日 + 每周
  • 存储介质:云存储 + 本地硬盘 + 异地服务器

10. 恢复演练原则

定期执行实际恢复演练,确认备份可解密、可读取,恢复时间在可接受范围内。


依赖

  • Linux x64 独立发行包无需预装 Node.js、npm、Bun 或 restic
  • npm 安装方式需要 Node.js >= 18
  • Linux x64 平台内置 restic 0.18.1,其他平台需自行安装 restic

way 查找 restic 的顺序:

  1. WAY_RESTIC_BIN 指定的二进制
  2. Linux x64 npm 包内置的 restic
  3. Linux x64 独立发行包旁边或安装目录中的 restic
  4. 系统 PATH 中的 restic

安装

Linux x64 独立发行包(推荐)

GitHub Release 提供 Linux x64 独立发行包,安装机无需预装 Node.js、npm、Bun 或 restic:

curl -fsSL https://raw.githubusercontent.com/shellus/way/master/scripts/install.sh | sudo sh

默认安装位置:

  • way: /usr/local/bin/way
  • 内置 restic: /usr/local/lib/way/vendor/restic/linux-x64/restic
  • 示例配置: /usr/local/lib/way/*.yaml.example

npm 安装

npm install -g @shellus/way

Linux x64 安装方式无需额外安装 restic。如需使用自定义 restic,可设置:

WAY_RESTIC_BIN=/usr/local/bin/restic way restic snapshots

快速开始

1. 初始化配置

way init

编辑 ~/.way/repositories.yaml 填入实际凭证,设置权限:

chmod 600 ~/.way/repositories.yaml

2. 初始化 restic 仓库

# 本地仓库
way restic init

# S3 仓库(指定其他仓库)
way --remote=s3 restic init

3. 配置定时备份

way systemd install
way systemd status

4. 手动执行备份

way backup           # 备份所有项目
way backup data      # 只备份 data 项目
way restore data --target /tmp/restore --dry-run  # 按规则预演恢复
way restic snapshots # 查看快照

命令参考

# 备份命令
way backup              # 执行所有项目备份
way backup data         # 只备份 data 项目
way backup data config  # 备份多个项目
way backup --dry-run    # 模拟备份(不实际写入)
way restore data --target /tmp/restore              # 按规则恢复 data 项目
way restore data --host old-host --target /tmp/restore --dry-run  # 从指定 host 模拟恢复
way restore data --target /tmp/restore --delete     # 删除目标中快照不存在的文件
way gc                  # 按 retention 策略清理旧快照
way gc --dry-run        # 模拟清理(不实际删除)

# daemon 模式(推荐)
way daemon              # 启动常驻进程,按配置定时执行

# systemd 管理
way systemd install     # 安装 systemd service(运行 daemon)
way systemd show        # 显示 systemd 配置
way systemd status      # 查看服务状态
way systemd uninstall   # 卸载服务

# 显式透传 restic(way 只设置环境变量)
way restic snapshots    # → restic snapshots
way restic check        # → restic check
way restic stats        # → restic stats
way restic restore abc123 --target /tmp/restore  # → restic restore abc123 --target /tmp/restore

# 指定 repository(默认用 repositories.yaml 中的 default)
way --remote=oss restic snapshots

way backup 会继续执行本轮全部目标项目并输出汇总。全部项目成功时退出码为 0;任一项目失败时退出码为 1

生命周期

graph LR
    A[way daemon] --> B[读取配置]
    B --> C[为每个项目创建 cron 任务]
    C --> D[node-cron 定时触发]
    D --> E[执行 restic backup]
    E --> F[推送 Uptime Kuma]

    G[systemd service] --> H[启动 daemon]
    H --> I[进程崩溃自动重启]
Loading

配置说明

配置文件默认存放在 ~/.way/,安装后复制示例文件并填入实际值:

cp /usr/local/lib/way/repositories.yaml.example ~/.way/repositories.yaml
cp /usr/local/lib/way/rules.yaml.example ~/.way/rules.yaml

也可以通过 WAY_DIR 环境变量指定其他目录:

WAY_DIR=/path/to/config way restic snapshots

rules.yaml

备份规则配置,参考 rules.yaml.example

  • defaults: 全局默认配置(schedule、retention)
  • projects: 备份项目配置,可覆盖默认 schedule 和 retention
  • projects.*.hooks: 项目级备份钩子,支持 before_backupafter_backup
  • uptime_kuma.push_url: 全局 Uptime Kuma Push 地址,作为项目未配置通知地址时的回退
  • projects.*.uptime_kuma.push_url: 项目级 Uptime Kuma Push 地址,优先于全局地址
  • maintenance: 维护任务配置(prune、check)
  • global_excludes: 全局排除规则

项目级钩子用于在 restic 备份前后执行一致性快照、校验或清理脚本:

projects:
  data:
    paths:
      - /path/to/data
    hooks:
      before_backup:
        - run: /path/to/scripts/prepare-data-backup.sh
          timeout: "10m"
      after_backup:
        - run: /path/to/scripts/verify-data-backup.sh
          timeout: "5m"

before_backup 失败会跳过该项目的 restic 备份并标记项目失败;after_backup 只在 restic 成功后执行,失败同样会标记项目失败。--dry-run 模式只打印钩子命令,不实际执行。钩子命令按 shell 命令执行,并会收到 WAY_PROJECTWAY_REMOTEWAY_DIRWAY_DRY_RUN 环境变量。

Linux 上的 hook 达到 timeout 后,Way 会终止对应 shell 的完整进程组;进程未在宽限期内退出时会继续强制终止,避免数据库导出、压缩或同步子进程脱离 Way 后持续运行。hook 仍应保持幂等,并自行清理失败时生成的临时文件。

项目级 Uptime Kuma 通知示例

uptime_kuma:
  push_url: "https://uptime.example.com/api/push/global-placeholder"

projects:
  data:
    paths: [/data]
    uptime_kuma:
      push_url: "https://uptime.example.com/api/push/data-placeholder"

  root:
    paths: [/root]
    uptime_kuma:
      push_url: "https://uptime.example.com/api/push/system-placeholder"

每个项目优先使用项目级 Push 地址,未配置时回退到全局地址。一次 way backup 中使用相同有效地址的项目只发送一条汇总通知;同组任一项目失败时状态为 DOWN,不同地址的通知互不覆盖。--dry-run 不发送通知,通知请求失败只记录错误,不改变备份结果。

项目级调度示例

defaults:
  schedule: false  # 默认不自动调度

projects:
  data:
    paths: [/data]
    schedule: "0 */2 * * *"  # 每 2 小时

  logs:
    paths: [/var/log]
    schedule: "0 3 * * *"  # 覆盖为每天凌晨 3 点

  archive:
    paths: [/archive]
    schedule: false  # 只手动触发:way backup archive
    retention:
      keep_weekly: 8
      keep_monthly: 12

手动备份匹配目录示例

日常备份可排除可重建依赖目录,避免遍历海量小文件:

projects:
  data:
    paths: [/data]
    excludes:
      - node_modules
      - vendor
    schedule: "0 */2 * * *"

如果需要偶尔保留依赖目录,可单独配置只手动触发的项目:

projects:
  data_deps:
    paths: [/data]
    include_dirs:
      - www/xhj/*/node_modules
      - www/xhj/*/vendor
    schedule: false

手动执行:

way backup data_deps

include_dirs 是相对 paths 的目录 glob,只支持路径段中的 *,不支持绝对路径和 **。命中目录后,way 会把该目录作为备份根路径写入临时 --files-from 列表。include_dirs 是专用模式,不应用 global_excludes,也不能同时配置项目级 excludes

schedule 语法(node-cron 格式):

schedule 支持 node-cron 字符串或 falsefalse 表示不创建自动调度任务,只能通过 way backup <project>way backup 手动触发。项目未设置 schedule 时继承 defaults.schedule;如果全局和项目都未设置,则不自动调度。

格式 说明 示例
"0 */2 * * *" 间隔表达式 每 2 小时
"0 9,15,21 * * *" 多个时间点(逗号) 每天 9:00、15:00、21:00
"0 9-17 * * 1-5" 时间范围 工作日 9:00-17:00 每小时
"*/30 * * * *" 分钟间隔 每 30 分钟
false 禁用自动调度 只手动备份

排除规则通配符语法

restic 使用 Go 的 filepath.Match 语法:

  • * 匹配任意字符,但不跨越目录分隔符
  • ** 匹配任意子目录

示例:

  • *Cache* 只匹配当前目录下含 Cache 的文件/目录
  • **/*Cache* 匹配任意深度子目录下含 Cache 的文件/目录

repositories.yaml

备份目的地配置,参考 repositories.yaml

v0.4.0 变更:凭证直接写明文,不再支持 ${VAR} 环境变量语法。

repositories:
  local:
    type: local
    path: /backup/repo
    credentials:
      password: your-password  # 直接明文

建议设置文件权限:chmod 600 ~/.way/repositories.yaml

配置备份

~/.way/ 目录包含所有配置和凭证,建议整体备份到安全位置:

# 打包配置目录
tar czf way-config-$(date +%Y%m%d).tar.gz -C ~ .way

# 加密备份(推荐)
gpg -c way-config-$(date +%Y%m%d).tar.gz

如果本机不可访问且遗忘了配置和凭证,所有备份数据将永久无法恢复。

必须在本机之外保存 ~/.way/ 备份:

  • 密码管理器(推荐)
  • 加密云存储
  • 离线存储(U 盘、纸质打印关键凭证)

关键信息:

项目 位置
备份规则 ~/.way/rules.yaml
仓库配置和凭证 ~/.way/repositories.yaml

数据恢复

way 提供两种恢复方式:

  1. 按规则恢复:使用 way restore,根据 rules.yaml 中的项目路径和 way:<project> 标签恢复。
  2. 原始 restic 恢复:使用 way restic restore,显式透传 restic 参数。

1. 查看快照列表

way restic snapshots                    # 列出所有快照
way restic snapshots --tag=way:home     # 只看 home 项目的快照
way restic snapshots --tag=way:data     # 只看 data 项目的快照

2. 浏览快照内容

way restic ls <snapshot-id>             # 列出快照中的所有文件
way restic ls <snapshot-id> /root/.ssh  # 列出快照中指定目录的文件
way restic find --snapshot <id> <filename>  # 在快照中搜索文件

3. 按规则恢复项目

# 恢复 data 项目的最新快照到指定目录
way restore data --target /tmp/restore

# 恢复所有项目
way restore --target /tmp/restore

# 指定快照 ID
way restore data --snapshot abc123 --target /tmp/restore

# 预演恢复,不实际写入
way restore data --host old-host --target /tmp/restore --dry-run

# 让目标目录与快照一致,先 dry-run 核对删除清单
way restore data --host old-host --target /tmp/restore --delete --dry-run
way restore data --host old-host --target /tmp/restore --delete

way restore 会为项目自动添加 --tag=way:<project> 和项目 paths 对应的 --include 参数;传入 --host 时会只恢复指定 host 的快照。

4. 原始 restic 恢复

# 显式透传 restic restore
way restic restore <snapshot-id> --target /tmp/restore

# 只恢复特定路径
way restic restore <snapshot-id> --target /tmp/restore --include /root/.ssh

# 恢复单个文件到标准输出(适合快速查看)
way restic dump <snapshot-id> /root/.gitconfig

5. 从其他仓库恢复

way --remote=oss restic snapshots
way --remote=oss restore data --target /tmp/restore
way --remote=oss restic restore <snapshot-id> --target /tmp/restore

开发

参见 CONTRIBUTING.md 了解:

  • 项目结构和技术栈
  • 开发环境搭建
  • 变更规范和测试要求
  • 发布流程

项目维护规则:AGENTS.md

About

No description, website, or topics provided.

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages