10 KiB
Vaultwarden Backup & Restore Guide
Note
The official backup and restore documentation for Vaultwarden is located on the Vaultwarden GitHub Wiki. The steps below are tailored specifically to our local Docker container setup and automated backup script.
Script Architecture & Workflow
The custom backup script (vaultwarden_backup.sh) automates point-in-time snapshots of Vaultwarden while maintaining database integrity, supporting non-POSIX external backup drives (exFAT/NTFS), and providing real-time notification alerts.
+-------------------------------------------------------+
| Pre-flight Checks |
| (Mount point verify -> Data Dir check -> Docker running)
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| Step 1: Container DB Snapshot |
| `docker exec vaultwarden /vaultwarden backup` |
| (Generates db_YYYYMMDD_HHMMSS.sqlite3 safely in WAL) |
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| Step 2: Sync Snapshot DB |
| `rsync` snapshot -> `CURRENT_BACKUP_DIR/db.sqlite3` |
| (Deletes local temp snapshot file) |
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| Step 3: Sync Attachments & Data |
| `rsync` attachments, sends, RSA keys, config |
| (Excludes active live `db.sqlite3*`) |
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| Step 4: Update Path Pointer |
| Write `CURRENT_BACKUP_DIR` path -> `latest.txt` |
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| Step 5: Retention Cleanup |
| `find` & delete `backup_*` folders > 30 days |
+---------------------------+---------------------------+
|
v
+-------------------------------------------------------+
| ntfy Status Alert Sent |
+-------------------------------------------------------+
Detailed Breakdown of Script Operations
1. Pre-flight Infrastructure Checks
Before modifying any data or making temporary local files, the script verifies three critical dependencies:
- Mount Verification (
mountpoint -q): Ensures/mnt/5TB-Disk1is an actively mounted filesystem. This prevents writing gigabytes of backup data to the local host root disk if the external drive gets disconnected. - Source Path Verification: Confirms
/srv/docker/vaultwarden/dataexists. - Container State Check: Verifies that the Vaultwarden Docker container is actively running using
docker ps.
If any pre-flight test fails, the script sends an error payload to ntfy and exits immediately with status code 1.
2. Database Snapshot Generation (Hot Backup)
Vaultwarden uses SQLite with Write-Ahead Logging (WAL). Directly copying db.sqlite3 with standard filesystem tools (cp, rsync) while Vaultwarden is writing will produce a corrupted database backup.
To prevent corruption, the script invokes Vaultwarden's native backup CLI command inside the container:
docker exec vaultwarden /vaultwarden backup
- How it works: Vaultwarden issues an online SQLite backup API call that safely locks transactions briefly, creates a complete, uncorrupted database copy named
db_YYYYMMDD_HHMMSS.sqlite3inside the host volume directory (/srv/docker/vaultwarden/data), and immediately releases the lock.
3. Isolated Target Snapshot & Normalization
Once generated, the script locates the newest db_*.sqlite3 snapshot and copies it to the target backup folder as db.sqlite3:
- Naming Standardization: Renaming
db_YYYYMMDD_HHMMSS.sqlite3todb.sqlite3at the destination creates a turnkey restoration layout matching Vaultwarden's default expectation. - Local Cleanup: Immediately after copying,
rm -f "$LATEST_DB_BACKUP"removes the temporary snapshot from host storage (/srv/docker/vaultwarden/data/) to prevent local disk exhaustion.
4. Asset Synchronization (rsync)
Attachments, user sends, encryption keys (rsa_key*), and server configurations (config.json) are synced using rsync:
rsync -av --no-owner --no-group --exclude='db.sqlite3*' /srv/docker/vaultwarden/data/ "$CURRENT_BACKUP_DIR/"
- Flag Explanation:
-a(Archive mode): Preserves modification times, recursive directory structure, and file permissions.--no-owner --no-group: Preventsrsyncfrom throwing permission warnings when backing up to filesystems (like exFAT or NTFS) that do not support POSIX user/group ownership mapping.--exclude='db.sqlite3*': Prevents active WAL journal files (db.sqlite3-wal,db.sqlite3-shm) from being copied alongside the staticdb.sqlite3snapshot.
5. Filesystem-Agnostic "Latest" Pointer
On standard Linux filesystems (ext4/btrfs), scripts usually create a symbolic link (ln -s) to mark the latest backup folder. However, drives formatted as exFAT, FAT32, or NTFS reject symlinks with Operation not permitted.
To keep the script 100% compatible with any storage medium:
- The script writes the absolute path of the newest backup folder into a plain text file:
/mnt/5TB-Disk1/backup/services/vaultwarden/latest.txt. - Restores or external monitoring scripts can simply read
cat latest.txtto discover the active backup location.
6. Retention Engine
Automatic backup rotation is performed using find:
find "$VAULTWARDEN_DESTINATION" -maxdepth 1 -type d -name "backup_*" -mtime +30 -exec rm -rf {} +
-maxdepth 1: Restricts search depth to the top-level Vaultwarden backup directory to avoid recursing into subdirectories.-name "backup_*": Filters strictly for directories generated by this script.-mtime +30: Identifies folders whose file modification time is strictly older than 30 days (720 hours).-exec rm -rf {} +: Deletes matching historical backup directories in a single batch operation.
7. Event Notifications via ntfy
All execution pathways (successes, container missing, unmounted drives, rsync failures) trigger an HTTP POST request to the defined ntfy server via curl, delivering real-time status updates directly to connected clients.
Automated Backup Execution
Cron Configuration
The backup script is executed automatically via root's crontab.
To view or edit the automated schedule:
sudo crontab -e
Recommended Schedule (Every night at 2:30 AM):
30 2 * * * /bin/bash /srv/docker/vaultwarden/vaultwarden_backup.sh >/dev/null 2>&1
Manual Script Execution
To manually trigger a complete backup at any time:
sudo /srv/docker/vaultwarden/vaultwarden_backup.sh
Manual Backup Procedure
If you need to perform a backup manually without using the script:
1. Generate Container Database Snapshot
sudo docker exec vaultwarden /vaultwarden backup
2. Copy Snapshot and Assets
# Define target directory
TARGET_DIR="/mnt/5TB-Disk1/backup/services/vaultwarden/manual_$(date +%Y-%m-%d_%H%M%S)"
mkdir -p "$TARGET_DIR"
# Locate and copy the generated DB snapshot
LATEST_DB=$(ls -t /srv/docker/vaultwarden/data/db_*.sqlite3 | head -n 1)
sudo rsync -av --no-owner --no-group "$LATEST_DB" "$TARGET_DIR/db.sqlite3"
# Remove the temporary snapshot from source
sudo rm -f "$LATEST_DB"
# Copy remaining assets (RSA keys, attachments, sends, config)
sudo rsync -av --no-owner --no-group --exclude='db.sqlite3*' /srv/docker/vaultwarden/data/ "$TARGET_DIR/"
Restore Vaultwarden Procedure
Caution
Always stop the Vaultwarden container before restoring files. Overwriting files on an active container can cause database locks or file corruption.
Step 1: Identify Backup to Restore
Identify the backup directory path from latest.txt or list all available timestamped backups:
# View path to the most recent successful backup
cat /mnt/5TB-Disk1/backup/services/vaultwarden/latest.txt
# Or list all historical backup directories
ls -l /mnt/5TB-Disk1/backup/services/vaultwarden/
Step 2: Stop Vaultwarden Container
sudo docker stop vaultwarden
# OR if using Docker Compose:
# cd /srv/docker/vaultwarden && sudo docker compose down
Step 3: Restore Data Files
Rsync the database snapshot, attachments, sends, and RSA keys back to the host data directory.
Note
Replace
/mnt/5TB-Disk1/backup/services/vaultwarden/backup_YYYY-MM-DD_HHMMSSbelow with the target backup directory you wish to restore.
sudo rsync -av --delete /mnt/5TB-Disk1/backup/services/vaultwarden/backup_2026-10-03_101124/ /srv/docker/vaultwarden/data/
Step 4: Verify Host File Permissions
Ensure the restored files match the container user's expected ownership (UID/GID 1000:1000 default):
sudo chown -R 1000:1000 /srv/docker/vaultwarden/data
Step 5: Start Vaultwarden Container & Verify Logs
sudo docker start vaultwarden
# OR if using Docker Compose:
# cd /srv/docker/vaultwarden && sudo docker compose up -d
# Verify startup logs
sudo docker logs -f vaultwarden
Authors and Acknowledgment
- Vaultwarden Wiki: https://github.com/dani-garcia/vaultwarden/wiki
- Vaultwarden Repository: https://github.com/dani-garcia/vaultwarden