Note: Vaultwarden was formerly known as bitwarden_rs.
This repo contains my automated setup for SQLite-based Vaultwarden backups. It's designed solely to meet my own backup requirements (i.e., not to be general purpose):
-
Generate a single archive with a complete backup of all Vaultwarden data and config on a configurable schedule.
-
Retain backup archives on the local Vaultwarden host for a configurable number of days.
-
Upload encrypted copies of the backup archives to one or more cloud storage services using rclone. The retention policy is configured/managed at the storage service level.
-
Return success when all backup archives are successfully uploaded, or failure if any uploads fail. This allows cron monitoring services like Healthchecks.io, Cronitor, or Dead Man’s Snitch to provide notification of backup failures.
For the most part, I'm not looking for contributions or feature requests, as this repo is only intended to implement my own backup requirements. I may be willing to make some minor generalizations to make it easier for people to use the repo without modification, but aside from that, feel free to fork and modify this setup to fit your own needs.
Note: This single-archive backup scheme isn't space-efficient if your vault includes large file attachments, as they will be re-uploaded with each backup. If this is an issue, you might consider modifying the script to use restic instead.
-
A standard Unix-like (preferably Linux) host running Vaultwarden. I don't know much about Synology or other such environments.
-
A cron daemon. This is used to run backup actions on a scheduled basis.
-
An
sqlite3
binary (https://sqlite.org/cli.html). This is used to back up the SQLite database. This can be installed via thesqlite3
package on Debian/Ubuntu or thesqlite
package on RHEL/CentOS/Fedora. -
An
rclone
binary (https://rclone.org/). This is used to copy the backup archives to cloud storage. This can be installed via therclone
package on Debian/Ubuntu and RHEL/CentOS/Fedora (EPEL required for RHEL/CentOS), but as rclone changes more rapidly, it's probably best to just use the latest binary from https://rclone.org/downloads/. -
An account at one or more cloud storage services supported by rclone. If you don't have one yet, here are a few cloud storage services that offer a free tier:
- Backblaze B2 (10 GB)
- Box (10 GB)
- Cloudflare R2 (10 GB)
- Dropbox (2 GB)
- Google Drive (15 GB)
- IDrive e2 (10 GB) -- must configure rclone remote with
no_check_bucket = true
- Microsoft OneDrive (5 GB)
- Oracle Cloud (10 GB)
- Storj (150 GB)
-
Optionally, a
gpg
(GnuPG 2.x) binary (https://gnupg.org/). This can be installed via thegnupg
package on Debian/Ubuntu or thegnupg2
package on RHEL/CentOS/Fedora. -
Optionally, an
age
binary (https://github.com/FiloSottile/age). This option requires a custom version of the tool that supports reading the passphrase from an environment variable.
-
Start by cloning this repo to the directory containing your Vaultwarden data directory, under the name
backup
. In my setup, it looks like this:$HOME/vaultwarden # Top-level Vaultwarden directory ├── backup # This backup repo └── data # Vaultwarden data directory
-
Copy the
backup.conf.template
file tobackup.conf
.-
If you want encrypted backup archives using
gpg
, set theGPG_PASSPHRASE
variable accordingly. If you want to encrypt usingage
instead, set theAGE_PASSPHRASE
variable. If both variables are set, onlygpg
encryption will be performed. If you don't want encryption at all, comment out both variables or set them to be blank.This passphrase is used to encrypt the backup archives, which may contain somewhat sensitive data in plaintext in
config.json
(the password entries themselves are already encrypted by Bitwarden). It should be something easy enough for you to remember, but complex enough to deter, for example, any unscrupulous cloud storage personnel who might be snooping around. As this passphrase is stored on disk in plaintext, it definitely should not be your Bitwarden master passphrase or anything similar.rclone crypt is another option for encrypted archives. If you prefer to use this method, just set
GPG_PASSPHRASE
to be blank, configure rclone crypt appropriately, and use the crypt remote inRCLONE_DESTS
. -
Change
RCLONE_DESTS
to your list of rclone destinations. You'll have to configure rclone appropriately first. -
Note that
backup.conf
is simply sourced into thebackup.sh
script, so you can add arbitrary environment variables intobackup.conf
as needed. This can be useful for configuring any tools called frombackup.sh
, such asrclone
.
-
-
Modify the
backup/crontab
file as needed. This crontab actually callscron.sh
to run the backup, rather than callingbackup.sh
directly. Currently,cron.sh
captures the output of the current run ofbackup.sh
to abackup.log
file. It also saves a copy of this log file, named according to whether the backup run was a success or failure. You can add other custom logic tocron.sh
if needed, such as signaling failure to a cron monitoring service.-
If
$HOME/vaultwarden
isn't your top-level Vaultwarden directory, adjust the paths in this file accordingly. -
Review the backup schedule. I generate backup archives hourly, but you might prefer to do this less frequently to save space.
-
Review the local backup archive retention policy. I delete archives older than 14 days (
-mtime +14
). Adjust this if needed. -
Review the log file retention policy. I delete log files older than 14 days (
-mtime +14
). Adjust this if needed. -
Review the SQLite VACUUM schedule, or remove the job if you don't want vacuuming. Vacuuming compacts the database file so that operations are faster and backups are smaller.
-
-
Install the crontab under a user (typically your normal login) that can read your Vaultwarden data. In many cases, running
crontab -e
and pasting in the contents of the crontab file should work. Note that if your cron user doesn't have write permissions to the database, then you must ensure it has write permissions to the Vaultwarden data directory, as SQLite may need to create a-wal
file for the database if it doesn't already exist. If it's unable to do this, the backup will fail with anattempt to write a readonly database
error. (For more details, see https://sqlite.org/wal.html#read_only_databases.) -
If you use GnuPG 2.1 or later, see the note about
--pinentry-mode loopback
inbackup.sh
.
If everything is working properly, you should see the following:
- Backup archives generated under
backup/archives
. - Encrypted backup archives uploaded to your configured rclone destination(s).
- A log of the last backup at
backup/backup.log
. - Copies of the backup logs saved to
backup/logs
.
For example:
$HOME/vaultwarden/backup
├── archives
│ ├── vaultwarden-20210101-0000.tar.xz
│ ├── vaultwarden-20210101-0000.tar.xz.gpg
│ ├── vaultwarden-20210101-0100.tar.xz
│ ├── vaultwarden-20210101-0100.tar.xz.gpg
│ └── ...
├── backup.conf
├── backup.conf.template
├── backup.log
├── backup.sh
├── cron.sh
├── crontab
├── logs
│ ├── backup-success-20210101-0000.log
│ ├── backup-success-20210101-0100.log
│ ├── backup-failure-20210101-0200.log
│ └── ...
├── LICENSE
└── README.md