跳到正文
SupaCove文档

06 / 13

存储目的地

把加密备份上传到你自己的 S3、Cloudflare R2 或 Backblaze B2 存储桶,可在控制台或通过 API 配置

目的地是你自己的一个存储桶,SupaCove 会把每份加密备份上传到那里。没有配置目的地时,备份只保存在实例的本地磁盘上。

目的地绑定到数据库之后,手动备份和定时备份都会自动使用它。目的地可以在控制台里配置,也可以通过 HTTP API 配置;没有命令行或环境变量的方式。

两种方式都于 2026-10-08 在本地实例上实际执行过,使用 MinIO 作为 S3 兼容存储。Cloudflare R2 和 Backblaze B2 走的是同一套代码,但我们还没有在真实服务上测试过。

在控制台里配置

打开顶部导航的存储。

  1. 添加目的地。 填写平台、存储桶和凭据(字段与 API 相同),点击“测试并添加”。保存之前会先测试存储桶;失败时显示存储服务商的错误信息,不会保存任何内容。
  2. 各数据库的上传位置。 在第二个面板里为每个数据库选择目的地。选“无”表示备份只留在本实例。更改从下一次备份起生效;该数据库有备份正在运行时会被拒绝。

每个目的地所在的行还有测试(写入、读回并删除一个测试对象)、把存储桶与实例记录做比较的对账按钮,以及删除。仍有数据库上传到该目的地时,删除会被拒绝。

本页余下部分介绍如何通过 API 完成同样的操作。

在命令行里登录

API 使用和控制台相同的会话:一个会话 cookie,外加每个修改类请求都要带的 CSRF 令牌。

BASE=https://backup.example.com/api

# 1. 登录,cookie 会写入 cookies.txt
curl -s -c cookies.txt -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"<你的密码>"}' \
  "$BASE/auth/login"

# 2. 从 cookie 文件里取出 CSRF 令牌
CSRF=$(awk '$6 ~ /sb_csrf$/ {print $7}' cookies.txt)

之后:

  • GET 请求只需要 -b cookies.txt。
  • POST、PUT、DELETE 还要加 -H "X-CSRF-Token: $CSRF";带请求体时再加 -H 'Content-Type: application/json'。

这一步常见的错误:

响应原因
401 unauthenticated没带会话 cookie,或会话已过期(7 天)。重新登录并重新读取 CSRF 令牌。
403 csrf缺少 X-CSRF-Token 请求头,或令牌属于另一个会话。
403 cross_origin请求带了与实例不一致的 Origin 请求头。curl 默认不发送,不要自己加。

cookie 的名字是 __Host-sb_session 和 __Host-sb_csrf。只有以 SB_INSECURE_COOKIE=1 运行的实例(明文 HTTP 的开发环境)才没有 __Host- 前缀。上面的 awk 命令两种都能匹配。

创建目的地

存储桶必须事先存在,SupaCove 不会替你创建。

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
  -d '{
    "name": "offsite-s3",
    "platform": "s3",
    "region": "eu-central-1",
    "bucket": "my-backups",
    "prefix": "supacove",
    "accessKey": "<access key id>",
    "secretKey": "<secret access key>",
    "verifyReadback": true,
    "keepRemote": 10,
    "keepDays": 0
  }' \
  "$BASE/destinations"

保存之前,服务端会往桶里写入一个很小的测试对象,读回来比对,再删除。其中任何一步失败都会返回 422 diagnostic_test_failed 并附上存储服务商的错误信息,不会保存任何内容。成功时返回 201 和目的地信息,其中包含 id。

因此凭据也需要删除权限,保留策略清理本来也需要它。

字段

字段必填说明
name是去掉首尾空格后 1–100 个 UTF-8 字节(一个汉字占三个),不能重名
platform否s3(默认)、r2 或 b2
endpointr2、b2 必填http(s)://host[:port],不带路径。s3 可不填;对接 S3 兼容服务时填写
regionb2 必填s3 默认 us-east-1,r2 默认 auto
bucket是合法的 S3 桶名:3–63 个字符,小写字母、数字、点和短横线
prefix否字母、数字、/、.、_、-;不允许出现 ..。首尾的斜杠会被去掉,再在末尾补一个。留空表示桶的根目录
accessKey、secretKey是需要能在该前缀下写入、读取、列出和删除对象
keepRemote否每个数据库保留的份数,默认 10,最小 1
keepDays否按天数保留的上限;0(默认)表示不启用
verifyReadback否默认 true。会保存并原样返回,见下方说明

keepRemote 与 keepDays 如何生效、哪些备份永远不会被清理,见计划与保留。

读回校验无法关闭

每次上传后都会从桶里读回密文,并与密文的 SHA-256 比对。这项检查始终执行:verifyReadback 会被保存并原样返回,但把它设为 false 并不会跳过校验。

凭据如何保存

secretKey 在写入数据库之前用实例的主密钥加密;accessKey 以明文保存。两者都不会出现在 API 的响应里。主密钥一旦更换,已保存的密钥就无法读取,目的地需要重新创建。

绑定到数据库

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
  -X PUT -d '{"destinationId": 1}' \
  "$BASE/databases/1/destination"

用 GET $BASE/databases 和 GET $BASE/destinations 可以查到各自的 id。一个数据库最多绑定一个目的地。从下一次备份开始,只有密文和清单都提交到桶里之后,任务才算 succeeded,此时它的 remoteState 为 committed。

每份备份在桶里是 <prefix>backups/ 下的两个对象:密文(….dump.age)和清单(….manifest.json)。

之后的检查

# 重新执行一次 写入 / 读取 / 删除 测试
curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -X POST "$BASE/destinations/1/test"

# 把桶里的内容和实例的记录做对账
curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -X POST "$BASE/destinations/1/reconcile"

对账报告给出 remoteObjects 和 matched 两个计数,并列出 orphaned(桶里有、实例没有记录)、missing(有记录、桶里没有)和 uncommitted 的对象。它只做比较,不修复也不删除任何东西。

下载远端备份

curl -s -b cookies.txt "$BASE/tasks/7/download-url"

响应里是密文的预签名地址,有效期 15 分钟。这个地址指向目的地自己的 endpoint,所以下载的机器必须能访问到它。

修改目的地

没有更新接口。新建一个目的地,把数据库改绑过去,再删除旧的。

删除目的地

先解绑,再删除:

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H 'Content-Type: application/json' \
  -X PUT -d '{"destinationId": null}' \
  "$BASE/databases/1/destination"

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -X DELETE "$BASE/destinations/1"

删除做了什么、没做什么:

  • 仍有数据库绑定该目的地时会被拒绝,返回 409 in_use;有上传正在进行时返回 409 upload_in_flight。
  • 它把目的地从实例里移除。桶里的对象原样保留。
  • 已经上传到那里的备份不能再通过 download-url 获取,该接口会返回 409 destination_removed。需要直接从桶里取。

错误码

状态码错误码含义
400invalid_request某个字段没通过校验,消息里会指明
409name_exists已有同名的目的地
422diagnostic_test_failed测试对象无法写入、读回或删除,附带服务商的错误信息
409not_assignable绑定失败,例如目的地 id 不存在
409in_use仍有数据库绑定该目的地,拒绝删除
409upload_in_flight有上传在进行,拒绝删除
409destination_removed对目的地已被删除的备份请求 download-url
404not_found目的地 id 不存在

最后更新

本页目录