前言

有个朋友,在 Oracle 免费服务器上托管 Vaultwarden,在没有做过数据备份的情况下,账号被扬了 😆

Unlucky Guy-1.webp Unlucky Guy-2.webp

我也喜欢自托管一些服务,有些数据需要定期的备份,但是我比较懒,偶尔手动备份一下。有了上面倒霉蛋朋友的经历,不得不好好整一下备份服务了。对于涉及敏感信息文件的备份,我认为至少要满足三点:

  1. 安全 使用可靠的加密方式保护对备份的访问
  2. 版本快照 可以在快照之间滚动版本
  3. 自动化 高度可拓展性,定时执行任务

介绍

满足要求的备份服务有很多,但是 Duplicacy 最强大的功能是在支持多种存储服务的条件下,还支持多个实例备份到同一个存储服务。这多个实例之间无需互相通信,且不依赖其他的备份。

Duplicacy 的文档集合的不是很全面,一些较新的说明或举例都分散在 Duplicacy 社区 里。在国内看起来热度不是很高,但是国外用户量挺大的,社区也确实比较活跃,看大牛们秀各种神奇的操作。作者应该是一个国人独立开发者,CLI 软件源码开放,但是它并不是自由软件。只不过对于 个人非商业用途 它是 完全免费 的,这对我个人已经足够了。

本文只记录了基本命令的一些说明和注意点。可能还不是很全面。关于 自动化任务进阶使用 请看下一篇 Duplicacy CLI 进阶使用指南

总之,本文又臭又长,东拼西凑,毫无逻辑。如果您完全看不下去,请不要怀疑,绝对是我的问题!

截止本文时间,Duplicacy 支持的存储服务有:

不同的存储服务在 Duplicacy 中使用的 URL 可以在 Storage Backends 查看,本文我会以 OneDrive Buisness 为例。

安装

Duplicacy GUI 会包含 CLI 程序,本文只介绍 Duplicacy CLI

在 Duplicacy CLI 的 Releases 页面下载编译好的二进制文件

# 选择系统或架构使用 Wget 下载
# Linux x64
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_linux_x64_3.0.1

# Linux x86
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_linux_i386_3.0.1

# Linux ARM
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_linux_arm_3.0.1

# Linux ARM64
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_linux_arm64_3.0.1

# FreeBSD x64
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_freebsd_x64_3.0.1

# macOS x64 (Intel)
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_osx_x64_3.0.1

# macOS ARM64 (Apple Silicon)
$ sudo wget -O /opt/duplicacy https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_osx_arm64_3.0.1

# 也可以使用 cURL 下载
$ sudo curl -L https://github.com/gilbertchen/duplicacy/releases/download/v3.0.1/duplicacy_osx_arm64_3.0.1 -o /opt/duplicacy

# Windows 用户只需这一步即可完成安装
# 不支持 ARM Windows
$ scoop install duplicacy

赋予可执行权限

$ sudo chmod +x /opt/duplicacy

创建软链接

$ sudo ln -s /opt/duplicacy /usr/local/bin/duplicacy

验证安装

$ duplicacy -h

Duplicacy 已经安装完成啦,现在您也可以给 duplicacy 命令设置一个简短的别名,编辑 .bashrc.zshrc,添加一行

alias dup='duplicacy'

重载 Shell 配置

# Bash
$ source ~/.bashrc

# Zsh
$ source ~/.zshrc

# 适用于所有 Shell
$ exec $SHELL

以后,您就可以用 dup 命令代替它的全称啦~

使用

本文参考了 Duplicacy Wiki, Duplicacy 社区 的大量说明和帖子,并尽可能保持简单够用的原则,您应该可以在社区根据 标签 快速检索到更多您想要了解的内容。

在开始之前,首先了解下 Duplicacy 的三个基本概念

  • Storage - 目标存储
  • Repository - 存储库
  • Snapshot ID - 快照 ID

Duplicacy Concept

Storage 是 Duplicacy 支持的存储(一般是远程云存储,比如本文中的 OneDrive),我们将多台机器备份到这个存储空间里;Repository 是 Duplicacy 初始化 (init) 一个本地备份目录后形成的 存储库,这一点它和 Git 有一点类似;Snapshot ID 用来区分连接到同一 Storage 的不同 Repository 存储库唯一的 快照 ID

  1. 每一个 Repository 必须有一个独一无二的 Snapshot ID
  2. Snapshot ID 在不同机器上是唯一的
  3. Snapshot ID 只能包含字母、数字、-(连字符) 以及 _(下划线)

为了描述方便,本文接下来保持称呼 Storage, Repository, Snapshot ID

init 初始化

要创建一个用来备份的 Repository,使用 Duplicacy 的 init 命令,查看一下命令帮助1

$ duplicacy init -h
NAME:
   duplicacy init - 如有必要,初始化存储,并将当前目录初始化为存储库

用法:
   duplicacy init [Options] <Snapshot ID> <Storage URL>

OPTIONS:
   -e  使用密码加密 Storage
   -c <size>  块平均大小 (默认 4M)
   -max <size>  块最大大小 (默认 (块平均大小*4))
   -min <size>  块最大大小 (默认 (块平均大小/4))
   -iterations <i>  存储密钥推导中使用的迭代次数 (默认 16384)
   -pref-dir <path>  .diplicacy 目录的替代位置 (绝对路径或相对路径)
   -storage-name <name>  给 Storage 指定一个名称 (默认 default)
   -repository <path>  在指定的路径而不是当前工作目录下初始化一个新的版本库。
   -key <public key>  用于加密文件块的 RSA 公钥
   -erasure-coding <data shards>:<parity shards>  启用擦除编码以防 Storage 损坏

使用 OneDrive Buisness 作为 Storage 来初始化我们的第一个 Repository,访问应用获取 OneDrive 访问令牌凭据:

授权访问权限后浏览器会自动下载一个 xxx-token.json 文件,将它复制到当前 Repository 的 .duplicacy 目录下

# 初始化 Repository - 需要加密 (OneDrive Personal 的 URL 开头是 one://)
$ duplicacy init -e cooldog odb://backup
# [出现提示] 输入 xxx-token.json 文件路径
Enter the path of the OneDrive token file (downloadable from https://duplicacy.com/one_start):.duplicacy/odb-token.json
# [出现提示] 输入加密密码
Enter storage password for odb://backup:****************
Re-enter storage password:****************
# [初始化成功] 备份到 Storage 的 backup 目录下,Snapshot ID 为 cooldog
/Users/dejavu/Space/clink will be backed up to odb://backup with id cooldog

现在 OneDrive 的 backup 文件夹会是这样

Backup Folder

本地 Repository 文件目录如下

.
├── .DS_Store
├── .duplicacy  # Duplicacy 配置目录
│   ├── odb-token.json  # OneDrive Business 访问令牌凭据文件
│   └── preferences  # 当前 Repository 配置目录
├── Makefile
├── README.md
├── doc
│   ├── clink.conf
│   ├── clink.nginx
│   └── clink.service
├── index.h
├── main.c
├── mongoose.c
└── mongoose.h

2 directories, 12 files

backup 备份

Repository 正确初始化了,现在就可以尝试同步了,查看命令帮助 2

$ duplicacy backup -h
NAME:
   duplicacy backup - 将 Repository 的快照保存到 Storage 中

USAGE:
   duplicacy backup [Options]

OPTIONS:
   -hash  通过 Hash 值检测文件差异 (而不是文件大小或时间戳)
   -t <tag>  给备份指定一个标签
   -stats  显示备份过程和备份完成的统计数据
   -threads <n>  上传文件线程数
   -limit-rate <kB/s>  全局上传速度限制 (单位 kb/s)
   -dry-run  空运行测试,实际不备份任何东西。与 -stats 和 -d 一起使用
   -vss  启用影卷复制服务 (仅限 Windows 和使用 APFS 文件系统的 macOS)
   -vss-timeout <timeout>  等待影卷复制操作完成的超时秒数
   -storage <storage name>  备份到指定的 Storage 而不是 default Storage
   -enum-only  递归枚举 Repository 包含或排除的文件和文件夹并退出
   -metadata-chunk-size <size>  元数据块的平均大小 (默认 1M)
   -max-in-memory-entries <number>  保存在 RAM 中的最大条目大小 (默认 1M)

开始备份

$ duplicacy backup -stats -threads 4
Storage set to odb://backup
Enter storage password:****************
No previous backup found
Listing all chunks
Indexing /Users/dejavu/Space/clink
Parsing filter file /Users/dejavu/Space/clink/.duplicacy/filters
Loaded 0 include/exclude pattern(s)
Uploaded chunk 0 size 104953, 11KB/s 00:00:01 99.8%
Uploaded .DS_Store (6148)
Uploaded Makefile (722)
Uploaded README.md (5102)
Uploaded index.h (2283)
Uploaded main.c (10175)
Uploaded mongoose.c (58270)
Uploaded mongoose.h (21683)
Uploaded doc/clink.conf (142)
Uploaded doc/clink.nginx (220)
Uploaded doc/clink.service (208)
Backup for /Users/dejavu/Space/clink at revision 1 completed
Files: 10 total, 102K bytes; 10 new, 102K bytes
File chunks: 1 total, 102K bytes; 1 new, 102K bytes, 45K bytes uploaded
Metadata chunks: 3 total, 1K bytes; 3 new, 1K bytes, 1K bytes uploaded
All chunks: 4 total, 104K bytes; 4 new, 104K bytes, 47K bytes uploaded
Total running time: 00:00:27

list 罗列

我们使用 list 命令列出有关快照的信息,命令帮助 3

$ duplicacy list -h
NAME:
   duplicacy list - 列出快照

USAGE:
   duplicacy list [Options]

OPTIONS:
   -all, -a  列出 Repository 中的所有快照
   -id <snapshot id>  列出指定的 Snapshot ID
   -r <revision> [+]  快照的修订编号 (revision)
   -t <tag>  列出具有制定标签的快照
   -files  打印每个快照中的文件列表
   -chunks  打印每个快照中的块,如果没有指定哪个快照,则打印所有块
   -reset-passwords  从输入中获取密码,而不是 Keychain 或 Keyring
   -storage <storage name>  从指定的 Storage 中检索快照
   -key <private key>  解密文件块的 RSA 私钥

可以列出我们现在的 Repository 快照信息

$ duplicacy list
Storage set to odb://backup
Snapshot cooldog revision 1 created at 2022-12-04 01:55 -hash

列出快照信息的同时打印文件列表 4

$ duplicacy list -files
Storage set to odb://backup
Snapshot cooldog revision 1 created at 2022-12-04 01:55 -hash
Files: 10
 6148 2022-12-04 01:34:42 6593a90dc7ef81b6e9e81893123649d5398109d9a8986940dad902549045fa49 .DS_Store
  722 2021-09-30 21:30:41 ba93b79806661d3de27563ec5870ea1601eede75757a5c70c24aebaa89f54271 Makefile
 5102 2021-09-30 21:30:41 2143edd665413b6282a4d90993a2465c2e355ce590cdbb4ec58d7d06a89d1f69 README.md
 2283 2021-09-30 21:30:41 588b03a366cedd57c6b541b86b9d0bf90b50a45f7c2654ba69a72ce0105cd4cf index.h
10175 2021-09-30 21:30:41 bf0849dc2d45ec3bb2ed243ad5fbba95c172390c0b0e277588a0a27432377b54 main.c
58270 2021-09-30 21:30:41 a0c55f14ffcef2773d422e6fa80cde9e7ed62c620cc35a76df51d960de3c8918 mongoose.c
21683 2021-09-30 21:30:41 b2b33093437598d63da4b2a3e70ec6f2c17dc248f71567f2ed0f024f49a7afde mongoose.h
  142 2021-09-30 21:30:41 706b0d61343e18c4aeb91435703a0617d308937ab9d7caca516ae0ee9f9e8a2d doc/clink.conf
  220 2021-09-30 21:30:41 667e15beb81904ce08f20c4d9ac92a33c45b2f6e375ccaef15453fe95a17ba68 doc/clink.nginx
  208 2021-09-30 21:30:41 a6e9a1db65655723b2aac6af3a2d4b1e1202c2e69eac55647c93262ab6f1d295 doc/clink.service
Total size: 104953, file chunks: 1, metadata chunks: 3

restore 恢复

restore 用于将 Repository 恢复到之前的修订版 revision,查看命令帮助 5

$ duplicacy restore -h
NAME:
   duplicacy restore - 将 Repository 恢复到之前保存的快照 (Snapshot)

USAGE:
   duplicacy restore [Options] [--] [Pattern] ...

OPTIONS:
   -r <revision>  快照的修订编号 (必需)
   -hash  通过 Hash 值检测文件差异 (而不是文件大小或时间戳)
   -overwrite  覆盖 Repository 中的现有文件
   -delete  删除不在快照中的文件
   -ignore-owner  不要在恢复的文件上设置原始 UID/GID (用户 ID/用户组 ID)
   -stats  显示恢复过程和完成后的统计数据
   -threads <n>  下载文件的线程数
   -limit-rate <kB/s>  全局下载速度限制 (单位 kb/s)
   -storage <storage name>  恢复到指定的 Storage 而不是 default Storage
   -key <private key>  用于解密文件块的 RSA 私钥
   -persist  即使存在块错误或已经存在的文件,仍然继续处理 (不使用 -overwrite), 并报告任何受影响的文件
   -key-passphrase <private key passphrase>  解密 RSA 私钥的口令 (Passphrase)

Repository 刚才第一次进行 backup 的时候有了第一个 revision,它应该是 1,我对 Repository 里的文件做了一些更改,现在文件目录树如下:

.
├── .DS_Store
├── .duplicacy
│   ├── cache
│   │   └── default
│   ├── odb-token.json
│   └── preferences
├── doc
│   ├── clink.conf
│   ├── clink.nginx
│   └── clink.service
└── index.h

4 directories, 7 files

可以看到,我删除了一些文件,现在我们要恢复到修订编号 (revision) 为 1 的快照

$ duplicacy restore -r 1 -threads 4 -overwrite -delete -ignore-owner -stats
Storage set to odb://backup
Loaded 0 include/exclude pattern(s)
Indexing /Users/dejavu/Space/clink
Parsing filter file /Users/dejavu/Space/clink/.duplicacy/filters
Loaded 0 include/exclude pattern(s)
Restoring /Users/dejavu/Space/clink to revision 1
Downloaded chunk 1 size 104953, 9KB/s 00:00:01 100.0%
Downloaded Makefile (722)
Downloaded README.md (5102)
Downloaded main.c (10175)
Downloaded mongoose.c (58270)
Downloaded mongoose.h (21683)
Restored /Users/dejavu/Space/clink to revision 1
Files: 6 total, 100K bytes
Downloaded 5 file, 94K bytes, 1 chunks
Skipped 5 file, 9K bytes
Total running time: 00:00:11

现在 Repository 就恢复到 revision 1 了

.
├── .DS_Store
├── .duplicacy
│   ├── cache
│   │   └── default
│   ├── odb-token.json
│   └── preferences
├── Makefile
├── README.md
├── doc
│   ├── clink.conf
│   ├── clink.nginx
│   └── clink.service
├── index.h
├── main.c
├── mongoose.c
└── mongoose.h

4 directories, 12 files

上面这些操作都是在当前计算机上完成的,如果在另一台服务器 6 上执行恢复操作呢?

# 假如这台服务器上也有这个目录
$ cd backup/clink

# 创建 Duplicacy 配置目录并将 OneDrive 访问令牌凭据文件上传到这个目录下
$ mkdir .duplicacy

# 初始化 Repository
$ duplicacy init -e cooldog odb://backup
Enter the path of the OneDrive token file (downloadable from https://duplicacy.com/one_start):.duplicacy/odb-token.json
Enter storage password for odb://backup:****************
The storage 'odb://backup' has already been initialized
Compression level: 100
Average chunk size: 4194304
Maximum chunk size: 16777216
Minimum chunk size: 1048576
Chunk seed: 04f4b3d5140215e00dbd78e619e41fea530a59a2e1f43d49214064e6d8ec01ef
/home/dejavu/backup/clink will be backed up to odb://backup with id cooldog

现在这个 Repository 还是空的

$ tree -L 3 -a
.
└── .duplicacy
    ├── odb-token.json
    └── preferences

1 directory, 2 files

在这台服务器上恢复修订编号 (revision) 为 1 的快照

$ duplicacy restore -r 1 -threads 4 -overwrite -delete -ignore-owner -stats
Storage set to odb://backup
Enter storage password:****************
Loaded 0 include/exclude pattern(s)
Indexing /home/dejavu/backup/clink
Parsing filter file /home/dejavu/backup/clink/.duplicacy/filters
Loaded 0 include/exclude pattern(s)
Restoring /home/dejavu/backup/clink to revision 1
Downloaded chunk 1 size 104953, 13KB/s 00:00:01 101.8%
Downloaded .DS_Store (6148)
Downloaded Makefile (722)
Downloaded README.md (5102)
Downloaded index.h (2283)
Downloaded main.c (10175)
Downloaded mongoose.c (58270)
Downloaded mongoose.h (21683)
Downloaded doc/clink.conf (142)
Downloaded doc/clink.nginx (220)
Downloaded doc/clink.service (208)
Restored /home/dejavu/backup/clink to revision 1
Files: 10 total, 102K bytes
Downloaded 10 file, 102K bytes, 1 chunks
Skipped 0 file, 0 bytes
Total running time: 00:00:08

恢复完成

$ tree -L 3 -a
.
├── doc
│   ├── clink.conf
│   ├── clink.nginx
│   └── clink.service
├── .DS_Store
├── .duplicacy
│   ├── cache
│   │   └── default
│   ├── odb-token.json
│   └── preferences
├── index.h
├── main.c
├── Makefile
├── mongoose.c
├── mongoose.h
└── README.md

4 directories, 12 files

check 验证

check 命令检查指定快照中所有引用的块是否存在 Storage 中,查看命令帮助 7

$ duplicacy check -h
NAME:
   duplicacy check - 检查快照完整性

USAGE:
   duplicacy check [Options]

OPTIONS:
   -all, -a  检查所有的 Snapshot ID
   -id <snapshot id>  检查指定的 Snapshot ID
   -r <revision> [+]  快照的修订编号 (revision)
   -t <tag>  检查具有制定标签的快照
   -fossils  如果找不到块则从参考 fossils 中检查
   -resurrect  将参考 fossils 转换回块
   -files  验证每个文件的完整性
   -chunks  验证每个块的完整性
   -stats  显示删除重复数据的统计信息 (隐含 -all 参数和所有修订编号)
   -tabular  使用表格式的使用情况和重复数据删除统计信息 (隐含 -stats, -all 参数和所有修订编号)
   -storage <storage name>  从指定的 Storage 中检索快照
   -key <private key>  解密加密文件块的 RSA 私钥
   -key-passphrase <private key passphrase>  解密 RSA 私钥的口令 (Passphrase)
   -threads <n>  验证块的线程数
   -persist  即使存在块错误,仍然继续处理,并报告受影响(损坏)的文件

cat 打印

cat 命令使用标准输出打印文件,查看命令帮助 8

# 查看帮助
$ duplicacy cat -h

# 查看修订编号 1
$ duplicacy cat -r 1

history 历史

history 命令显示关于文件 Hash 值、大小、时间戳在修订编号上变化的历史记录 9

# 查看 main.c 的历史记录
$ duplicacy history -r 1 main.c
Storage set to odb://backup
      1:           10175 2021-09-30 21:30:41 bf0849dc2d45ec3bb2ed243ad5fbba95c172390c0b0e277588a0a27432377b54 main.c
current:            9994 2022-12-04 13:08:50                                                                  main.c*

diff 比较

使用 diff 命令比较两个快照或两个修订版本之间文件的变化

# 比较 main.c 文件在修订编号 1 和 3 之间的变化
$ duplicacy diff -r 1 -r 3 main.c

# 比较修订编号 1 和 3 之间的变化
$ duplicacy diff -r 1 -r 3
Storage set to odb://backup
+ 58270 2021-09-30 21:30:41 a0c55f14ffcef2773d422e6fa80cde9e7ed62c620cc35a76df51d960de3c8918 head.c
+ 17705 2022-12-04 12:09:26 65a5308d783eaf2a17b532186b30e10014d08a112404a9d7ab827b425de52e2a head.h
  10175 2021-09-30 21:30:41 bf0849dc2d45ec3bb2ed243ad5fbba95c172390c0b0e277588a0a27432377b54 main.c
*  9994 2022-12-04 13:08:50 f81385aac1c2c805d22eab0cfd52fdcc294cc964cf9df93f704d0255e5ae517e main.c

password 密码

Duplicacy 在备份文件到 Storage 的时候会包含一个 config 文件,这个文件经过加密,password 命令会使用旧的密码揭秘这个文件,并使用新的密码重新加密该文件。修改这个密码 不会 改变用于加密或解密块和快照等文件的加密密钥。

我建议在没有理解这个设计的情况下,您不应当进行任何错误的修改。

$ duplicacy password -h
NAME:
   duplicacy password - 更改 Storage 的密码

USAGE:
   duplicacy password [Options]

OPTIONS:
   -storage <storage name>  指定特定 Storage 的密码(如果有多个 Storage)
   -iterations <i>  存储密钥推导中使用的迭代次数 (默认 16384)

benchmark 跑分

benchmark 命令运行一组基准测试,包含当前 Repository 使用某种 Storage 的上传/下载速度以及本地硬盘的访问速度。

$ duplicacy benchmark -h
NAME:
   duplicacy benchmark - 运行一组基准测试下载和上传速度

USAGE:
   duplicacy benchmark [Options]

OPTIONS:
   -file-size <size>  写入/读取的本地文件大小 (单位 MB, 默认值 256)
   -chunk-count <count>  上传/下载的块数量 (默认 64)
   -chunk-size <size>  上传/下载块的大小 (单位 MB, 默认值 4)
   -upload-threads <n>  上传线程的数量 (默认 1)
   -download-threads <n>  下载线程的数量 (默认 1)
   -storage <storage name>  指定 Storage 运行上传/下载基准测试 

这是我的本地访问 OneDrive Business 基准测试(😅 学校的垃圾 Gi-WiFI)

$ duplicacy benchmark  -upload-threads 2 -download-threads 2
Storage set to odb://backup
Generating 256.00M byte random data in memory
Writing random data to local disk
Wrote 256.00M bytes in 0.08s: 3351.40M/s
Reading the random data from local disk
Read 256.00M bytes in 0.02s: 12587.09M/s
Split 256.00M bytes into 52 chunks without compression/encryption in 1.02s: 251.87M/s
Split 256.00M bytes into 52 chunks with compression but without encryption in 1.26s: 202.83M/s
Split 256.00M bytes into 52 chunks with compression and encryption in 1.29s: 198.21M/s
Generating 64 chunks
Uploaded 256.00M bytes in 253.00s: 1.01M/s
Downloaded 256.00M bytes in 52.00s: 4.92M/s
Deleted 64 temporary files from the storage

这是国内一台小鸡的基准测试,OneDrive 国际版在国内只能说勉强能用

$ duplicacy benchmark  -upload-threads 2 -download-threads 2
Storage set to odb://backup
Enter the path of the OneDrive token file (downloadable from https://duplicacy.com/one_start):.duplicacy/odb-token.json
Generating 256.00M byte random data in memory
Writing random data to local disk
Wrote 256.00M bytes in 0.21s: 1221.80M/s
Reading the random data from local disk
Read 256.00M bytes in 0.25s: 1012.62M/s
Split 256.00M bytes into 52 chunks without compression/encryption in 1.68s: 152.79M/s
Split 256.00M bytes into 52 chunks with compression but without encryption in 2.30s: 111.39M/s
Split 256.00M bytes into 52 chunks with compression and encryption in 2.37s: 107.92M/s
Generating 64 chunks
Uploaded 256.00M bytes in 273.94s: 957K/s
Downloaded 256.00M bytes in 606.24s: 432K/s
Deleted 64 temporary files from the storage

可以多进行几次基准测试,然后调整块大小、上传/下载线程数量以获得最佳的性能。

set 设置

set 命令用于更改默认或指定 Storage 的选项,选项里有标记 [=true] 的可以用 false 来关闭,比如关闭加密: -e=false ;将密码或访问密钥保存到 Keychain 或 Keyring 中:-no-save-password=false,更多信息可以查看 Duplicacy 的密码管理

$ duplicacy set -h
NAME:
   duplicacy set - 更改默认或指定 Storage 的选项

USAGE:
   duplicacy set [Options]

OPTIONS:
   -encrypt, e[=true]  用密码对存储进行加密
   -no-backup[=true]  禁止备份到此 Storage
   -no-restore[=true]  禁止从此 Storage 恢复
   -no-save-password[=true]  不要将密码或访问密钥保存到 Keychain 或 Keyring 中
   -nobackup-file <file name>  包含此名称文件的目录不会被备份
   -exclude-by-attribute[=true]  根据文件属性排除文件 (仅 macOS 有效, 使用 com_apple_backup_excludeItem 处理)
   -key  添加一个密钥/密码,由 -value 选项提供
   -value  密钥/密码的值
   -storage <storage name>
   -filters <file path>  指定包含/排除使用的模式过滤器文件的路径

add 添加

add 命令给当前 Repository 添加一个新的 Storage,大部分选项和 init 初始化类似

$ duplicacy add -h
NAME:
   duplicacy add - Add an additional storage to be used for the existing repository

USAGE:
   duplicacy add [command options] <storage name> <snapshot id> <storage url>

OPTIONS:
   -e  使用密码加密 Storage
   -c <size>  块平均大小 (默认 4M)
   -max <size>  块最大大小 (默认 (块平均大小*4))
   -min <size>  块最大大小 (默认 (块平均大小/4))
   -iterations <i>  存储密钥推导中使用的迭代次数 (默认 16384)
   -copy <storage name>  使新 Storage 与现有 Storage 兼容,以进行复制操作
   -bit-identical  (当使用 -copy 的时候) 使新的 Storage 相同,也允许 rsync 等
   -repository <path>  在指定的路径而不是当前工作目录下初始化一个新的版本库。
   -key <public key>  用于加密文件块的 RSA 公钥
   -erasure-coding <data shards>:<parity shards>  启用擦除编码以防 Storage 损坏

需要注意的是 -bit-identical 不能直接将 config 文件从未加密的 Storage 复制到新的加密 Storage

copy 复制

copy 命令用于将快照从一个 Storage 复制到另一个 Storage,这两个 Storage 想要兼容复制,需要满足条件:一些配置参数必须相同,其中一个 Storage 在使用 add 命令添加的时候必须附加 -copy 选项进行初始化。查看命令帮助 10

$ duplicacy copy -h
NAME:
   duplicacy copy - 在兼容的 Storage 之间复制快照
USAGE:
   duplicacy copy [Options]

OPTIONS:
   -id <snapshot id>  指定 Snapshot ID 复制,而不是复制所有快照
   -r <revision> [+]  指定修订编号
   -from <storage name>  快照被复制的源 Storage
   -to <storage name>  快照复制到的目标 Storage
   -download-limit-rate <kB/s>  全局下载速度限制 (单位 kb/s)
   -upload-limit-rate <kB/s>	  全局上传速度限制 (单位 kb/s)
   -threads <n>  上传线程数
   -download-threads <n>  下载线程数
   -key <private key>  解密快照被复制的源 Storage 的 RSA 私钥
   -key-passphrase <private key passphrase>  解密 RSA 私钥的口令 (Passphrase)

prune 修剪

随着时间的推移,Storage 的空间占用越来越大,一般我们只需要保留一定「保留策略」的快照(比如七天、一个月、半年……),prune 命令用于在 Storage 中删除快照中过旧的或者不再需要的修订版本及未使用的块

$ duplicacy prune -h
NAME:
   duplicacy prune - 根据修订编号、标签和保留策略修剪快照

USAGE:
   duplicacy prune [command options]

OPTIONS:
   -id <snapshot id>  删除指定 Snapshot ID 的快照而不是默认快照
   -all, -a  匹配所有 Snapshot ID
   -r <revision> [+]  删除指定的修订编号
   -t <tag> [+]  删除带有指定标签的快照
   -keep <n:m> [+]  对于超过 m 天的快照,保留每 n 天一个快照
   -exhaustive  删除所有未引用的块 (不仅仅是被删除的快照引用的块)
   -exclusive  假设对 Storage 的独占访问 (禁止另外收集 fossil)
   -dry-run, -d  显示哪些内容会被删除
   -delete-only  删除之前收集的 fossil (如果可删除) 且不收集 fossil
   -collect-only  识别和收集 fossil 且不删除以前收集的 fossil
   -ignore <id> [+]  在决定是否可以删除 fossil 时忽略制定的 Snapshot ID 的快照
   -storage <storage name>  修剪指定 Storage 的快照
   -threads <n>  修剪未引用块的线程数

比如:

# 对于超过 30 天的修订,每 7 天保留一次修订
$ duplicacy prune -keep 7:30 

# 删除超过一年的备份
$ duplicacy prune -keep 0:365

# 指定多个 -keep 保留策略,按照 m 的降序排列
$ duplicacy prune -keep 0:360 -keep 30:180 -keep 7:30 -keep 1:7

一般地,假如多个 Repository 备份到同一个 Storage,建议只有一个 Duplicacy 实例运行 prune 修剪策略

需要卸载?

# 取消软链接
$ sudo rm -i /usr/local/bin/duplicacy

# 删除程序
$ sudo rm /opt/duplicacy

# Windows
$ scoop uninstall duplicacy

免费存储

在不付费的情况下可以白嫖的存储服务推荐(Duplicacy 支持使用的服务),对于重要的服务应当优先考虑稳定性。

服务名称免费层说明
Cloudflare R210GB 存储,下行流量免费A 类操作 100 万;B 类操作 1000 万;兼容 S3 API;需要绑定支付方式
OneDrive E5 Developer5TB~25TB 存储,完全免费国内机器连接慢,极少账号会翻车
OneDrive Personal5GB 存储,完全免费国内机器连接慢,账号稳定
Backblaze B210GB 存储,1GB 下行流量兼容 S3 API;Duplicacy 本身支持
Oracle Object Storage20GB 存储,10TB 下行流量兼容 S3 API;
阿里云 OOS5GB 存储,5GB 下行流量仅限香港区域,兼容 S3 API
Dropbox2GB 存储,完全免费国内被墙
FileBase5GB 存储,完全免费IPFS 区块链存储,兼容 S3 API
Scaleway75GB 存储,75GB 下行流量兼容 S3 API
Google Drive15GB 存储,完全免费Duplicacy 本身支持
Synology C215GB 存储,15GB 下行流量兼容 S3 API
Storj DCS150GB 存储,150GB 下行流量兼容 S3 API
IDrive E210GB 存储,10GB 下行流量兼容 S3 API
Tebi.io25GB 存储,250GB 下行流量兼容 S3 API
Getspace50GB 存储,完全免费支持 WebDAV,速度还行

  1. 三个块大小参数被传递给可变大小分块算法,他们会影响整体的性能。块太小,发送请求和接收响应会产生大量额外开销;块太大,每个块需要传输更多数据,重复数据删除的效果将不够明显。一旦初始化的时候设置了块大小相关的参数,就不能再修改! ↩︎

  2. 每次 backup 备份都会产生一个 修订编号 revision;默认情况下通过比较文件大小和时间戳来检测修改,使用 -hash 扫描会完全检测文件是否更改但会增加性能开销;调整线程数不会显著提高速度,线程数不建议超过 30;Repository 里多种 Storage 可以使用 -storage 指定; ↩︎

  3. 修订编号 (revision) 是快照创建的时候分配给它的一个数字,每次创建新的快照这个数字都会增加;-r 选项可以指定特定的 revision,比如 -r 1,也可以指定一个 revision 范围,比如 -r 1-99,可以同时设置多个 -r 选项;-reset-passwords 用于重置保存的密码; ↩︎

  4. 可以看到 macOS 存储文件目录属性的 .DS_Store 也被存到快照里了,我们后面介绍添加/排除文件 ↩︎

  5. 默认情况下 restore 不会覆盖现有文件,除非使用 - overwrite 选项; ↩︎

  6. 在多台不同的计算机上将某个 Repository 同步到同一个 Storage ,只要 Snapshot ID 一致,Duplicacy 就会认为它是同一个 Repository ↩︎

  7. 默认情况下只检查块的存在,如果指定 -files 选项回验证快照的完整性,这会下载块并计算 Hash值,以验证所有 Hash 值都匹配;-chunks 会检查一次每个块,将通过验证的块添加到 .duplicacy/cache/storage/verified_chunks 列表里,后续这些块不会再进行验证; ↩︎

  8. 如果未指定文件,则会打印整个快照内容; ↩︎

  9. 文件名末尾的 * 表示相比上一次修订编号该文件有了变动 ↩︎

  10. copy 复制会保留修订编号,目标 Storage 已经存在的修订编号,复制快照会失败;如果未指定 -from 源 Storage 选项,将复制默认 Storage 中的快照; ↩︎