Automating Vaultwarden Backups: A Complete Strategy for SQLite and PostgreSQL
A comprehensive guide for self-hosters on building a resilient, automated backup strategy for Vaultwarden databases and file attachments.
Disclosure: this article contains an affiliate link. DotExe may earn a commission if you purchase through it, at no extra cost to you. Any discount is subject to Hostinger's current offers (20% OFF) and eligibility terms.
Vaultwarden is the industry-standard, lightweight implementation of the Bitwarden API, providing a secure, self-hosted password management solution for individuals and teams. Because it functions as the central repository for your most sensitive digital credentials, a robust backup strategy is not merely an optional maintenance task—it is a critical security requirement. A failure to implement a reliable, automated backup system leaves your entire digital identity vulnerable to hardware failure, accidental deletion, or configuration corruption. In this guide, we will dissect the architecture of a Vaultwarden instance, define the necessary components for a complete recovery, and build an automated, resilient backup pipeline for both SQLite and PostgreSQL deployments.
The Anatomy of a Vaultwarden Instance
To build a successful backup, you must first understand exactly what data defines your Vaultwarden environment. Unlike stateless web applications, Vaultwarden is stateful, meaning its history and configuration are persisted on disk. A complete backup must capture three distinct data areas:
- The Database: This is the heart of the application. If you are using the default configuration, this is a file named
db.sqlite3. If you have scaled your instance to use a database server, this will be an external PostgreSQL instance. - The Attachments: Vaultwarden allows users to upload files to their vault entries. These are stored within the
/data/attachmentsdirectory. If you lose this, you lose every file you have ever attached to your passwords. - The Icon Cache: This is stored in
/data/icon_cache. While not strictly necessary for recovering your passwords, losing this directory forces Vaultwarden to re-download favicons for every site in your vault, which can be bandwidth-intensive and slow down the initial recovery process.
A common mistake is to back up only the database file. If you perform a restore from such a backup, you will find your vault items intact, but all your file attachments will be missing, and your vault will appear broken or incomplete. A professional-grade backup strategy must treat these three components as a single, atomic unit of work.
The SQLite Backup Challenge
By default, Vaultwarden uses SQLite. SQLite is an excellent choice for small-to-medium deployments because it requires no external database server, reducing the complexity of your Docker Compose stack. However, SQLite is a file-based database. If you attempt to copy db.sqlite3 while the Vaultwarden container is actively writing to it, you risk creating a corrupted, partial snapshot.
To perform a safe backup, you must use the internal SQLite backup API. This API creates a consistent snapshot by locking the database for the duration of the copy, ensuring that all pending transactions are finalized before the snapshot is written. You can trigger this through the sqlite3 CLI tool inside your running container.
Performing a Consistent SQLite Snapshot
Instead of a simple cp command, use the following approach to ensure data integrity:
docker exec -t vaultwarden sqlite3 /data/db.sqlite3 ".backup '/data/backups/db-$(date +%Y%m%d).sqlite3'"
This command instructs the SQLite engine to perform an online backup. The -t flag ensures that the command is executed in a terminal-like environment, and the query .backup handles the file locking internally. This creates a consistent file that you can safely move, compress, or copy to off-site storage without fear of corruption.
PostgreSQL Backup Workflows
As your vault grows, you may choose to migrate to PostgreSQL for better concurrency and performance. PostgreSQL separates the data layer from the application layer, which changes how you approach backups. You should never attempt to copy the underlying PostgreSQL data files directly. Instead, you must use pg_dump, which generates a logical SQL script representing the entire state of your database.
Executing a PostgreSQL Logical Backup
To back up your PostgreSQL instance, you need to execute pg_dump within the context of your database container. This produces a portable, version-agnostic file that is highly resilient to future upgrades.
docker exec -t postgres-container pg_dump -U vaultwarden_user vaultwarden_db > /backups/vaultwarden-$(date +%Y%m%d).sql
This method is superior to file-level backups because it allows you to restore the database even if you migrate to a different version of PostgreSQL or move your data to a different architecture. Always ensure your backup user has read-only access to the database to minimize the risk of accidental modification during the backup process.
Designing for Reliability with Automation
Manual backups are prone to human error and inconsistency. To ensure your data is always protected, you must automate the process. A well-designed backup script should be idempotent, meaning it can be run multiple times without causing side effects or failures. For more on this concept, read our guide on idempotent-scheduled-jobs-automation.
The All-In-One Backup Script
Create a shell script on your host machine, for example, vaultwarden-backup.sh. This script will handle the database snapshot, archive the attachments, and perform cleanup of old files to prevent disk space exhaustion.
#!/bin/bash
# Configuration
BACKUP_DIR="/mnt/backups/vaultwarden"
DATE=$(date +%Y%m%d)
# Ensure backup directory exists
mkdir -p "$BACKUP_DIR"
# 1. Backup Database (SQLite example)
docker exec -t vaultwarden sqlite3 /data/db.sqlite3 ".backup '$BACKUP_DIR/db-$DATE.sqlite3'"
# 2. Archive Attachments
tar -czf "$BACKUP_DIR/attachments-$DATE.tar.gz" -C /path/to/vaultwarden/data attachments
# 3. Cleanup: Keep only the last 30 days of backups
find "$BACKUP_DIR" -type f -mtime +30 -delete
echo "Backup completed successfully on $DATE"
Scheduling with Cron
To run this script daily, add it to your system's crontab. Open the editor with crontab -e and add the following line to schedule the job for 2:00 AM:
0 2 * * * /usr/local/bin/vaultwarden-backup.sh
This ensures that your backups occur during off-peak hours, minimizing the impact on server performance. For those interested in tracking the success of these jobs, consider implementing-uptime-kuma-heartbeat-monitors-for-serverless-functions or using push monitors to confirm the script finishes without error.
Verification and Disaster Recovery
A backup is only as good as your ability to restore it. Many administrators fall into the trap of assuming their backups are working simply because the script runs without throwing an error. You must verify your backups regularly.
Testing the Restore Process
Never wait for a disaster to test your recovery process. Create a staging environment—a separate Docker container or a virtual machine—and attempt to restore your backup there.
- Stop the staging container.
- Overwrite the database file with your backup.
- Extract the attachments archive into the data folder.
- Start the container and verify that you can log in and view your vault items and attachments.
If you cannot restore the data, your backup strategy is effectively non-existent. For deeper insights into this practice, refer to our guide on designing-self-hosted-backups-you-can-actually-restore.
Operational Considerations and Trade-offs
When designing your backup system, consider the 3-2-1 rule: keep three copies of your data, on two different media types, with one copy stored off-site. Storing backups on the same server as the Vaultwarden instance provides quick recovery from accidental deletions, but it does not protect you from a total server failure or a ransomware attack that encrypts your entire filesystem.
Off-site Storage
Use tools like rclone or rsync to synchronize your local backup directory to cloud storage (e.g., S3, Backblaze B2, or an encrypted remote server). This adds a layer of resilience against catastrophic hardware failure or physical loss of your primary server.
Security of Backups
Your backups contain your encrypted vault database. While the data is encrypted at rest by Vaultwarden, the backup file itself should be treated with the same level of security as the primary database. Ensure that your backup directory has restricted permissions (chmod 700) so that only the user running the backup script can access the files. If you are uploading backups to the cloud, ensure you use client-side encryption before the files leave your server.
Troubleshooting Common Failures
Even with a robust script, things can go wrong. Here are the most common failure modes and how to diagnose them:
- Zero-byte Backups: This usually happens if the
docker execcommand fails silently or if the destination path is not writable. Always check the exit status of your commands in your script usingif [ $? -ne 0 ]; then ... filogic. - Permission Denied Errors: Ensure the user running the cron job has sufficient permissions to execute Docker commands and write to the backup directory. Adding the user to the
dockergroup is common, but ensure this does not violate your security policy. - Disk Space Exhaustion: If your backup script does not include a cleanup routine, your server will eventually run out of space. Always use
findor a similar tool to purge old backups. - Database Locking: If you see "database is locked" errors, it usually means the SQLite file is being accessed by multiple processes. The
.backupcommand is designed to handle this, but ensure you are not running other maintenance tasks simultaneously.
By following these steps, you create a resilient, automated, and verifiable backup system that protects your Vaultwarden instance against data loss. Remember that the goal of a backup strategy is not just to save data, but to ensure business continuity and peace of mind.
Affiliate resource and disclosure
Review Hostinger Web Hosting and check whether it fits your requirements, pricing, and terms.
Disclosure: this article contains an affiliate link. DotExe may earn a commission if you purchase through it, at no extra cost to you. Any discount is subject to Hostinger's current offers (20% OFF) and eligibility terms.
Frequently Asked Questions
Can I just copy the Vaultwarden data folder to back it up?
Copying the data folder while the container is running is dangerous because the database may be in an inconsistent state, leading to potential corruption. You must use specific tools like sqlite3 .backup or pg_dump to ensure you capture a consistent, valid snapshot of the database while the application is active.
Do I need to back up the attachments folder separately?
Yes, the database only stores metadata and references to your files, not the actual file content. You must include the attachments and icon_cache directories in your daily backup routine to ensure you can fully recover your vault's state, including all uploaded documents and images.
How often should I run my Vaultwarden backups?
Most users find that a daily backup is sufficient for personal use, but you should adjust this frequency based on how often you add or update sensitive information. Ensure your automation includes a cleanup step so that you do not run out of disk space over time by keeping infinite historical copies.
Is it safe to store backups on the same server as Vaultwarden?
Storing backups on the same server is sufficient for quick recovery from accidental deletions, but it does not protect you against hardware failure or server-wide issues. You should always sync your backups to an external location or cloud storage to meet the requirements of a robust disaster recovery plan.