Automated encrypted exports for Vaultwarden using the official Bitwarden CLI.
Most Vaultwarden backup solutions copy the SQLite database directly. This has drawbacks:
- Must handle WAL files and database locks correctly
- Tied to Vaultwarden's internal schema (version-dependent)
- Cannot easily restore to a different Bitwarden-compatible server
This tool uses the Bitwarden CLI to create a proper encrypted export:
- Portable, password-protected JSON export
- Can restore to Vaultwarden, official Bitwarden, or any compatible server
- Decoupled from internal database format
- Uses rclone for 40+ storage backends
# docker-compose.yml
services:
vaultwarden-export:
image: ghcr.io/ncherro/vaultwarden-export:latest
restart: unless-stopped
environment:
- BW_URL=https://vault.example.com
- RCLONE_DEST=s3:my-bucket/backups
- RCLONE_CONFIG_S3_TYPE=s3
- RCLONE_CONFIG_S3_PROVIDER=AWS
- RCLONE_CONFIG_S3_ACCESS_KEY_ID=xxx
- RCLONE_CONFIG_S3_SECRET_ACCESS_KEY=xxx
- RCLONE_CONFIG_S3_REGION=us-east-1
- BW_CLIENTID=user.xxx
- BW_CLIENTSECRET=xxx
- BW_MASTER_PASSWORD=xxx
- BACKUP_PASSWORD=xxxdocker-compose up -d| Variable | Description |
|---|---|
BW_URL |
Your Vaultwarden server URL |
BW_CLIENTID |
Bitwarden API client ID |
BW_CLIENTSECRET |
Bitwarden API client secret |
BW_MASTER_PASSWORD |
Master password to unlock the vault |
BACKUP_PASSWORD |
Password to encrypt the backup file |
RCLONE_DEST |
Rclone destination (e.g., s3:bucket/path) |
RCLONE_CONFIG_* |
Rclone backend config (see Storage Backends) |
| Variable | Default | Description |
|---|---|---|
BACKUP_CRON |
0 4 * * * |
Cron schedule (daily at 4am) |
RUN_ONCE |
false |
Run once and exit (for K8s jobs) |
BACKUP_ON_START |
false |
Run backup on container start |
RETENTION_COUNT |
7 |
Backups to keep (0 = unlimited) |
BACKUP_FILENAME |
vaultwarden-%Y-%m-%d.json |
Filename pattern |
TZ |
UTC |
Timezone for cron |
Get notified on backup success or failure via webhooks. Works with Home Assistant, Discord, Slack, ntfy, or any HTTP endpoint.
| Variable | Description |
|---|---|
WEBHOOK_ERROR_URL |
URL to POST on failure |
WEBHOOK_ERROR_MESSAGE |
Custom error payload (optional) |
WEBHOOK_SUCCESS_URL |
URL to POST on success |
WEBHOOK_SUCCESS_MESSAGE |
Custom success payload (optional) |
Default payload:
{"service": "vaultwarden-export", "message": "Backup completed successfully", "timestamp": "2024-01-15T04:00:00+00:00"}Placeholders for custom messages: {message}, {service}, {timestamp}
Examples:
Home Assistant (requires webhook automation):
- WEBHOOK_ERROR_URL=http://192.168.1.100:8123/api/webhook/backup-failedDiscord:
- WEBHOOK_ERROR_URL=https://discord.com/api/webhooks/xxx/yyy
- WEBHOOK_ERROR_MESSAGE={"content": "π¨ {service}: {message}"}Slack:
- WEBHOOK_ERROR_URL=https://hooks.slack.com/services/xxx
- WEBHOOK_ERROR_MESSAGE={"text": "{service}: {message}"}ntfy:
- WEBHOOK_ERROR_URL=https://ntfy.sh/your-topic
- WEBHOOK_ERROR_MESSAGE={message}For better security, use file-based secrets instead of environment variables. Environment variables can leak through process listings, debug logs, and container inspection. File-based secrets avoid this by reading values from files at runtime.
Append _FILE to any secret variable:
environment:
# Bitwarden secrets
- BW_CLIENTID_FILE=/secrets/client_id
- BW_CLIENTSECRET_FILE=/secrets/client_secret
- BW_MASTER_PASSWORD_FILE=/secrets/master_password
- BACKUP_PASSWORD_FILE=/secrets/backup_password
# Rclone secrets (any RCLONE_CONFIG_* var supports _FILE)
- RCLONE_CONFIG_S3_ACCESS_KEY_ID_FILE=/secrets/aws_access_key_id
- RCLONE_CONFIG_S3_SECRET_ACCESS_KEY_FILE=/secrets/aws_secret_access_key
volumes:
- ./secrets:/secrets:roRestrict file permissions so only the owner can read them:
chmod 600 secrets/*The _FILE suffix works with all secret variables (BW_CLIENTID, BW_CLIENTSECRET, BW_MASTER_PASSWORD, BACKUP_PASSWORD) and any RCLONE_CONFIG_* variable.
- Log into your Vaultwarden web UI
- Go to Settings β Security β Keys
- Click View API Key
- Copy the
client_idandclient_secret
Uses rclone for uploads, supporting 40+ providers.
environment:
- RCLONE_DEST=s3:my-bucket/vaultwarden
- RCLONE_CONFIG_S3_TYPE=s3
- RCLONE_CONFIG_S3_PROVIDER=AWS
- RCLONE_CONFIG_S3_ACCESS_KEY_ID=xxx
- RCLONE_CONFIG_S3_SECRET_ACCESS_KEY=xxx
- RCLONE_CONFIG_S3_REGION=us-east-1environment:
- RCLONE_DEST=b2:my-bucket/vaultwarden
- RCLONE_CONFIG_B2_TYPE=b2
- RCLONE_CONFIG_B2_ACCOUNT=xxx
- RCLONE_CONFIG_B2_KEY=xxxenvironment:
- RCLONE_DEST=/backups
volumes:
- /path/on/host:/backupsenvironment:
- RCLONE_CONFIG=/config/rclone.conf
- RCLONE_DEST=myremote:bucket/path
volumes:
- ./rclone.conf:/config/rclone.conf:ro- Log into your Vaultwarden web UI
- Go to Tools β Import Data
- Select format: Bitwarden (json)
- Upload your backup file
- Enter the backup password when prompted
docker run --rm \
-e BW_URL=https://vault.example.com \
-e RCLONE_DEST=/backups \
-e BW_CLIENTID=xxx \
-e BW_CLIENTSECRET=xxx \
-e BW_MASTER_PASSWORD=xxx \
-e BACKUP_PASSWORD=xxx \
-e RUN_ONCE=true \
-v /path/to/backups:/backups \
ghcr.io/ncherro/vaultwarden-export:latestdocker build -t vaultwarden-export .- Backup password: Use a strong, unique password stored separately from your master password
- File-based secrets: Preferred over environment variables for production
- Master password exposure: This tool requires your master password - consider the implications for your threat model
Found a bug or have a feature request? Open an issue on GitHub.
This tool requires access to your Vaultwarden master password. Use at your own risk. The authors are not responsible for data loss or security incidents.
MIT