# Vaultwarden Backup & Restore Guide > [!Note] > The official backup and restore documentation for Vaultwarden is located on the [Vaultwarden GitHub Wiki](https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault). 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-Disk1` is 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/data` exists. * **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: ```bash 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.sqlite3` inside 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.sqlite3` to `db.sqlite3` at 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`: ```bash 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`: Prevents `rsync` from 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 static `db.sqlite3` snapshot. ### 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.txt` to discover the active backup location. ### 6. Retention Engine Automatic backup rotation is performed using `find`: ```bash 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: ```bash sudo crontab -e ``` **Recommended Schedule (Every night at 2:30 AM):** ```cron 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: ```bash 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 ```bash sudo docker exec vaultwarden /vaultwarden backup ``` ### 2. Copy Snapshot and Assets ```bash # 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: ```bash # 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 ```bash 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_HHMMSS` below with the target backup directory you wish to restore. ```bash 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): ```bash sudo chown -R 1000:1000 /srv/docker/vaultwarden/data ``` ### Step 5: Start Vaultwarden Container & Verify Logs ```bash 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