POST / POSTS

Vaultwarden 备份与恢复架构及操作指南

AI摘要
本文围绕一套基于 Docker Compose、PostgreSQL、ttionya/vaultwarden-backup、rclone 与 WebDAV 的 Vaultwarden 备份恢复方案,系统介绍备份对象、执行链路、加密策略、定时调度、远端归档与恢复流程,并给出可直接落地的备份与恢复操作命令,适用于需要建立标准化口令库容灾能力的自托管场景。

Vaultwarden 备份与恢复架构及操作指南

一、引言

Vaultwarden 作为一套常见的自托管密码管理服务,通常承载着用户账号、附件、密钥材料以及发送文件等关键数据。一旦出现误操作、容器损坏、主机迁移或数据库异常,若缺少成体系的备份与恢复方案,将直接影响业务连续性与数据安全。

本文基于一套已经落地的 Vaultwarden + PostgreSQL + Docker Compose + WebDAV 方案,给出一份完整的技术说明。文章重点覆盖以下内容:

  • Vaultwarden 当前备份架构的组成与职责划分
  • 备份链路中的数据范围、加密方式、调度策略与远端归档方式
  • 备份任务的实施步骤与验证方法
  • 恢复操作的执行路径、命令示例与注意事项

本文中的示例目录采用 /home/heaven/docker/vaultwarden,如实际部署路径不同,可按同样思路调整。


二、备份对象与系统现状

在当前部署中,Vaultwarden 运行于 Docker Compose 中,主服务数据目录通过宿主机绑定挂载到 ./data,数据库使用 PostgreSQL,而不是默认的 SQLite。

从备份视角看,一套完整的 Vaultwarden 数据至少应包含以下内容:

  • db.dump PostgreSQL 数据库导出的逻辑备份文件,保存组织、用户、凭据条目、集合关系等结构化数据。
  • rsa_key* Vaultwarden 使用的 RSA 密钥材料。
  • attachments 条目附件目录。
  • sends Send 功能相关的数据目录。
  • config.json 若部署使用该文件存放配置,则也应纳入备份;若当前实例完全由环境变量驱动,备份工具会在执行时跳过该文件。

因此,备份方案不能只停留在数据库导出层面,而应覆盖数据库 + 文件目录 + 密钥材料三类核心资产。


三、整体备份架构设计

1. 架构组件

当前方案包含以下关键组件:

  • vaultwarden 主业务容器,负责对外提供密码管理服务。
  • postgres16 PostgreSQL 数据库容器,存放 Vaultwarden 核心业务数据。
  • ttionya/vaultwarden-backup 专用备份容器,用于读取 Vaultwarden 数据目录、导出 PostgreSQL、打包并上传归档。
  • rclone 负责把加密后的备份文件推送到远端 WebDAV 存储。
  • WebDAV 远端备份存储目标,用于保存最终归档文件。
  • cron 宿主机调度器,用于在每天固定时间触发一次性备份容器。

2. 数据流向

整个备份链路可以抽象为如下流程:

TEXT
宿主机 cron(每天 03:00)
docker compose run --rm backup
          ├── 读取 Vaultwarden 数据目录 /data
          ├── 连接 PostgreSQL 导出 db.dump
          ├── 打包 rsa_key / attachments / sends
          ├── 使用 7z + 密码进行加密压缩
          ├── 通过 rclone 上传到 WebDAV
          └── 清理容器内临时文件,并删除远端 5 天前备份

3. 设计要点

该方案有四个关键设计点:

第一,备份容器采用一次性运行模式。
backup 服务通过 docker compose run --rm 触发,每次备份结束后容器即退出,不长期驻留,运维边界更清晰。

第二,备份中间文件不在宿主机持久保留。
备份包在容器内部临时生成,上传完成后即清理,宿主机只保留日志文件。这种方式降低了本地明文归档残留风险。

第三,远端存储使用 WebDAV,归档通过 rclone 实现。
这使得备份目标可以灵活切换到支持 WebDAV 的网盘、对象存储网关或私有云盘系统。

第四,归档启用加密压缩。
备份包采用 7z 格式并配置独立压缩密码,避免远端存储侧直接暴露敏感业务数据。


四、Docker Compose 中的备份服务设计

在当前系统中,backup 服务并不常驻,而是作为一个随调随起的任务型容器存在。核心配置可整理为如下形式:

YAML
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8380:80"
    volumes:
      - ./data:/data
    environment:
      - DATABASE_URL=postgresql://vaultwarden:<db-password>@postgres16:5432/vaultwarden
    networks:
      - javdb_bridge

  backup:
    image: ttionya/vaultwarden-backup:latest
    command: ["backup"]
    restart: "no"
    volumes:
      - ./data:/data:ro
      - /home/heaven/.config/rclone:/config/rclone:ro
      - ./.backup_zip_password:/run/secrets/zip-password:ro
    environment:
      - TIMEZONE=Asia/Shanghai
      - DATA_DIR=/data
      - DB_TYPE=postgresql
      - PG_HOST=postgres16
      - PG_PORT=5432
      - PG_DBNAME=vaultwarden
      - PG_USERNAME=vaultwarden
      - PG_PASSWORD=<db-password>
      - RCLONE_REMOTE_NAME=clouddrive2-dav
      - RCLONE_REMOTE_DIR=115/backup/vault
      - ZIP_ENABLE=true
      - ZIP_PASSWORD_FILE=/run/secrets/zip-password
      - ZIP_TYPE=7z
      - BACKUP_KEEP_DAYS=5
      - BACKUP_FILE_SUFFIX=%Y%m%d-%H%M%S
      - DISPLAY_NAME=vaultwarden
    networks:
      - javdb_bridge

networks:
  javdb_bridge:
    external: true

上述配置中,最值得关注的参数如下:

  • DATA_DIR=/data 指定 Vaultwarden 实际数据目录。
  • DB_TYPE=postgresql 显式切换到 PostgreSQL 备份模式。
  • PG_HOST=postgres16 使用容器网络内的数据库服务名,而不是宿主机 IP。
  • RCLONE_REMOTE_NAMERCLONE_REMOTE_DIR 指向已经配置好的 rclone remote 和远端目录。
  • ZIP_PASSWORD_FILE 通过只读文件向容器提供压缩密码,而不是把密码直接暴露在命令行中。
  • BACKUP_KEEP_DAYS=5 表示删除 5 天之前的远端备份文件,保留最近 5 天归档。

五、备份实施步骤

1. 准备压缩密码文件

建议在 Compose 目录下为压缩密码单独准备一个只读文件,并收紧权限:

SHELL
cd /home/heaven/docker/vaultwarden
umask 077
openssl rand -base64 48 > .backup_zip_password
chmod 600 .backup_zip_password

该文件是后续解密恢复的关键凭据,必须进行离线保管。

2. 确认 rclone 配置可用

当前方案直接复用宿主机现有的 rclone.conf。可通过如下命令确认 remote 是否存在:

SHELL
rclone config show

若需要确认远端目录可访问,可执行:

SHELL
rclone lsd clouddrive2-dav:115/backup/vault

3. 注册每日定时任务

当前系统采用宿主机 cron 统一调度,而不是让备份容器内部自行常驻并调度。建议使用如下任务:

CRON
0 3 * * * cd /home/heaven/docker/vaultwarden && /usr/bin/docker compose run --rm -T backup >> /home/heaven/docker/vaultwarden/vaultwarden-backup.log 2>&1

这条任务表达的含义是:

  • 每天凌晨 03:00 进入 Vaultwarden Compose 目录
  • 启动一次 backup 服务
  • 备份结束后自动移除容器
  • 将标准输出和错误输出统一写入 vaultwarden-backup.log

4. 手工触发一次备份

在定时任务正式投入使用前,应先人工执行一次,验证参数和链路:

SHELL
cd /home/heaven/docker/vaultwarden
docker compose run --rm -T backup

若执行正常,日志中通常会看到如下关键信息:

  • 备份 PostgreSQL 数据库
  • 打包 rsa_keyattachmentssends
  • 生成 backup.<timestamp>.7z
  • 上传到远端目录
  • 删除 5 天之前的远端历史文件

5. 验证备份结果

可从两个维度进行验证。

其一,检查本地日志:

SHELL
tail -n 80 /home/heaven/docker/vaultwarden/vaultwarden-backup.log

重点确认是否包含:

  • backup vaultwarden postgresql database
  • package backup file
  • upload backup file to storage system

其二,检查远端文件是否生成:

SHELL
rclone lsl clouddrive2-dav:115/backup/vault | tail -n 10

若输出中出现类似 backup.20260407-161447.7z 的文件,说明上传已经完成。


六、恢复架构设计

备份体系的真正价值并不在于“能生成备份文件”,而在于“能可靠恢复”。从恢复链路上看,当前方案包含如下步骤:

TEXT
WebDAV 远端备份包
rclone 下载到本地 restore 目录
停止 vaultwarden 主服务
启动 restore 容器并挂载:
  - 目标数据目录
  - 待恢复备份文件目录
  - 压缩密码文件
  - PostgreSQL 网络
解密 7z 归档并恢复:
  - db.dump -> PostgreSQL
  - rsa_key / attachments / sends -> /data
重新启动 vaultwarden 并验证登录、条目与附件

这里有两个原则必须明确:

  • 恢复会覆盖现有数据。
  • 恢复前必须停止 Vaultwarden 主服务,但 PostgreSQL 必须保持可连接。

七、标准恢复操作步骤

1. 从 WebDAV 下载目标备份文件

首先在本地准备一个恢复目录,并把指定时间点的备份包下载下来:

SHELL
mkdir -p /home/heaven/docker/vaultwarden/restore

rclone copyto \
  clouddrive2-dav:115/backup/vault/backup.20260407-161447.7z \
  /home/heaven/docker/vaultwarden/restore/backup.20260407-161447.7z

对于生产环境,建议先明确恢复点,再执行下载,不要在恢复时临时挑选文件。

2. 停止 Vaultwarden 服务

恢复前应先停止主业务容器,避免恢复过程中业务继续写入:

SHELL
cd /home/heaven/docker/vaultwarden
docker compose stop vaultwarden

3. 执行恢复命令

当前系统使用 PostgreSQL,因此恢复容器必须加入与数据库相同的 Docker 网络,并显式带上数据库连接参数:

SHELL
docker run --rm -it \
  --network javdb_bridge \
  --mount type=bind,source=/home/heaven/docker/vaultwarden/data,target=/data \
  --mount type=bind,source=/home/heaven/docker/vaultwarden/restore,target=/bitwarden/restore \
  --mount type=bind,source=/home/heaven/docker/vaultwarden/.backup_zip_password,target=/run/secrets/zip-password,readonly \
  -e DATA_DIR=/data \
  -e DB_TYPE=postgresql \
  -e PG_HOST=postgres16 \
  -e PG_PORT=5432 \
  -e PG_DBNAME=vaultwarden \
  -e PG_USERNAME=vaultwarden \
  -e PG_PASSWORD=<db-password> \
  -e ZIP_PASSWORD_FILE=/run/secrets/zip-password \
  ttionya/vaultwarden-backup:latest restore \
  --zip-file /bitwarden/restore/backup.20260407-161447.7z

若需要跳过交互确认,可以附加 --force-restore 参数,但生产环境应谨慎使用。

4. 启动服务并验证恢复结果

恢复完成后,重新拉起 Vaultwarden 服务:

SHELL
cd /home/heaven/docker/vaultwarden
docker compose up -d vaultwarden

随后建议执行如下验证:

  • 登录后台并检查用户是否可正常认证
  • 抽查若干关键条目是否存在
  • 检查附件是否可访问
  • 检查 Send 数据是否可读取
  • 查看容器日志中是否存在数据库连接或解密异常

八、备份与恢复中的注意事项

1. 不要把压缩密码写入公开配置

压缩密码决定了远端归档的可恢复性。若直接写入 Compose 文件、Shell 历史或公开仓库,将显著放大安全风险。更稳妥的做法是使用独立只读文件或 Secret 机制。

2. BACKUP_KEEP_DAYS=5 是“按天保留”,不是“按文件数保留”

该配置的语义是删除超过 5 天的远端备份,而不是只保留最近 5 个文件。如果一天执行多次备份,远端可能会同时保留多个同日文件。

3. 恢复演练必须定期执行

只存在备份而从未恢复验证的方案,并不能视为真正可用的灾备体系。建议至少定期在测试环境执行一次全量恢复演练。

4. config.json 缺失不一定是异常

若当前实例完全通过环境变量配置,备份工具会提示 config.json 不存在并跳过,这是符合预期的,不应误判为备份失败。

5. 恢复前应额外保留当前状态快照

即便已经选定历史恢复点,在覆盖恢复之前,仍建议对当前线上状态再执行一次紧急备份,以便在恢复点选择错误时回滚。


九、结语

对于 Vaultwarden 这类承载高敏感数据的系统,备份与恢复不能仅以“数据库导出成功”作为交付标准,而应形成一套完整的工程闭环:明确备份对象、控制加密与保留策略、验证远端归档、固化恢复命令,并定期执行恢复演练。

本文所介绍的方案,以 ttionya/vaultwarden-backup 作为核心备份执行器,结合 rclone + WebDAV + cron 完成归档与调度,具备结构清晰、依赖简单、易于验证和易于迁移的特点。对于采用 Docker Compose 部署、并以 PostgreSQL 作为后端数据库的 Vaultwarden 实例,这是一套可直接复用的标准化备份恢复方案。