{"id":27781244,"url":"https://github.com/nikhilbadyal/bitwarden-backup","last_synced_at":"2026-05-05T20:41:23.663Z","repository":{"id":290055182,"uuid":"973050311","full_name":"nikhilbadyal/bitwarden-backup","owner":"nikhilbadyal","description":"Bitwarden Vault Backup Script","archived":false,"fork":false,"pushed_at":"2025-04-26T15:20:39.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-26T16:19:17.594Z","etag":null,"topics":["backup","backup-script","bash","bitwarden","cloudflare","rclone"],"latest_commit_sha":null,"homepage":"http://www.nikhilbadyal.com/bitwarden-backup/","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikhilbadyal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-26T06:33:11.000Z","updated_at":"2025-04-26T15:20:42.000Z","dependencies_parsed_at":"2025-04-26T16:29:23.660Z","dependency_job_id":null,"html_url":"https://github.com/nikhilbadyal/bitwarden-backup","commit_stats":null,"previous_names":["nikhilbadyal/bitwarden-backup"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikhilbadyal%2Fbitwarden-backup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikhilbadyal%2Fbitwarden-backup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikhilbadyal%2Fbitwarden-backup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikhilbadyal%2Fbitwarden-backup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikhilbadyal","download_url":"https://codeload.github.com/nikhilbadyal/bitwarden-backup/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251702776,"owners_count":21630088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","backup-script","bash","bitwarden","cloudflare","rclone"],"created_at":"2025-04-30T12:43:34.648Z","updated_at":"2026-05-05T20:41:23.654Z","avatar_url":"https://github.com/nikhilbadyal.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VaultSync\n\n![VaultSync Logo](./ui/src/full-logo.svg)\n\n**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.**\n\n## 🚀 Quick Start (TL;DR)\n\n### 1. Generate Rclone Config\n\n```bash\n# If you have this repo cloned:\n./generate-rclone-base64.sh\n\n# Interactive mode (create new config):\n./generate-rclone-base64.sh --interactive\n\n# Test config and save to file:\n./generate-rclone-base64.sh --test --output my-config.txt\n\n# Or manually create base64 from existing rclone config:\nbase64 -w 0 \u003c ~/.config/rclone/rclone.conf\n```\n\n### 2. Minimal Configuration\n\nCreate a `.env` file with these **5 required variables**:\n\n```bash\ncat \u003e .env \u003c\u003c EOF\nBW_CLIENTID=your_bitwarden_client_id\nBW_CLIENTSECRET=your_bitwarden_client_secret\nBW_PASSWORD=your_bitwarden_master_password\nENCRYPTION_PASSWORD=your_strong_encryption_password\nRCLONE_CONFIG_BASE64=your_base64_encoded_rclone_config\nEOF\n```\n\n### Optional: Organization Export Support\n\nTo also backup organization vaults, add these optional variables:\n\n```bash\n# Enable organization exports\nEXPORT_ORGANIZATIONS=true\n\n# Optional: list organization IDs to export (comma-separated, no spaces)\n# If omitted, all accessible organizations are auto-discovered and exported\n# Get org IDs manually with: bw list organizations --session $BW_SESSION\nBW_ORGANIZATION_IDS=12345678-1234-1234-1234-123456789012,87654321-4321-4321-4321-210987654321\n```\n\n**📋 Backup Format Compatibility:**\n- **Personal-only backups** (default): Uses standard Bitwarden export format\n- **Organization backups**: Uses consolidated format when organizations are exported\n- **Restore script**: Automatically detects and handles both formats\n\n### 3. Run Backup\n\n**⚡ Fastest (No cloning required):**\n\n```bash\ndocker run --rm --env-file .env --pull always \\\n  -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata \\\n  nikhilbadyal/bitwarden-backup:latest\n```\n\n**Or with Docker Compose:**\n\n```bash\ngit clone https://github.com/nikhilbadyal/bitwarden-backup.git\ncd bitwarden-backup\n# Copy your .env file here\ndocker-compose up --build --no-cache\n# Added --no-cache to ensure latest image is always pulled.\n```\n\n**Or with scripts:**\n\n```bash\n./setup-rclone.sh \u0026\u0026 ./scripts/backup.sh\n```\n\nThat's it! Your vault will be backed up to all configured remotes with encryption and compression.\n\n**🖥️ Want a Web UI?** See the [Management Interface](#-management-interface) section below for the complete web dashboard setup!\n\n## 🌐 Management Interface\n\nThis project includes both a **modern web UI** and **REST API** for managing your Bitwarden backups through an intuitive interface or programmatic access.\n\n### Quick Setup\n\n**🖥️ Web UI + API (Recommended):**\n```bash\n# Start everything (UI + API + Redis + Nginx)\ndocker-compose -f docker-compose.full.yml up -d --build --no-cache\n# Added --build --no-cache to ensure latest image is always pulled and rebuilt.\n\n# Access the complete application\n# - Web UI: http://localhost:80\n# - API Docs: http://localhost:80/api/v1/docs\n```\n\n**🔌 API Only:**\n```bash\n# Run the API with Docker\n./run-api.sh\n\n# Access the API\n# - API Root: http://localhost:5050/\n# - Documentation: http://localhost:5050/api/v1/docs\n```\n\nFor detailed API setup instructions, Docker configuration, and usage examples, see:\n\n**📖 [API.md](API.md) - Complete API Setup Guide**\n\nThe API provides endpoints for:\n\n- 📊 System health and monitoring\n- 📁 Backup file management and listing\n- ☁️ Remote storage provider management\n- 🔍 Advanced search and filtering capabilities\n\n## 🖥️ Web UI Dashboard\n\nThis project includes a **modern React-based web interface** for managing your Bitwarden backups through an intuitive dashboard.\n\n### ✨ UI Features\n\n- **📊 Real-time System Health** - Monitor API status, Redis connectivity, and Rclone availability\n- **☁️ Remote Management** - View and manage all configured cloud storage remotes\n- **📁 Backup Browser** - Browse backup history with detailed metadata and logs\n- **🔧 Rclone Config Tool** - Convert and manage rclone configurations through the web interface\n- **🔐 Secure Authentication** - Token-based authentication with session management\n- **📱 Responsive Design** - Works on desktop, tablet, and mobile devices\n\n### 🚀 Quick UI Setup\n\n**Option 1: Full Stack (Recommended)**\n```bash\n# Start everything (API + UI + Redis + Nginx)\ndocker-compose -f docker-compose.full.yml up -d\n\n# Access the complete application\n# - Web UI: http://localhost:80\n# - API: http://localhost:80/api (proxied through Nginx)\n```\n\n**Option 2: Manual Development Setup**\n```bash\n# 1. Start the API backend\nuvicorn api.main:app --host 0.0.0.0 --port 5050\n\n# 2. In another terminal, start the UI\ncd ui\nnpm install\nnpm start\n\n# Access:\n# - UI: http://localhost:3000\n# - API: http://localhost:5050\n```\n\n**Option 3: Docker Compose (Separate Services)**\n```bash\n# Start API only\ndocker-compose -f docker-compose.api.yml up -d --build --no-cache\n# Added --build --no-cache to ensure latest image is always pulled and rebuilt.\n\n# Start UI only (in another terminal)\ndocker-compose -f docker-compose.ui.yml up -d --build --no-cache\n# Added --build --no-cache to ensure latest image is always pulled and rebuilt.\n\n# Access:\n# - UI: http://localhost:3000\n# - API: http://localhost:5050\n```\n\n### 🔧 UI Configuration\n\nThe UI requires these environment variables for proper API connectivity:\n\n| Variable            | Description     | Default                 | Docker Example            |\n|:--------------------|:----------------|:------------------------|:--------------------------|\n| `VITE_API_BASE_URL` | API backend URL | `http://localhost:5050` | `/api` (with Nginx proxy) |\n\n**For development:**\n```bash\n# In ui/.env file\nVITE_API_BASE_URL=http://localhost:5050\n```\n\n**For Docker with Nginx (recommended):**\nThe full Docker Compose setup automatically configures Nginx to:\n- Serve the UI on port 80\n- Proxy `/api/*` requests to the backend\n- Handle CORS and routing properly\n\n### 🎨 UI Development\n\nThe web interface is built with modern technologies:\n\n- **Frontend**: React 19 + Vite\n- **UI Framework**: Material-UI (MUI) v7\n- **Routing**: React Router v7\n- **Build Tool**: Vite (fast HMR and builds)\n- **Styling**: Emotion + MUI theming\n\n**Development Commands:**\n```bash\ncd ui\n\n# Install dependencies\nnpm install\n\n# Start development server (with hot reload)\nnpm start  # or npm run dev\n\n# Build for production\nnpm run build\n\n# Preview production build\nnpm run preview\n\n# Lint and format code\nnpm run lint\nnpm run format\n```\n\n### 🔐 Authentication\n\nThe UI uses token-based authentication:\n\n1. **First Visit**: You'll be redirected to the login page\n2. **Enter API Token**: Use the same `API_TOKEN` from your `.env` file\n3. **Persistent Session**: Token is stored in localStorage for convenience\n4. **Logout**: Click the logout button to clear the session\n\n### 📱 UI Screenshots \u0026 Features\n\n**System Health Dashboard:**\n- Real-time component status (Redis, Rclone)\n- System uptime and version information\n- One-click cache clearing\n- Color-coded health indicators\n\n**Remote Storage Management:**\n- View all configured rclone remotes\n- Test remote connectivity\n- Storage usage and configuration details\n\n**Backup Browser:**\n- Chronological backup listing\n- Detailed backup metadata (size, date, remote)\n- Download and restoration options\n- Search and filtering capabilities\n\n**Rclone Configuration:**\n- Web-based config converter\n- Base64 encoding/decoding\n- Configuration validation\n\n### 🐛 UI Development Notes\n\n**Full Disclosure**: The web interface was \"vibe coded\" due to limited frontend expertise - it's fully functional but could use some design polish! 😅\n\n**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.\n\n**Known Limitations**:\n- Basic responsive design (works but could be enhanced)\n- Minimal animations and transitions\n\n---\n\n## 📋 Detailed Documentation\n\n### What This Does\n\nThis repository provides a **\"configure once, forget forever\"** solution for Bitwarden vault backups:\n\n1. `setup-rclone.sh`: Configures rclone from a base64-encoded configuration to support **ANY rclone-compatible storage service**\n2. `backup.sh`: Performs automated backup, validates, compresses, encrypts, and uploads to **ALL configured remotes** simultaneously\n3. `generate-rclone-base64.sh`: Helper script to generate base64-encoded rclone configurations\n4. `restore-backup.sh`: Decrypt and restore backup files back to plain JSON format\n\n### Prerequisites\n\n- A Bitwarden account with API access enabled (works with both official Bitwarden and self-hosted servers)\n- Docker installed (recommended) OR `bw`, `jq`, `gzip`, `openssl`, `rclone` CLI tools installed\n- Access to one or more cloud storage services with rclone support\n\n### Alternative Installation Methods\n\n**🔧 Full Setup (Clone Repository):**\n\n```bash\ngit clone https://github.com/nikhilbadyal/bitwarden-backup.git\ncd bitwarden-backup\n\n# Generate rclone config\n./generate-rclone-base64.sh\n\n# Create .env file (copy from env.example)\ncp env.example .env\n# Edit .env with your values\n\n# Run backup\n./setup-rclone.sh \u0026\u0026 ./scripts/backup.sh\n```\n\n## 🔧 Configuration\n\n### Required Environment Variables\n\n| Variable               | Description                           | Example                       |\n|:-----------------------|:--------------------------------------|:------------------------------|\n| `BW_CLIENTID`          | Your Bitwarden API Client ID          | `user.1234567890abcdef`       |\n| `BW_CLIENTSECRET`      | Your Bitwarden API Client Secret      | `abcdef1234567890`            |\n| `BW_PASSWORD`          | Your Bitwarden Master Password        | `MySecretPassword123!`        |\n| `ENCRYPTION_PASSWORD`  | Strong password for backup encryption | `BackupEncryption456!`        |\n| `RCLONE_CONFIG_BASE64` | Base64-encoded rclone configuration   | `W215LXMzXQp0eXBlID0gczMK...` |\n\n### API Configuration (Required for API service)\n\n| Variable                         | Description                                                         | Example                                         |\n|:---------------------------------|:--------------------------------------------------------------------|:------------------------------------------------|\n| `API_TOKEN`                      | Authentication token for API access                                 | `your_secure_api_token`                         |\n| `REDIS_URL`                      | Redis connection URL for caching                                    | `redis://localhost:6379/0`                      |\n| `BACKUP_PATH`                    | Remote path/bucket for storing backups                              | `bitwarden-backup`                              |\n| `API_ALLOW_BACKUP_DECRYPTION`    | Enables sensitive download/restore operations                       | `false`                                         |\n| `API_ALLOWED_HOSTS`              | Trusted host allow-list (comma-separated)                           | `localhost,127.0.0.1,api.example.com`           |\n| `API_CORS_ORIGINS`               | Explicit CORS origins (comma-separated)                             | `http://localhost,http://localhost:3000`        |\n| `API_CORS_ALLOW_CREDENTIALS`     | CORS credential support (`true/false`)                              | `true`                                          |\n| `API_CORS_ALLOW_METHODS`         | Explicit CORS methods (comma-separated)                             | `GET,POST,PUT,DELETE,OPTIONS`                   |\n| `API_CORS_ALLOW_HEADERS`         | Explicit CORS request headers (comma-separated)                     | `Authorization,Content-Type,Accept`             |\n| `API_CORS_EXPOSE_HEADERS`        | CORS response headers exposed to browser (comma-separated)          | `X-Request-ID,X-Response-Time,X-API-Version`    |\n| `API_STREAM_TOKEN_TTL_SECONDS`   | Short-lived SSE stream token TTL in seconds                         | `120`                                           |\n\n### Self-Hosted Bitwarden Support\n\nThis backup tool **fully supports self-hosted Bitwarden servers**! Configure your custom server using these optional environment variables:\n\n| Variable           | Description                                   | Example                         |\n|:-------------------|:----------------------------------------------|:--------------------------------|\n| `BW_SERVER`        | **Primary server URL** (recommended approach) | `https://bitwarden.example.com` |\n| `BW_WEB_VAULT`     | Custom web vault URL (advanced)               | `https://vault.example.com`     |\n| `BW_API`           | Custom API URL (advanced)                     | `https://api.example.com`       |\n| `BW_IDENTITY`      | Custom identity URL (advanced)                | `https://id.example.com`        |\n| `BW_ICONS`         | Custom icons service URL (advanced)           | `https://icons.example.com`     |\n| `BW_NOTIFICATIONS` | Custom notifications URL (advanced)           | `https://notify.example.com`    |\n| `BW_EVENTS`        | Custom events URL (advanced)                  | `https://events.example.com`    |\n| `BW_KEY_CONNECTOR` | Key Connector URL (for organizations)         | `https://keycon.example.com`    |\n\n**Quick Examples:**\n\n```bash\n# For most self-hosted installations, just set BW_SERVER:\nBW_SERVER=\"https://vault.mycompany.com\"\n\n# For Bitwarden EU cloud:\nBW_SERVER=\"https://vault.bitwarden.eu\"\n\n# For complex custom setups (rarely needed):\nBW_WEB_VAULT=\"https://vault.example.com\"\nBW_API=\"https://api.example.com\"\nBW_IDENTITY=\"https://identity.example.com\"\n```\n\n**Important Notes:**\n- Leave these variables empty or unset to use the official Bitwarden service\n- `BW_SERVER` is the recommended approach for most self-hosted installations\n- Individual service URLs (`BW_API`, `BW_IDENTITY`, etc.) override `BW_SERVER` if both are set\n- All existing backup functionality works identically with self-hosted servers\n\n### Export Configuration Variables\n\n| Variable               | Description                                                               | Default | Example                     |\n|:-----------------------|:--------------------------------------------------------------------------|:--------|:----------------------------|\n| `EXPORT_PERSONAL`      | Export personal vault                                                     | `true`  | `true` or `false`           |\n| `EXPORT_ORGANIZATIONS` | Export organization vaults                                                | `false` | `true` or `false`           |\n| `BW_ORGANIZATION_IDS`  | Optional org IDs to export; empty means auto-discover all accessible orgs | None    | `12345678-...,87654321-...` |\n| `EXPORT_ORGANIZATIONS_FAIL_FAST` | Fail immediately when any org export fails (`true`) or continue with partial success (`false`) | `false` | `true` or `false` |\n\n**Format Details:**\n- When `EXPORT_ORGANIZATIONS=false` (default): Uses standard Bitwarden export format\n- When `EXPORT_ORGANIZATIONS=true`: Uses consolidated format with `personal` and `organizations` sections\n- When `EXPORT_ORGANIZATIONS_FAIL_FAST=false` (default): Organization export failures are logged and remaining orgs continue\n- Restore script automatically detects format and provides extraction options\n\n### Optional Variables (Advanced)\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand optional configuration\u003c/summary\u003e\n\n| Variable                 | Description                                | Default            |\n|:-------------------------|:-------------------------------------------|:-------------------|\n| `BACKUP_DIR`             | Temporary directory for backup files       | `/tmp/bw_backup`   |\n| `BACKUP_PATH`            | Remote path/bucket for storing backups     | `bitwarden-backup` |\n| `MIN_BACKUP_SIZE`        | Minimum backup size in bytes               | `1024`             |\n| `COMPRESSION_LEVEL`      | Gzip compression level (1-9)               | `9`                |\n| `RETENTION_COUNT`        | Number of backups to keep per remote       | `240`              |\n| `BW_UNLOCK_RETRIES`      | Number of vault unlock attempts            | `3`                |\n| `BW_UNLOCK_RETRY_DELAY`  | Seconds to wait between retry attempts     | `5`                |\n| `PBKDF2_ITERATIONS`      | PBKDF2 iterations for encryption           | `600000`           |\n| `BITWARDEN_SYNC_TIMEOUT` | Bitwarden sync timeout in seconds          | `60`               |\n| `PARALLEL_THRESHOLD`     | Min remotes needed for parallel processing | `3`                |\n| `MAX_PARALLEL_JOBS`      | Maximum parallel jobs for pruning          | `4`                |\n| `APPRISE_URLS`           | Notification URLs (space-separated)        | None               |\n| `BW_SERVER`              | Self-hosted Bitwarden server URL           | None               |\n| `BW_WEB_VAULT`           | Custom web vault URL (advanced)            | None               |\n| `BW_API`                 | Custom API URL (advanced)                  | None               |\n| `BW_IDENTITY`            | Custom identity URL (advanced)             | None               |\n| `BW_ICONS`               | Custom icons service URL (advanced)        | None               |\n| `BW_NOTIFICATIONS`       | Custom notifications URL (advanced)        | None               |\n| `BW_EVENTS`              | Custom events URL (advanced)               | None               |\n| `BW_KEY_CONNECTOR`       | Key Connector URL (for organizations)      | None               |\n\n**Important Notes:**\n\n- `BACKUP_PATH`: For S3-compatible services, this becomes the bucket name. For other services, this is the folder path where backups are stored.\n- `MIN_BACKUP_SIZE`: Backups smaller than this are considered invalid and the script will exit with an error.\n- `PBKDF2_ITERATIONS`: Changes only affect new backups. Restore script automatically detects iteration count for backward compatibility.\n- All scripts automatically load variables from `.env` file if it exists in the project root.\n\n\u003c/details\u003e\n\n### 📋 What You Get (Features)\n\n**Backup Features:**\n\n- **Multi-Remote Support**: Backup to multiple cloud services simultaneously\n- **Strong Encryption**: AES-256-CBC encryption with PBKDF2 (configurable, default 600,000 iterations) using your password\n- **Zero-Disk Security**: Uses secure pipe-based processing - unencrypted vault data never touches disk\n- **Smart Change Detection**: Only uploads when vault actually changes (SHA256 comparison)\n- **Detailed Notifications**: Per-remote status in final notifications (success/failed/up-to-date)\n- **Automatic Retries**: Handles network issues and API rate limiting for Bitwarden unlock\n- **Secure Cleanup**: Logs out of Bitwarden and cleans temporary files\n- **Cross-platform**: Supports Linux and macOS (different SHA256 utilities)\n\n**Restore Features:**\n\n- **Multi-Source Restore**: Decrypt local files or download from any remote\n- **Backup Browsing**: List and browse backups across all storage services\n- **Verification Pipeline**: Multi-stage validation (decryption → decompression → JSON validation)\n\n---\n\n## 🗂️ Detailed Documentation\n\n### Supported Cloud Storage Services\n\nThis backup solution supports **ALL rclone-compatible storage services**, including:\n\n**Object Storage:**\n\n- Amazon S3, Google Cloud Storage, Azure Blob Storage\n- Cloudflare R2, Backblaze B2, Wasabi, MinIO\n- IBM Cloud Object Storage, Oracle Cloud Storage\n\n**Consumer Cloud Storage:**\n\n- Google Drive, Dropbox, OneDrive, Box\n- pCloud, Mega, Yandex Disk, Mail.ru Cloud\n\n**Enterprise Storage:**\n\n- SFTP, FTP, WebDAV, HTTP\n- Swift (OpenStack), Ceph, QingStor\n\n**And many more!** See the [rclone documentation](https://rclone.org/) for the complete list.\n\n## Example Multi-Remote Setup\n\nYour rclone configuration can include multiple remotes:\n\n```ini\n[aws-s3]\ntype = s3\nprovider = AWS\naccess_key_id = AKIAIOSFODNN7EXAMPLE\nsecret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\nregion = us-east-1\n\n[google-drive]\ntype = drive\nclient_id = 123456789.apps.googleusercontent.com\nclient_secret = abcdefghijklmnopqrstuvwx\ntoken = {\"access_token\":\"ya29.a0AfH6SMC...\"}\n\n[cloudflare-r2]\ntype = s3\nprovider = Cloudflare\naccess_key_id = your_r2_access_key\nsecret_access_key = your_r2_secret_key\nendpoint = https://abc123.r2.cloudflarestorage.com\n\n[dropbox-backup]\ntype = dropbox\ntoken = {\"access_token\":\"sl.B0abcdefghijklmnop...\"}\n```\n\nThe backup script will automatically:\n\n1. Detect all 4 remotes\n2. Upload your backup to ALL of them\n3. Maintain separate retention policies for each\n4. Track changes independently per remote\n\n### Usage Examples\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand usage examples\u003c/summary\u003e\n\n**Manual Backup (Scripts):**\n\n```bash\n./setup-rclone.sh \u0026\u0026 ./scripts/backup.sh\n```\n\n**Automated with Cron:**\n\n```crontab\n# Daily backup at 3:00 AM\n0 3 * * * /path/to/bitwarden-backup/setup-rclone.sh \u0026\u0026 /path/to/bitwarden-backup/scripts/backup.sh \u003e\u003e /var/log/bitwarden_backup.log 2\u003e\u00261\n```\n\n**Docker Compose:**\n\n```bash\ndocker-compose up --build\n```\n\n**Automated Docker Compose with Cron:**\n\nFor automated backups using Docker Compose with cron scheduling, you have several options:\n\nAdd this to your host system's crontab:\n\n```crontab\n# Daily backup at 3:00 AM using Docker Compose\n0 3 * * * cd /path/to/bitwarden-backup \u0026\u0026 docker-compose up --build --force-recreate \u003e\u003e /var/log/bitwarden_backup.log 2\u003e\u00261\n\n# Weekly backup (Sundays at 2:00 AM)\n0 2 * * 0 cd /path/to/bitwarden-backup \u0026\u0026 docker-compose up --build --force-recreate \u003e\u003e /var/log/bitwarden_backup.log 2\u003e\u00261\n\n# Multiple daily backups (every 6 hours)\n0 */6 * * * cd /path/to/bitwarden-backup \u0026\u0026 docker-compose up --build --force-recreate \u003e\u003e /var/log/bitwarden_backup.log 2\u003e\u00261\n```\n\n**Cron Schedule Examples:**\n\n```crontab\n# Every day at 3:00 AM\n0 3 * * *\n\n# Every 12 hours (noon and midnight)\n0 */12 * * *\n\n# Every Monday at 2:00 AM\n0 2 * * 1\n\n# Every 1st day of the month at 1:00 AM\n0 1 1 * *\n\n# Every 15 minutes (for testing)\n*/15 * * * *\n\n# Multiple times per day (6 AM, 2 PM, 10 PM)\n0 6,14,22 * * *\n```\n\n**GitHub Actions Automation:**\n\n1. Fork this repository\n2. Add your environment variables as a repository secret named `BITWARDEN_BACKUP_ENV`\n3. Automatic daily backups run at 2:00 AM UTC with free GitHub infrastructure\n4. Includes pre-commit checks (shellcheck) and log artifact storage\n\n\u003c/details\u003e\n\n## 🔄 Backup Restoration\n\nThe `restore-backup.sh` script allows you to decrypt and restore your encrypted backups back to plain JSON format.\n\n### Quick Restore Examples\n\n```bash\n# Decrypt a local backup file\n./restore-backup.sh bw_backup_20241218123456.json.gz.enc\n\n# Download and decrypt latest backup from S3 remote\n./restore-backup.sh -r s3-remote\n\n# List all available backups from all configured remotes\n./restore-backup.sh -l\n\n# Decrypt with custom output filename\n./restore-backup.sh -f backup.enc -o my_vault.json\n```\n\n### Restore Options\n\n| Option            | Description                       | Example                |\n|:------------------|:----------------------------------|:-----------------------|\n| `-f, --file`      | Decrypt local backup file         | `--file backup.enc`    |\n| `-r, --remote`    | Download \u0026 decrypt from remote    | `--remote s3-backup`   |\n| `-o, --output`    | Custom output filename            | `--output vault.json`  |\n| `-l, --list`      | List backups from all remotes     | `--list`               |\n| `--list-remote`   | List backups from specific remote | `--list-remote gdrive` |\n| `--download-only` | Download without decrypting       | `--download-only`      |\n\n### Restoration Process\n\n1. **🔍 Validation** - Checks file existence and encryption password\n2. **🔓 Decryption** - Decrypts using AES-256-CBC with your password\n3. **📦 Decompression** - Extracts gzip compressed data\n4. **✅ JSON Validation** - Ensures valid Bitwarden vault format\n5. **💾 Secure Save** - Saves with secure file permissions (600)\n6. **🧹 Cleanup** - Removes temporary files\n\n### Security Notes\n\n- Restored JSON files contain **unencrypted vault data** - handle with care\n- Files are created with secure permissions (owner read/write only)\n- Temporary files are automatically cleaned up\n- **Delete restored files** when no longer needed\n- The same `ENCRYPTION_PASSWORD` from backups is required\n\n### Advanced Features\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand advanced features\u003c/summary\u003e\n\n**Detailed Backup Features:**\n\n- **Multi-Remote Support**: Backup to multiple cloud storage services simultaneously (S3, Google Drive, Dropbox, OneDrive, Cloudflare R2, and 40+ others supported by rclone)\n- **Base64 Configuration**: Accepts rclone config as base64 to avoid typing errors and enable easy deployment\n- **Isolated Configuration**: Uses project-specific rclone config to avoid interfering with your global rclone setup\n- **Multi-Stage Validation**: JSON validation, size checks, compression verification, and encryption testing\n- **Encryption Verification**: Tests decryption and validates gzip format before upload\n- **Intelligent Change Detection**: SHA256 hashing to avoid unnecessary uploads when vault hasn't changed\n- **Independent Retention Management**: Per-remote retention policies based on configurable count\n- **Optional Apprise Notifications**: Success and failure notifications\n- **Automatic Retry Logic**: Handles transient network issues and API rate limiting for Bitwarden vault unlock\n- **Robust Error Handling**: Individual remote failures don't stop the entire process\n- **Secure Cleanup**: Logs out of Bitwarden and unsets sensitive environment variables\n\n**Detailed Restore Features:**\n\n- **Multi-Source Restore**: Decrypt local files or download directly from any configured remote\n- **Backup Browsing**: List and browse available backups across all your cloud storage services\n- **Verification Pipeline**: Multi-stage validation (decryption → decompression → JSON validation)\n- **Secure Processing**: Temporary files with secure permissions and automatic cleanup\n- **Flexible Output**: Custom output file names and locations\n- **Download-Only Mode**: Download encrypted backups without decrypting (for manual processing)\n\n\u003c/details\u003e\n\n## Logging and Monitoring\n\n### Exit Codes\n\n| Code | Meaning                               |\n|:-----|:--------------------------------------|\n| `0`  | Success                               |\n| `1`  | Missing required environment variable |\n| `2`  | Missing required dependency           |\n| `3`  | Backup directory issue                |\n| `4`  | Bitwarden login failed                |\n| `5`  | Bitwarden vault unlock failed         |\n| `6`  | Bitwarden data export failed          |\n| `7`  | Invalid backup file                   |\n| `8`  | Compression or encryption failed      |\n| `99` | Unexpected error during upload        |\n\n### Notifications\n\nConfigure [Apprise](https://github.com/caronc/apprise) for notifications:\n\n```bash\n# Multiple notification services\nAPPRISE_URLS=\"mailto://user@example.com tgram://bot_token/chat_id discord://webhook_id/webhook_token\"\n```\n\n**Enhanced Notification Details:**\n\nThe final notification now includes detailed per-remote status:\n\n**Success Notification Example:**\n\n```\nBitwarden backup script completed successfully. New backup uploaded: bw_backup_20241218123456.json.gz.enc.\n\n📊 Remote Status:\n  ✅ aws-s3: Success\n  ✅ google-drive: Up to date\n  ❌ dropbox-backup: Failed\n  ✅ cloudflare-r2: Success\n\n📋 Summary: 📤 2 uploaded, ✅ 1 up-to-date, ❌ 1 failed\n```\n\n**No Changes Notification Example:**\n\n```\nBitwarden backup script completed successfully. No changes detected, no new backup uploaded.\n\n🔍 Remote Status:\n  ✅ aws-s3: Up to date\n  ✅ google-drive: Up to date\n  ✅ cloudflare-r2: Up to date\n```\n\n**Failure Notification Example:**\n\n```\nBitwarden backup script failed with exit code 8.\nReason: Compression or encryption failed. Check ENCRYPTION_PASSWORD.\n\n⚠️ Remote Status at time of failure:\n  ✅ aws-s3: Success\n  ❌ google-drive: Failed\n  ⏸️ dropbox-backup: Not processed\n```\n\n## Security Considerations\n\n- **`.env` File**: Contains sensitive credentials. Set permissions to `chmod 600 .env`.\n- **Backup Directory**: Set secure permissions `chmod 700` on backup directory.\n- **Encryption Password**: Store securely and separately from backups. **Losing this password means losing access to your backups.**\n- **Rclone Configuration**: Contains cloud storage credentials. The base64 encoding is for convenience, not security.\n- **Multi-Remote Security**: Each remote should have appropriate access controls and encryption.\n\n## Migration from R2-Only Version\n\nIf you're upgrading from the R2-only version:\n\n1. **Keep your existing `.env`** - the new version is backward compatible\n2. **Generate rclone config**: Use `./generate-rclone-base64.sh` to create `RCLONE_CONFIG_BASE64`\n3. **Add the new variable** to your `.env` file\n4. **Optional**: Remove old R2-specific variables (they're ignored now)\n5. **Run the backup** - it will work with your existing R2 setup plus any new remotes\n\n## Troubleshooting\n\n### Common Issues\n\n**\"RCLONE_CONFIG_BASE64 contains invalid base64 data\" (Docker Hub image only):**\n\nThere'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:\n\n**Workaround 1: Use local build instead**\n\n```bash\ngit clone https://github.com/nikhilbadyal/bitwarden-backup.git\ncd bitwarden-backup\n# Copy your .env file here\ndocker-compose up --build\n```\n\n**Workaround 2: Regenerate base64 (may help)**\n\n```bash\nbase64 -w 0 \u003c ~/.config/rclone/rclone.conf | tr -d '\\n'\n```\n\nThis issue is being investigated - the local build is currently more reliable.\n\n**No remotes found:**\n\n- Ensure `RCLONE_CONFIG_BASE64` is properly set\n- Test your config: `./generate-rclone-base64.sh --test`\n\n**Upload failures:**\n\n- Check remote credentials and permissions\n- Verify network connectivity\n- Review rclone configuration syntax\n\n**Permission errors:**\n\n- Ensure scripts are executable: `chmod +x *.sh scripts/*.sh`\n- Check backup directory permissions\n\n**Bitwarden unlock failures:**\n\nThe script includes automatic retry logic for vault unlock failures. If you're experiencing frequent unlock issues:\n\n- **Increase retry attempts**: Set `BW_UNLOCK_RETRIES=5` (default: 3)\n- **Increase retry delay**: Set `BW_UNLOCK_RETRY_DELAY=10` (default: 5 seconds)\n- **Check network connectivity** to Bitwarden servers\n- **Verify your master password** is correct in the `BW_PASSWORD` variable\n- **Check for API rate limiting** if running frequent backups\n\n**🎉 Universal Architecture Support:**\n\nThe Docker image is built for **2 main architectures** and works universally:\n\n- ✅ **linux/amd64** (Intel/AMD 64-bit: Most desktops, servers, cloud instances)\n- ✅ **linux/arm64** (ARM 64-bit: Apple Silicon, Raspberry Pi 4/5, AWS Graviton)\n\n**Manual Installation (without Docker):**\n\nIf running scripts directly on any system, install Bitwarden CLI via npm:\n\n```bash\n# Install Node.js and npm\nsudo apt update \u0026\u0026 sudo apt install -y nodejs npm\n\n# Install Bitwarden CLI globally\nsudo npm install -g @bitwarden/cli\n\n# Verify installation\nbw --version\n```\n\n**Read-only filesystem errors with Bitwarden CLI:**\n\nIf you see errors like `EROFS: read-only file system, open '/home/backupuser/.config/Bitwarden CLI/data.json'`:\n\nThis 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:\n\n```bash\ndocker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata nikhilbadyal/bitwarden-backup:latest\n```\n\n**Using outdated Docker images:**\n\nDocker may use cached local images instead of pulling the latest from Docker Hub. To ensure you're running the most recent version:\n\n```bash\n# Option 1: Use --pull always flag (recommended)\ndocker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata --pull always nikhilbadyal/bitwarden-backup:latest\n\n# Option 2: Manually pull first, then run\ndocker pull nikhilbadyal/bitwarden-backup:latest\ndocker run --rm --env-file .env -e BITWARDENCLI_APPDATA_DIR=/tmp/bw_appdata nikhilbadyal/bitwarden-backup:latest\n```\n\n**Note**: `docker-compose` automatically handles this with `pull_policy: always` in the compose file.\n\n### Getting Help\n\n1. **Check logs**: Review script output for specific error messages\n2. **Test rclone**: Use `rclone ls remote:` to test connectivity\n3. **Validate config**: Use the `--test` flag with the helper script\n4. **Check dependencies**: Ensure all required tools are installed\n\n## Contributing\n\nContributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.\n\n## License\n\nThis project is open source. Please check the license file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikhilbadyal%2Fbitwarden-backup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikhilbadyal%2Fbitwarden-backup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikhilbadyal%2Fbitwarden-backup/lists"}