Configure once, forget forever. Automated Bitwarden vault backups with multi-remote cloud storage support. Set up once and enjoy hands-free daily backups to multiple cloud services simultaneously (S3, Google Drive, Dropbox, OneDrive, Cloudflare R2, and 40+ others). Supports both official Bitwarden and self-hosted servers.
# If you have this repo cloned:
./generate-rclone-base64.sh
# Interactive mode (create new config):
./generate-rclone-base64.sh --interactive
# Test config and save to file:
./generate-rclone-base64.sh --test --output my-config.txt
# Or manually create base64 from existing rclone config:
base64 -w 0 < ~/.config/rclone/rclone.conf
Create a .env
file with these 5 required variables:
cat > .env << EOF
BW_CLIENTID=your_bitwarden_client_id
BW_CLIENTSECRET=your_bitwarden_client_secret
BW_PASSWORD=your_bitwarden_master_password
ENCRYPTION_PASSWORD=your_strong_encryption_password
RCLONE_CONFIG_BASE64=your_base64_encoded_rclone_config
EOF
To also backup organization vaults, add these optional variables:
# Enable organization exports
EXPORT_ORGANIZATIONS=true
# List organization IDs to export (comma-separated, no spaces)
# Get org IDs with: bw list organizations --session $BW_SESSION
BW_ORGANIZATION_IDS=12345678-1234-1234-1234-123456789012,87654321-4321-4321-4321-210987654321
π Backup Format Compatibility:
β‘ Fastest (No cloning required):
docker run --rm --env-file .env --pull always \
-e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata \
nikhilbadyal/bitwarden-backup:latest
Or with Docker Compose:
git clone https://github.com/nikhilbadyal/bitwarden-backup.git
cd bitwarden-backup
# Copy your .env file here
docker-compose up --build --no-cache
# Added --no-cache to ensure latest image is always pulled.
Or with scripts:
./setup-rclone.sh && ./scripts/backup.sh
Thatβs it! Your vault will be backed up to all configured remotes with encryption and compression.
π₯οΈ Want a Web UI? See the Management Interface section below for the complete web dashboard setup!
This project includes both a modern web UI and REST API for managing your Bitwarden backups through an intuitive interface or programmatic access.
π₯οΈ Web UI + API (Recommended):
# Start everything (UI + API + Redis + Nginx)
docker-compose -f docker-compose.full.yml up -d --build --no-cache
# Added --build --no-cache to ensure latest image is always pulled and rebuilt.
# Access the complete application
# - Web UI: http://localhost:80
# - API Docs: http://localhost:80/api/v1/docs
π API Only:
# Run the API with Docker
./run-api.sh
# Access the API
# - API Root: http://localhost:5050/
# - Documentation: http://localhost:5050/api/v1/docs
For detailed API setup instructions, Docker configuration, and usage examples, see:
π API.md - Complete API Setup Guide
The API provides endpoints for:
This project includes a modern React-based web interface for managing your Bitwarden backups through an intuitive dashboard.
Option 1: Full Stack (Recommended)
# Start everything (API + UI + Redis + Nginx)
docker-compose -f docker-compose.full.yml up -d
# Access the complete application
# - Web UI: http://localhost:80
# - API: http://localhost:80/api (proxied through Nginx)
Option 2: Manual Development Setup
# 1. Start the API backend
cls && uvicorn api.main:app --reload --host 0.0.0.0 --port 5050
# 2. In another terminal, start the UI
cd ui
npm install
npm start
# Access:
# - UI: http://localhost:3000
# - API: http://localhost:5050
Option 3: Docker Compose (Separate Services)
# Start API only
docker-compose -f docker-compose.api.yml up -d --build --no-cache
# Added --build --no-cache to ensure latest image is always pulled and rebuilt.
# Start UI only (in another terminal)
docker-compose -f docker-compose.ui.yml up -d --build --no-cache
# Added --build --no-cache to ensure latest image is always pulled and rebuilt.
# Access:
# - UI: http://localhost:3000
# - API: http://localhost:5050
The UI requires these environment variables for proper API connectivity:
Variable | Description | Default | Docker Example |
---|---|---|---|
VITE_API_BASE_URL |
API backend URL | http://localhost:5050 |
/api (with Nginx proxy) |
For development:
# In ui/.env file
VITE_API_BASE_URL=http://localhost:5050
For Docker with Nginx (recommended): The full Docker Compose setup automatically configures Nginx to:
/api/*
requests to the backendThe web interface is built with modern technologies:
Development Commands:
cd ui
# Install dependencies
npm install
# Start development server (with hot reload)
npm start # or npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Lint and format code
npm run lint
npm run format
The UI uses token-based authentication:
API_TOKEN
from your .env
fileSystem Health Dashboard:
Remote Storage Management:
Backup Browser:
Rclone Configuration:
Full Disclosure: The web interface was βvibe codedβ due to limited frontend expertise - itβs fully functional but could use some design polish! π
Contributing: If youβre a frontend developer and want to contribute design improvements, weβd be incredibly grateful! The codebase is contribution-friendly and uses modern React patterns.
Known Limitations:
This repository provides a βconfigure once, forget foreverβ solution for Bitwarden vault backups:
setup-rclone.sh
: Configures rclone from a base64-encoded configuration to support ANY rclone-compatible storage servicebackup.sh
: Performs automated backup, validates, compresses, encrypts, and uploads to ALL configured remotes simultaneouslygenerate-rclone-base64.sh
: Helper script to generate base64-encoded rclone configurationsrestore-backup.sh
: Decrypt and restore backup files back to plain JSON formatbw
, jq
, gzip
, openssl
, rclone
CLI tools installedπ§ Full Setup (Clone Repository):
git clone https://github.com/nikhilbadyal/bitwarden-backup.git
cd bitwarden-backup
# Generate rclone config
./generate-rclone-base64.sh
# Create .env file (copy from env.example)
cp env.example .env
# Edit .env with your values
# Run backup
./setup-rclone.sh && ./scripts/backup.sh
Variable | Description | Example |
---|---|---|
BW_CLIENTID |
Your Bitwarden API Client ID | user.1234567890abcdef |
BW_CLIENTSECRET |
Your Bitwarden API Client Secret | abcdef1234567890 |
BW_PASSWORD |
Your Bitwarden Master Password | MySecretPassword123! |
ENCRYPTION_PASSWORD |
Strong password for backup encryption | BackupEncryption456! |
RCLONE_CONFIG_BASE64 |
Base64-encoded rclone configuration | W215LXMzXQp0eXBlID0gczMK... |
Variable | Description | Example |
---|---|---|
API_TOKEN |
Authentication token for API access | your_secure_api_token |
REDIS_URL |
Redis connection URL for caching | redis://localhost:6379/0 |
BACKUP_PATH |
Remote path/bucket for storing backups | bitwarden-backup |
This backup tool fully supports self-hosted Bitwarden servers! Configure your custom server using these optional environment variables:
Variable | Description | Example |
---|---|---|
BW_SERVER |
Primary server URL (recommended approach) | https://bitwarden.example.com |
BW_WEB_VAULT |
Custom web vault URL (advanced) | https://vault.example.com |
BW_API |
Custom API URL (advanced) | https://api.example.com |
BW_IDENTITY |
Custom identity URL (advanced) | https://id.example.com |
BW_ICONS |
Custom icons service URL (advanced) | https://icons.example.com |
BW_NOTIFICATIONS |
Custom notifications URL (advanced) | https://notify.example.com |
BW_EVENTS |
Custom events URL (advanced) | https://events.example.com |
BW_KEY_CONNECTOR |
Key Connector URL (for organizations) | https://keycon.example.com |
Quick Examples:
# For most self-hosted installations, just set BW_SERVER:
BW_SERVER="https://vault.mycompany.com"
# For Bitwarden EU cloud:
BW_SERVER="https://vault.bitwarden.eu"
# For complex custom setups (rarely needed):
BW_WEB_VAULT="https://vault.example.com"
BW_API="https://api.example.com"
BW_IDENTITY="https://identity.example.com"
Important Notes:
BW_SERVER
is the recommended approach for most self-hosted installationsBW_API
, BW_IDENTITY
, etc.) override BW_SERVER
if both are setVariable | Description | Default | Example |
---|---|---|---|
EXPORT_PERSONAL |
Export personal vault | true |
true or false |
EXPORT_ORGANIZATIONS |
Export organization vaults | false |
true or false |
BW_ORGANIZATION_IDS |
Organization IDs to export (comma-separated) | None | 12345678-...,87654321-... |
Format Details:
EXPORT_ORGANIZATIONS=false
(default): Uses standard Bitwarden export formatEXPORT_ORGANIZATIONS=true
: Uses consolidated format with personal
and organizations
sectionsBackup Features:
Restore Features:
This backup solution supports ALL rclone-compatible storage services, including:
Object Storage:
Consumer Cloud Storage:
Enterprise Storage:
And many more! See the rclone documentation for the complete list.
Your rclone configuration can include multiple remotes:
[aws-s3]
type = s3
provider = AWS
access_key_id = AKIAIOSFODNN7EXAMPLE
secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region = us-east-1
[google-drive]
type = drive
client_id = 123456789.apps.googleusercontent.com
client_secret = abcdefghijklmnopqrstuvwx
token = {"access_token":"ya29.a0AfH6SMC..."}
[cloudflare-r2]
type = s3
provider = Cloudflare
access_key_id = your_r2_access_key
secret_access_key = your_r2_secret_key
endpoint = https://abc123.r2.cloudflarestorage.com
[dropbox-backup]
type = dropbox
token = {"access_token":"sl.B0abcdefghijklmnop..."}
The backup script will automatically:
The restore-backup.sh
script allows you to decrypt and restore your encrypted backups back to plain JSON format.
# Decrypt a local backup file
./restore-backup.sh bw_backup_20241218123456.json.gz.enc
# Download and decrypt latest backup from S3 remote
./restore-backup.sh -r s3-remote
# List all available backups from all configured remotes
./restore-backup.sh -l
# Decrypt with custom output filename
./restore-backup.sh -f backup.enc -o my_vault.json
Option | Description | Example |
---|---|---|
-f, --file |
Decrypt local backup file | --file backup.enc |
-r, --remote |
Download & decrypt from remote | --remote s3-backup |
-o, --output |
Custom output filename | --output vault.json |
-l, --list |
List backups from all remotes | --list |
--list-remote |
List backups from specific remote | --list-remote gdrive |
--download-only |
Download without decrypting | --download-only |
ENCRYPTION_PASSWORD
from backups is requiredCode | Meaning |
---|---|
0 |
Success |
1 |
Missing required environment variable |
2 |
Missing required dependency |
3 |
Backup directory issue |
4 |
Bitwarden login failed |
5 |
Bitwarden vault unlock failed |
6 |
Bitwarden data export failed |
7 |
Invalid backup file |
8 |
Compression or encryption failed |
99 |
Unexpected error during upload |
Configure Apprise for notifications:
# Multiple notification services
APPRISE_URLS="mailto://[email protected] tgram://bot_token/chat_id discord://webhook_id/webhook_token"
Enhanced Notification Details:
The final notification now includes detailed per-remote status:
Success Notification Example:
Bitwarden backup script completed successfully. New backup uploaded: bw_backup_20241218123456.json.gz.enc.
π Remote Status:
β
aws-s3: Success
β
google-drive: Up to date
β dropbox-backup: Failed
β
cloudflare-r2: Success
π Summary: π€ 2 uploaded, β
1 up-to-date, β 1 failed
No Changes Notification Example:
Bitwarden backup script completed successfully. No changes detected, no new backup uploaded.
π Remote Status:
β
aws-s3: Up to date
β
google-drive: Up to date
β
cloudflare-r2: Up to date
Failure Notification Example:
Bitwarden backup script failed with exit code 8.
Reason: Compression or encryption failed. Check ENCRYPTION_PASSWORD.
β οΈ Remote Status at time of failure:
β
aws-s3: Success
β google-drive: Failed
βΈοΈ dropbox-backup: Not processed
.env
File: Contains sensitive credentials. Set permissions to chmod 600 .env
.chmod 700
on backup directory.If youβre upgrading from the R2-only version:
.env
- the new version is backward compatible./generate-rclone-base64.sh
to create RCLONE_CONFIG_BASE64
.env
fileβRCLONE_CONFIG_BASE64 contains invalid base64 dataβ (Docker Hub image only):
Thereβs a known issue with the Docker Hub image having stricter base64 validation than local builds. If your base64 works with local Docker Compose but fails with the Docker Hub image:
Workaround 1: Use local build instead
git clone https://github.com/nikhilbadyal/bitwarden-backup.git
cd bitwarden-backup
# Copy your .env file here
docker-compose up --build
Workaround 2: Regenerate base64 (may help)
base64 -w 0 < ~/.config/rclone/rclone.conf | tr -d '\n'
This issue is being investigated - the local build is currently more reliable.
No remotes found:
RCLONE_CONFIG_BASE64
is properly set./generate-rclone-base64.sh --test
Upload failures:
Permission errors:
chmod +x *.sh scripts/*.sh
Bitwarden unlock failures:
The script includes automatic retry logic for vault unlock failures. If youβre experiencing frequent unlock issues:
BW_UNLOCK_RETRIES=5
(default: 3)BW_UNLOCK_RETRY_DELAY=10
(default: 5 seconds)BW_PASSWORD
variableπ Universal Architecture Support:
The Docker image is built for 2 main architectures and works universally:
Manual Installation (without Docker):
If running scripts directly on any system, install Bitwarden CLI via npm:
# Install Node.js and npm
sudo apt update && sudo apt install -y nodejs npm
# Install Bitwarden CLI globally
sudo npm install -g @bitwarden/cli
# Verify installation
bw --version
Read-only filesystem errors with Bitwarden CLI:
If you see errors like EROFS: read-only file system, open '/home/backupuser/.config/Bitwarden CLI/data.json'
:
This happens when the Docker container runs with a read-only filesystem but Bitwarden CLI needs to write configuration files. The Docker Compose file already handles this, but for manual Docker runs, add:
docker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata nikhilbadyal/bitwarden-backup:latest
Using outdated Docker images:
Docker may use cached local images instead of pulling the latest from Docker Hub. To ensure youβre running the most recent version:
# Option 1: Use --pull always flag (recommended)
docker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata --pull always nikhilbadyal/bitwarden-backup:latest
# Option 2: Manually pull first, then run
docker pull nikhilbadyal/bitwarden-backup:latest
docker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata nikhilbadyal/bitwarden-backup:latest
Note: docker-compose
automatically handles this with pull_policy: always
in the compose file.
rclone ls remote:
to test connectivity--test
flag with the helper scriptContributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
This project is open source. Please check the license file for details.