Skip to content

Runbook — Vaultwarden backup & restore

Vaultwarden runs as a native systemd unit on pi-home (DietPi). Its data is a single SQLite database plus the web vault and icon cache.

  • Unit: vaultwarden.service (User=vaultwarden)
  • Data root: /mnt/dietpi_userdata/vaultwarden (146 MB, the data root)
  • db.sqlite3 (+ -wal, -shm) — the passwords
  • web-vault/ — static, can be re-copied
  • icon_cache/, tmp/, attachments/ — replaceable
  • vaultwarden.env (chmod 600), cert.pem, privkey.pem, rsa_key.pem — config + TLS keypair

Backup status. Vaultwarden is covered by the pi-home data branch: nightly restic of /mnt/dietpi_userdata to BOTH /mnt/pi-hdd/ backups/pi-home/data (physical) and gdrive:backups/pi-home/data (off-site). The backup copies the SQLite files as they are — if the restore ever looks torn, fall back to the manual online backup (Option A) below, which is still the cleanest for a known-good single file.

Backup — manually, on demand

Because the DB is SQLite with a running process, do not just copy the file mid-write — the -wal may not be checkpointed and the copy could be torn. Use Vaultwarden's dump or stop the service.

Run an online VACUUM INTO to get a consistent snapshot (or the Bitwarden sqlite3 backup):

# pi-home
sqlite3 /mnt/dietpi_userdata/vaultwarden/db.sqlite3 \
  "VACUUM INTO '/var/tmp/vaultwarden-backup.sqlite3'"
# verify it opens + check count
sqlite3 /var/tmp/vaultwarden-backup.sqlite3 \
  "SELECT count(*) FROM users; SELECT count(*) FROM ciphers;"
cp /mnt/dietpi_userdata/vaultwarden/vaultwarden.env /var/tmp/

Option B — stop, copy, start (most thorough)

sudo systemctl stop vaultwarden
sudo -u vaultwarden cp -a /mnt/dietpi_userdata/vaultwarden /var/tmp/vaultwarden-full
sudo systemctl start vaultwarden

Copy /var/tmp/vaultwarden* somewhere durable (a Drive remote, the pi-home backup tree, or the restic repo) — /var/tmp is tmpfs and won't survive a reboot.

Restore

  1. Stop Vaultwarden:
    sudo systemctl stop vaultwarden
    
  2. Back up whatever is live first (in case you want to roll back):
    sudo mv /mnt/dietpi_userdata/vaultwarden/db.sqlite3{,.pre-restore}
    
  3. Restore the DB + env from the good snapshot, keeping ownership:
    sudo -u vaultwarden cp <snapshot>/db.sqlite3 \
      /mnt/dietpi_userdata/vaultwarden/db.sqlite3
    sudo -u vaultwarden cp <snapshot>/vaultwarden.env \
      /mnt/dietpi_userdata/vaultwarden/vaultwarden.env
    
    Remove stray -wal/-shm for the restored DB so SQLite re-inits cleanly:
    sudo rm -f /mnt/dietpi_userdata/vaultwarden/db.sqlite3-wal \
               /mnt/dietpi_userdata/vaultwarden/db.sqlite3-shm
    
  4. Start and verify:
    sudo systemctl start vaultwarden
    sudo systemctl status vaultwarden --no-pager
    
    Log in with a known-good credential; confirm a recent password/entry is present. Check the DB has your user count:
    sqlite3 /mnt/dietpi_userdata/vaultwarden/db.sqlite3 \
      "SELECT count(*) FROM users; SELECT count(*) FROM ciphers;"
    
  5. Keep db.sqlite3.pre-restore until you're certain, then remove it.

Make this safe going forward

The pi-home timers back up /mnt/dietpi_userdata nightly to pi-hdd + gdrive. The rest of this section is fallback tooling:

  1. Manual online backup (Option A) still useful before risky changes — it produces one consistent VACUUM INTO file.
  2. Restore path: pull the latest pi-home/data snapshot per the restic-restore runbook, then follow the Restore section here (stop → db.sqlite3.pre-restore → restore DB + env → remove -wal/-shm → start → verify counts).
  3. Track open backup items in the GitHub Issues on this repo (the off-site leg depends on the gdrive OAuth client staying usable).