Daily SQLite backup to the NetBackup SMB share plus restore/import/export helpers. SMB credentials moved out of the scripts into ~/.smbcredentials (mode 600) and are passed to smbclient via -A instead of -U "user%pass". This keeps the password out of version control and out of the process list, where -U exposes it to any local user through ps.
Vaultwarden Backup & Restore System
This directory contains scripts for backing up, restoring, and converting Vaultwarden data.
Overview
Primary Backup: SQLite Database (Automated Daily)
The main backup runs daily at 3:00 AM via cron (/home/bdm/scripts/vaultwarden-backup.sh). It:
- Creates a consistent SQLite backup using
sqlite3 .backup - Uploads to SMB share (
//192.168.123.2/NetBackup/Vault/) - Cleans up backups older than 60 days
This is the complete backup for disaster recovery. It contains ALL users, their encrypted vaults, organizations, collections, sends, etc.
Restore Options
Option 1: Full Instance Restore (Recommended for Disaster Recovery)
Use restore-sqlite.sh to restore the entire Vaultwarden instance:
./restore-sqlite.sh vaultwarden-2026-09-19_09-03-45.db
This replaces the database file and restarts Vaultwarden. All users log in with their existing master passwords.
Option 2: Individual User Vault Export/Import (JSON)
Use export-to-json.sh and import-from-json.sh for individual user vaults:
# Export (requires master password)
./export-to-json.sh user@example.com my-vault.json
# Import (requires master password)
./import-from-json.sh user@example.com my-vault.json
Note: JSON export requires the master password because the SQLite database stores all data ENCRYPTED. The master password is needed to decrypt the vault for JSON export.
Scripts
| Script | Purpose | Requires Master Password |
|---|---|---|
vaultwarden-backup.sh |
Daily automated SQLite backup (run by cron) | No |
restore-sqlite.sh |
Restore entire instance from SQLite backup | No |
export-to-json.sh |
Export single user vault to JSON | Yes |
import-from-json.sh |
Import JSON vault to user account | Yes |
mount-smb.sh |
Mount SMB share for cleanup (internal) | No |
umount-smb.sh |
Unmount SMB share (internal) | No |
cleanup-old-backups.sh |
Delete backups older than 60 days (internal) | No |
Backup Location
- SMB Share:
//192.168.123.2/NetBackup/Vault/ - Local Temp:
/tmp/vaultwarden-backup/(cleaned up after upload) - Log File:
/var/log/vaultwarden-backup.log
Cron Schedule
Daily at 3:00 AM (see crontab -l):
0 3 * * * /home/bdm/scripts/vaultwarden-backup.sh >> /var/log/vaultwarden-backup.log 2>&1
Manual Backup
To run a manual backup:
/home/bdm/scripts/vaultwarden-backup.sh
Sudo Configuration
The backup script uses sudo for specific commands. Sudoers rules are in /etc/sudoers.d/vaultwarden-backup:
sqlite3backup commandchownfor temp files- SMB mount/umount/cleanup wrapper scripts
Disaster Recovery Procedure
-
New server setup:
- Install Docker, Docker Compose
- Deploy Vaultwarden container with same volume name (
caddy_vaultwarden_data) - Start container once to create empty database
-
Restore database:
# Download backup from SMB (credentials read from the file below) smbclient //192.168.123.2/NetBackup -A "$HOME/.smbcredentials" -c "cd Vault; get vaultwarden-YYYY-MM-DD_HH-MM-SS.db" # Restore ./restore-sqlite.sh vaultwarden-YYYY-MM-DD_HH-MM-SS.db -
Verify: Users can log in with their existing credentials
JSON Import/Export Notes
- JSON files contain DECRYPTED vault data - store securely!
- Use
BW_MASTER_PASSWORDenv var for automation (less secure) - Interactive prompt is more secure
- JSON format is Bitwarden-compatible (select "Bitwarden (json)" on import)
- Import does not overwrite existing items - it adds/updates
Troubleshooting
Backup fails with "sqlite3 backup failed"
- Check if container is running:
docker ps | grep vaultwarden - Check volume path:
ls -la /var/lib/docker/volumes/caddy_vaultwarden_data/_data/ - Run manually to see errors:
/home/bdm/scripts/vaultwarden-backup.sh
SMB upload fails
- Check network connectivity:
ping 192.168.123.2 - Check the SMB credentials file is present and readable:
ls -l ~/.smbcredentials - Test manually:
smbclient //192.168.123.2/NetBackup -A "$HOME/.smbcredentials" -c "ls"
Cron doesn't run
- Check cron logs:
journalctl -u cron -f - Verify crontab:
crontab -l - Check log file:
cat /var/log/vaultwarden-backup.log
SMB Credentials
The scripts do not contain the SMB password. It lives in an external file so that it stays out of version control and out of the process list:
- Location:
~/.smbcredentials(override with theSMB_CRED_FILEenv var) - Permissions:
600, owned by the user running the backup (bdm)
Create it once, with mode 600:
umask 077
printf 'username = %s\npassword = %s\n' 'bdm' 'YOUR_PASSWORD' > ~/.smbcredentials
The scripts pass it to smbclient with -A (authentication file), which is
preferable to -U "user%pass" because a password passed via -U is visible to
any local user through ps.
Note that /root/.smbcredentials is a separate file used only by the sudo mount -t cifs calls, which run as root. The two are independent.
Security Notes
- SMB credentials are kept in
~/.smbcredentials(mode 600), not in the scripts - JSON exports contain plaintext passwords - encrypt them if storing long-term
- SQLite backups contain encrypted data - safe to store but treat as sensitive
- Master passwords are never stored - only used interactively or via env var