一、部署目标

我这里的诉求是:

  1. Vaultwarden 正常运行

  2. 备份容器每天自动打包 Vaultwarden 数据

  3. 本地保留最近 7 天备份

  4. 自动上传到 RustFS S3

  5. AK/SK 只给现有桶权限,不给建桶权限

其中 ttionya/vaultwarden-backup 本身就是给 Vaultwarden 做自动备份的镜像,支持定时任务、压缩、远端同步;远端上传依赖 rclone。(github.com)
rclone 的 S3 后端支持自定义 endpoint 和 force_path_style,适合 RustFS 这类 S3 兼容存储。(rclone.org)

二、目录结构

先准备一个目录:

mkdir -p ~/bitwarden
cd ~/bitwarden
mkdir -p bw-data vw-backups

最终目录大概是这样:

bitwarden/
├── docker-compose.yml
├── bw-data/
└── vw-backups/

这里:

  • bw-data/ 存 Vaultwarden 数据

  • vw-backups/ 存本地备份文件


三、完整 docker-compose.yml

直接上完整配置:

version: '3'

services:
  bitwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "480:80"
      - "4443:443"
    volumes:
      - ./bw-data:/data
    environment:
      - SMTP_HOST=smtp.office365.com
      - SMTP_FROM=yourmail@example.com
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - SMTP_USERNAME=yourmail@example.com
      - SMTP_PASSWORD=yourpassword
      - ADMIN_TOKEN=yourtoken
      - SIGNUPS_ALLOWED=false
      - DOMAIN=https://your.domain.com

  backup:
    image: ttionya/vaultwarden-backup:latest
    container_name: vaultwarden-backup
    restart: unless-stopped
    depends_on:
      - bitwarden
    volumes:
      - ./bw-data:/bitwarden/data/
      - ./vw-backups:/backup/
      - vaultwarden-rclone-data:/config/
    environment:
      - TIMEZONE=Asia/Singapore
      - CRON=30 3 * * *
      - ZIP_ENABLE=TRUE
      - ZIP_PASSWORD=改成你的备份压缩密码
      - BACKUP_KEEP_DAYS=7
      - BACKUP_FILE_SUFFIX=%Y%m%d
      - RCLONE_REMOTE_NAME=BitwardenBackup
      - RCLONE_REMOTE_DIR=你的桶名/vaultwarden
      - RCLONE_GLOBAL_FLAG=--s3-no-check-bucket

volumes:
  vaultwarden-rclone-data:
    name: vaultwarden-rclone-data

这份配置里最关键的是:

  • ./bw-data:/bitwarden/data/:把 Vaultwarden 数据给备份容器读取

  • ./vw-backups:/backup/:本地备份输出目录

  • vaultwarden-rclone-data:/config/:rclone 配置单独放 Docker volume

  • RCLONE_GLOBAL_FLAG=--s3-no-check-bucket:禁止 rclone 检查或尝试创建 bucket,适合只有现有桶权限的 AK/SK。(github.com )


四、为什么不用宿主机目录挂载 rclone.conf

一开始我也尝试过这种写法:

- ./vw-backup-config:/config/

理论上没错,但实际排查过程中很容易踩坑:

  • 文件路径看似对,容器里却读不到

  • 配置文件名对了,rclone 还是不识别

  • 容器重启太快,不方便排查

  • bind mount 下权限和路径问题更杂

后来直接改成 Docker volume:

- vaultwarden-rclone-data:/config/

就稳定多了。因为这个备份镜像文档本身也一直在用 volume 方式挂 /config/,并且推荐通过 rclone config 直接往这个 volume 写配置。(github.com )


五、创建 rclone 配置 volume

先创建 volume:

docker volume create vaultwarden-rclone-data

六、进入 rclone 交互配置

执行:

docker run --rm -it \
  --mount type=volume,source=vaultwarden-rclone-data,target=/config/ \
  ttionya/vaultwarden-backup:latest \
  rclone config

第一次会看到类似:

Config file "/config/rclone/rclone.conf" not found - using defaults
No remotes found, make a new one?
n) New remote
s) Set configuration password
q) Quit config

这个是正常的,因为它明确告诉你:
它实际使用的 rclone 配置文件路径是:

/config/rclone/rclone.conf

七、rclone 交互配置怎么填

按下面填写即可。

1. 新建 remote

输入:

n

2. 名称

输入:

BitwardenBackup

这里要和 compose 里的:

- RCLONE_REMOTE_NAME=BitwardenBackup

保持一致。

3. Storage

输入:

s3

4. provider

输入:

Other

5. env_auth

输入:

false

6. access_key_id

输入你的 RustFS AK

7. secret_access_key

输入你的 RustFS SK

8. region

输入:

us-east-1

很多 S3 兼容存储这里写一个占位 region 就行,rclone 的 S3 后端支持这样做。(rclone.org )

9. endpoint

这里一定要填 RustFS 的 S3 API 地址,不要填 console 地址。

例如:

https://s3.example.com

或者:

http://1.2.3.4:9000

如果你填成类似 s3-console.xxx,很可能会失败,因为控制台地址和 S3 API 地址不是一回事。(docs.rustfs.com )

10. acl

输入:

private

11. force_path_style

输入:

true

RustFS 对路径风格访问是兼容的,rclone 这边也支持 force_path_style。(docs.rustfs.com )

12. 其他选项

其余大部分直接回车默认即可,最后保存退出。


八、验证 rclone 配置

执行:

docker run --rm -it \
  --mount type=volume,source=vaultwarden-rclone-data,target=/config/ \
  ttionya/vaultwarden-backup:latest \
  rclone config show

如果正常,会看到类似:

[BitwardenBackup]
type = s3
provider = Other
access_key_id = xxxx
secret_access_key = xxxx
endpoint = https://你的S3接口地址
region = us-east-1
acl = private
force_path_style = true

看到这一段,说明 rclone 配置已经真正写进 volume 了。


九、启动服务

执行:

docker compose up -d

看容器状态:

docker ps

正常情况下会看到:

  • vaultwarden

  • vaultwarden-backup

都处于运行状态。


十、手动触发一次备份

虽然已经配了定时任务,但第一次最好手动跑一次验证。

执行:

docker exec vaultwarden-backup bash /app/backup.sh

如果正常,流程大概是:

  1. 读取 /bitwarden/data

  2. 打包生成 zip 备份

  3. 写入本地 /backup

  4. 上传到 BitwardenBackup:你的桶名/vaultwarden


十一、查看日志

实时看日志:

docker logs -f vaultwarden-backup

重点看有没有:

  • 本地备份成功

  • 上传成功

  • 本地旧备份清理成功


十二、几个关键参数解释

1. TIMEZONE

- TIMEZONE=Asia/Singapore

如果机器在新加坡,直接用 Asia/Singapore 即可。

2. CRON

- CRON=30 3 * * *

表示:

每天凌晨 3:30 自动备份一次

3. BACKUP_KEEP_DAYS

- BACKUP_KEEP_DAYS=7

表示:

本地备份保留 7 天,旧备份自动清理

4. RCLONE_REMOTE_DIR

- RCLONE_REMOTE_DIR=你的桶名/vaultwarden

这里不是随便写字符串。

rclone 的远端路径语法是:

remote:bucket/path

所以这里的含义是:

  • 你的桶名 = bucket

  • vaultwarden = bucket 里的目录

rclone 的 S3 路径规则就是这样。(rclone.org )

5. RCLONE_GLOBAL_FLAG

- RCLONE_GLOBAL_FLAG=--s3-no-check-bucket

这是这套配置里最关键的一行之一。

因为很多时候 AK/SK 只给了某个现有 bucket 的读写权限,并没有 CreateBucket 权限。

如果不加这个参数,rclone 可能会先检查或尝试创建 bucket,结果直接报:

CreateBucket ... AccessDenied

--s3-no-check-bucket 就是告诉 rclone:

不要检查,也不要尝试创建 bucket。(rclone.org )


十三、常见报错

1. rclone configuration information not found

说明备份容器没有读到 rclone 配置。

如果你用了我上面这套 volume 挂载 /config/ 的方法,通常不会再遇到这个问题。

重点检查:

  • vaultwarden-rclone-data:/config/ 是否写对

  • rclone config 是否真的写进了 volume

  • RCLONE_REMOTE_NAME 和 remote 名是否一致


2. CreateBucket ... AccessDenied

说明:

  • 你的 bucket 已存在

  • 你的 AK/SK 没有建桶权限

  • rclone 却在上传前尝试了 CreateBucket

解决方式就是加:

- RCLONE_GLOBAL_FLAG=--s3-no-check-bucket

并保证:

- RCLONE_REMOTE_DIR=现有桶名/目录名

3. endpoint 填成 console 地址

错误示例:

endpoint = https://s3-console.example.com

正确思路应该是:

endpoint = https://s3.example.com

也就是填 S3 API 地址,不是 Web 控制台地址。RustFS 文档也区分了控制台和对象存储接口。(docs.rustfs.com )