Vaultwarden Backup

This role backs up Vaultwarden (self-hosted Bitwarden) password vault using the official Bitwarden CLI.

ARA Ansible Bash Debian HTTPS JSON NAS Proxmox

Vaultwarden Backup Role

Overview

This role backs up Vaultwarden (self-hosted Bitwarden) password vault using the official Bitwarden CLI. It downloads the CLI temporarily, authenticates with API credentials, exports the vault as encrypted JSON, and stores it on dual NAS storage. The role automatically manages retention by keeping only the last 5 backups per NAS.

Purpose

  • Password Vault Protection: Backs up all passwords, notes, and vault items
  • Encrypted Export: Vault exported in encrypted format for security
  • Disaster Recovery: Restore vault after data loss or corruption
  • Migration Support: Transfer vault to new Vaultwarden instance
  • Dual Redundancy: Backs up to two separate NAS devices (Synology DS418 and Proxmox OMV)
  • Automated Process: Handles authentication, sync, export, and cleanup automatically

Requirements

  • Ansible 2.9 or higher
  • Vaultwarden server accessible via HTTPS
  • Vaultwarden API credentials (client ID and secret)
  • Master password for vault
  • Export password for encrypted backups
  • NAS mount points must be accessible and writable
  • unzip package (installed by role if missing)

What is Vaultwarden?

Vaultwarden is an unofficial Bitwarden-compatible server written in Rust. It provides:

  • Self-hosted password vault
  • Multi-device synchronization
  • Password generation
  • Secure notes and file attachments
  • Two-factor authentication
  • Compatible with official Bitwarden clients

Role Variables

Required Variables

VariableRequiredDescription
vault_vaultwarden_api_client_idYesVaultwarden API client ID (stored in Ansible Vault)
vault_vaultwarden_api_client_secretYesVaultwarden API client secret (stored in Ansible Vault)
vault_vaultwarden_master_passwordYesVault master password (stored in Ansible Vault)
vault_vaultwarden_backup_export_passwordYesPassword for encrypting the export (stored in Ansible Vault)

Optional Variables

VariableDefaultDescription
vaultwarden_backup_urlhttps://server.homelabVaultwarden instance URL
vaultwarden_backup_ca_file"" (system CA bundle)Custom CA certificate file path
vaultwarden_backup_syno_mount_point/mnt/synology-ds418/vaultwardenSynology NAS backup destination
vaultwarden_backup_prxmxomv_mount_point/mnt/prxmx-omv/vaultwardenProxmox OMV NAS backup destination

Variable Details

API Credentials (vault_vaultwarden_api_client_id and vault_vaultwarden_api_client_secret)

API credentials for programmatic access to Vaultwarden.

How to create API credentials in Vaultwarden:

  1. Log into Vaultwarden web vault
  2. Go to Settings → Security → Keys
  3. Click “View API Key”
  4. Enter master password
  5. Copy client_id and client_secret

Example vault variables:

vault_vaultwarden_api_client_id: "user.abc123def-456-789-ghi-jkl012mno345"
vault_vaultwarden_api_client_secret: "pqr678stu901vwx234yz..."

Master Password (vault_vaultwarden_master_password)

Your Vaultwarden master password. Required to unlock the vault.

Example vault variable:

vault_vaultwarden_master_password: "YourVerySecureMasterPassword123!"

Export Password (vault_vaultwarden_backup_export_password)

Password used to encrypt the exported JSON file. Should be different from master password for defense in depth.

Example vault variable:

vault_vaultwarden_backup_export_password: "DifferentSecureExportPassword456!"

Custom CA Certificate (vaultwarden_backup_ca_file)

Path to custom CA certificate file if using self-signed certificates.

Example:

vaultwarden_backup_ca_file: "/etc/ssl/certs/custom-ca.crt"

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • Vaultwarden server running and accessible
  • Valid Vaultwarden account with API access
  • NAS mounts configured (see nas_mount or nas_mount_systemd roles)
  • Internet access to download Bitwarden CLI

Example Playbook

Basic Usage

---
- name: Backup Vaultwarden Vault
  hosts: localhost
  become: true

  roles:
    - vaultwarden_backup

With Custom Configuration

---
- name: Backup Vaultwarden with Custom Settings
  hosts: localhost
  become: true

  vars:
    vaultwarden_backup_url: "https://passwords.example.com"
    vaultwarden_backup_ca_file: "/etc/ssl/certs/my-ca.crt"

  roles:
    - vaultwarden_backup

Scheduled Backup with Cron

---
- name: Schedule Weekly Vaultwarden Backup
  hosts: localhost
  become: true

  tasks:
    - name: Create cron job for weekly vault backup
      ansible.builtin.cron:
        name: "Weekly Vaultwarden Vault Backup"
        minute: "0"
        hour: "3"
        weekday: "0"  # Sunday
        job: "ansible-playbook /path/to/vaultwarden_backup.yml"

What This Role Does

  1. Ensures backup directories exist on both NAS mount points
  2. Creates temporary directory for Bitwarden CLI
  3. Downloads Bitwarden CLI from official source
  4. Ensures unzip is installed (for extracting CLI)
  5. Extracts Bitwarden CLI binary
  6. Sets executable permissions on CLI binary
  7. Configures server URL for Vaultwarden instance
  8. Logs in with API credentials (using environment variables)
  9. Unlocks vault with master password
  10. Extracts session key for authenticated operations
  11. Syncs vault to ensure latest data
  12. Exports vault as encrypted JSON to Synology NAS
  13. Exports vault as encrypted JSON to Proxmox OMV NAS
  14. Locks vault (clears session)
  15. Logs out from Vaultwarden
  16. Displays success message
  17. Cleans up temporary CLI directory
  18. Removes old backups, keeping only the 5 most recent per NAS

Bitwarden CLI Workflow

1. Download and Setup

# Download CLI
wget https://bitwarden.com/download/?app=cli&platform=linux -O bw-linux.zip

# Extract
unzip bw-linux.zip

# Make executable
chmod +x bw

2. Configure Server

bw config server https://server.homelab

3. Login with API Key

export BW_CLIENTID="client_id"
export BW_CLIENTSECRET="client_secret"
bw login --apikey

4. Unlock Vault

export BW_PASSWORD="master_password"
BW_SESSION=$(bw unlock --passwordenv BW_PASSWORD --raw)

5. Sync and Export

bw sync --session $BW_SESSION
bw export --format encrypted_json --password 'export_password' --output backup.json --session $BW_SESSION

6. Cleanup

bw lock
bw logout

Backup Format

File Naming

vaultwarden_backup_YYYYMMDD_HHMMSS.json

Examples:

  • vaultwarden_backup_20260107_143022.json
  • vaultwarden_backup_20260107_190530.json

Note: Uses underscore instead of ‘T’ for better readability.

JSON Content

The backup is an encrypted JSON file containing:

  • All vault items (logins, notes, cards, identities)
  • Folders and organization
  • Attachments metadata (not files)
  • Encrypted with the export password

Format:

{
  "encrypted": true,
  "passwordProtected": true,
  "salt": "...",
  "kdfIterations": 100000,
  "kdfType": 0,
  "encKeyValidation_DO_NOT_EDIT": "...",
  "data": "...encrypted data..."
}

Backup Content

The backup includes:

  • All vault items (logins, secure notes, cards, identities)
  • Folders and collections
  • Custom fields
  • URIs and match detection settings
  • TOTP secrets (2FA seeds)
  • Attachments metadata (filenames, not actual files)

The backup does NOT include:

  • File attachments (actual file content)
  • Trash/deleted items
  • Vault history
  • Organization settings (if using organizations)

Backup Security

The exported JSON is doubly encrypted:

  1. Bitwarden Encryption: Vault items are encrypted with your master password (always)
  2. Export Encryption: The export file is encrypted with the export password

To decrypt, you need:

  • Bitwarden CLI
  • Export password
  • Master password (to access items after import)

Backup Retention

The role implements automatic retention management:

  • Keeps: Last 5 backups per NAS
  • Deletes: Backups older than the 5th most recent
  • Per-NAS logic: Each NAS independently maintains 5 backups

This ensures you have:

  • 5 backups on Synology DS418
  • 5 backups on Proxmox OMV
  • Total: Up to 10 backup copies across both devices

Restoration

Import via Bitwarden CLI

# Configure server
bw config server https://server.homelab

# Login
bw login admin@example.com

# Unlock
export BW_SESSION=$(bw unlock --raw)

# Import encrypted backup
bw import bitwardenencjson vaultwarden_backup_20260107_143022.json \
  --importsecurepassword 'export_password' --session $BW_SESSION

Import via Web Vault

  1. Log into Vaultwarden web vault
  2. Go to Tools → Import Data
  3. Select format: “Bitwarden (json) - Encrypted”
  4. Choose file
  5. Enter export password
  6. Click “Import”

Security Considerations

  • Credentials Protected: All sensitive values marked with no_log: true
  • Vault Storage: All credentials must be in Ansible Vault
  • Double Encryption: Export is encrypted separately from vault encryption
  • Temporary CLI: Downloaded and cleaned up automatically
  • Session Management: Vault locked and logged out after export
  • File Permissions: Backup files should be readable only by authorized users
  • Consider Encryption at Rest: Encrypt NAS volumes for additional security

Tags

This role does not define any tags. Use playbook-level tags if needed:

- hosts: localhost
  roles:
    - vaultwarden_backup
  tags:
    - backup
    - vaultwarden
    - passwords
    - security

Notes

  • Downloads official Bitwarden CLI from bitwarden.com
  • CLI is temporary and removed after backup
  • Requires internet access to download CLI
  • Export includes vault metadata but not actual attachment files
  • Role uses shell module for password handling (more secure than command)
  • Supports custom CA certificates for self-signed SSL

Troubleshooting

”Authentication failed” or login errors

Verify API credentials:

  • Check client ID and secret are correct
  • Regenerate API key in Vaultwarden if needed
  • Ensure account is active and not locked

”Invalid master password”

Check:

  • Master password is correct (case-sensitive)
  • Account hasn’t been locked due to failed attempts
  • Test login via web vault

”Failed to export”

Common causes:

  • Export password is weak (needs to meet minimum requirements)
  • Insufficient disk space on NAS
  • Permission issues on destination directory

”Connection refused” or SSL errors

Verify:

  • Vaultwarden is running and accessible
  • URL is correct
  • SSL certificates are valid (or use custom CA)
  • Network connectivity

”Command not found” for unzip

The role installs unzip, but if it fails:

# Debian/Ubuntu
sudo apt-get install unzip

# RedHat/CentOS
sudo yum install unzip

Large vault takes long time

Normal for vaults with:

  • Thousands of items
  • Many attachments (metadata)
  • Slow network connection

Typical times:

  • Small vault (< 100 items): ~10-15 seconds
  • Medium vault (< 1000 items): ~30-60 seconds
  • Large vault (1000+ items): ~1-3 minutes

Performance Considerations

  • CLI download: ~5MB, takes 1-5 seconds
  • Login and unlock: ~2-3 seconds
  • Sync: Variable (depends on vault size)
  • Export: Variable (depends on vault size and NAS speed)

Total time: Usually 20-60 seconds for average vault

Bitwarden/Vaultwarden Compatibility

  • Bitwarden CLI: Works with both official Bitwarden and Vaultwarden
  • Vaultwarden: Compatible with all Bitwarden CLI versions
  • Export Format: Standard across Bitwarden/Vaultwarden

Best Practices

  1. Use strong export password (different from master password)
  2. Schedule regular backups (weekly minimum)
  3. Test restoration periodically
  4. Encrypt NAS volumes for additional security
  5. Keep export password secure (store in Ansible Vault)
  6. Monitor backup job for failures

Alternative: Database Backup

For additional safety, also backup the Vaultwarden database:

# Backup SQLite database (if using SQLite)
- name: Backup Vaultwarden database
  ansible.builtin.copy:
    src: /path/to/vaultwarden/db.sqlite3
    dest: /mnt/nas/vaultwarden/db_backup.sqlite3
    remote_src: true

This provides a low-level backup in addition to the encrypted export.

License

MIT

Author

Created for homelab infrastructure management.