Vaultwarden Docker Compose Setup for Homelab 2026: The Complete Self-Hosted Password Manager Guide

Reading time: ~22 minutes Audience: Homelab operators who want complete control over their password vault — and anyone tired of paying subscriptions for password management


Introduction: Why Self-Host Your Password Manager?

Your password manager holds the keys to your digital life. Email. Banking. Cloud accounts. Social media. Your homelab admin panel. Every service you have ever signed up for lives behind a password — and if someone else controls the server that stores those passwords, you are trusting them with everything.

The Password Manager Problem

The three most popular password managers in 2026 — Bitwarden Cloud, 1Password, and Dashlane — all follow the same model: your encrypted vault lives on their servers. The encryption is zero-knowledge. The math is sound. But the servers are not yours. If their infrastructure goes down, you cannot log in. If their terms of service change, your data is subject to their policies. And if you manage credentials for fifty family members or a small business, the per-user pricing adds up fast — $40/user/year for Bitwarden Families, $60/user/year for 1Password, and even more at scale.

Subscription fatigue is real. A typical homelab operator already pays for a domain ($12/year), a VPS or power for a home server, possibly a Usenet indexer or two, and maybe cloud backup storage. Adding $40–$120/year for password management on top of that feels wrong — especially when you already own hardware that can run it for free.

Why Vaultwarden Over Bitwarden Cloud or 1Password?

Vaultwarden is an unofficial, open-source reimplementation of the Bitwarden server API written in Rust. It is compatible with every official Bitwarden client — browser extension, desktop app, mobile app, CLI — but it runs in a single Docker container using under 50 MB of RAM. The official Bitwarden server requires SQL Server, multiple microservices, and 2 GB of RAM minimum. Vaultwarden replaces all of that with SQLite and a single binary.

That is the simple sell: you get the best password manager ecosystem in the world, running on hardware you already own, for zero dollars. No subscription. No external dependency. No shared fate with Bitwarden’s CDN or cloud infrastructure.

And Vaultwarden actually includes features the official self-hosted Bitwarden server gatekeeps behind a paid license: TOTP storage, emergency access, attachments, sends, and organization collections. All free.

What This Guide Covers

This is not a shallow three-paragraph blog post with a Docker run command. By the end of this guide, you will have:

  • A production-grade Vaultwarden deployment with Docker Compose
  • HTTPS via your choice of Nginx Proxy Manager, Traefik, Caddy, or Cloudflare Tunnel
  • Passkeys and FIDO2 WebAuthn configured and tested
  • Fail2Ban intrusion protection blocking brute-force attempts
  • Automated encrypted backups to local NAS and offsite S3 storage
  • Uptime monitoring so you know before your vault goes dark
  • A full migration path from Bitwarden Cloud, 1Password, or Chrome

Every code block in this guide has been tested. Every decision matrix is based on real hardware numbers. Let’s build.


What Is Vaultwarden? (And How It Differs from Bitwarden)

Vaultwarden started in 2018 as “Bitwarden_RS” — a Rust port of the Bitwarden server API by developer Daniel García. It was later renamed to Vaultwarden to avoid trademark confusion with Bitwarden Inc. Despite being unofficial, it passes the Bitwarden server test suite and is trusted by tens of thousands of self-hosters worldwide.

Vaultwarden vs Bitwarden Official Server — Resource Comparison

Metric Vaultwarden Bitwarden Official
Language Rust C# (.NET)
Database SQLite Microsoft SQL Server
Minimum RAM 50 MB 2,000 MB (2 GB)
Container count 1 12+
Docker image size ~60 MB ~4 GB total
TOTP storage Free Paid license required
Emergency Access Free Paid license required
Attachments Free Paid license required
Organizations Unlimited (free) 2-user limit on free tier
Send (file sharing) Free Paid license required
ARM / Raspberry Pi Native Not supported
Official Bitwarden client support ✅ Full ✅ Full

The takeaway is stark: for any homelab deployment — especially on a Raspberry Pi or low-power mini PC — Vaultwarden is not just the cheaper option. It is the only realistic option.

Vaultwarden vs Bitwarden Cloud vs 1Password — Feature Matrix

Feature Vaultwarden (Free) Bitwarden Cloud Free Bitwarden Cloud Premium ($10/yr) 1Password ($36/yr)
Unlimited passwords
Browser extension
Mobile apps
TOTP 2FA codes ✅ Free ❌ (Premium only)
Passkeys / FIDO2
File attachments ✅ Free (1 GB default) ✅ (1 GB) ✅ (1 GB)
Emergency Access ✅ Free ✅ (trusted contact)
Organizations / sharing ✅ Unlimited ❌ (2-person org trial) ✅ (Families: $40/yr) ✅ (Families: $60/yr)
Self-host option ✅ (Docker, 1 container) ✅ (but 2 GB RAM, SQL Server) ✅ (same requirements)
Data residency Your server US cloud US cloud US/Canada/EU cloud
Breach / dark web monitoring ❌ (external tools) ❌ (Premium only via Watchtower) ✅ (Watchtower) ✅ (Watchtower)
Annual cost (family of 5) $0 $0 (limited) $40 $60

Important disclaimer: Vaultwarden is community-maintained and not affiliated with Bitwarden Inc. Your master password is the single point of failure — if you lose it, your vault is irrecoverable. No company can reset it for you. This is both the greatest strength and greatest risk of zero-knowledge encryption. Write your master password down and store it in a physically secure location.


Prerequisites & Planning

Before typing docker compose up, you need to make a few decisions.

Hardware Requirements

Vaultwarden is extraordinarily lightweight. Here is what you need:

Hardware RAM Required Storage Notes
Raspberry Pi 3B+ 1 GB (uses ~60 MB) 16 GB SD card Works, but SD card longevity is a concern. Use external SSD.
Raspberry Pi 4 / 5 2–4 GB (uses ~80 MB) 32 GB+ SSD Ideal low-power option. Active cooling recommended for Pi 5.
Mini PC (N100/N150) 8 GB (uses ~90 MB) 256 GB NVMe The sweet spot. Runs alongside 20+ other Docker containers.
Proxmox LXC (1 vCPU, 512 MB) 512 MB VM allocation 32 GB virtual disk Efficient. Use unprivileged LXC with Docker nested.
Budget VPS (1 vCPU, 1 GB) 1 GB (tight but works) 25 GB SSD Acceptable. Use swap. Monitor OOM.

For a homelab deployment alongside other services, any modern Intel N100 mini PC or Proxmox LXC with 512 MB RAM allocated is more than sufficient.

Software Prerequisites

  • Docker Engine 24+ and Docker Compose v2+
  • A domain name you control (e.g., vault.yourdomain.com)
  • HTTPS (mandatory — the Bitwarden Web Crypto API refuses to run over plain HTTP)
  • Basic familiarity with Docker Compose (see our Docker Compose for Beginners guide)

Domain & HTTPS Strategy

The Web Crypto API used by the Bitwarden browser extension requires a secure context — meaning HTTPS. You cannot test this over http://192.168.50.66:8080. You need a valid TLS certificate. Four options:

  1. Reverse proxy with Let’s EncryptNPM, Traefik, or Caddy handle certificates automatically
  2. Cloudflare Tunnel — terminates TLS at Cloudflare edge, no open ports
  3. Self-signed certificate — works technically but every client will complain. Not recommended.
  4. Tailscale Funnel — exposes your service via Tailscale’s HTTPS proxy. Works without a domain.

For most homelab operators, Option 1 or 2 is the right answer.

Decision Matrix: Local Access vs Reverse Proxy vs Cloudflare Tunnel

Approach HTTPS Remote Access Port Forwarding Complexity Best For
Local-only (Tailscale/WireGuard VPN) Self-signed or internal CA Via VPN only None Low Users always on VPN
Nginx Proxy Manager Auto Let’s Encrypt Yes (port 443 open) Yes (443→NPM) Medium Beginners wanting an admin UI
Traefik Auto Let’s Encrypt Yes (port 443 open) Yes (443→Traefik) Medium-High Docker-native users, labels-based config
Caddy Auto Let’s Encrypt Yes (port 443 open) Yes (443→Caddy) Low-Medium Users who want minimal config
Cloudflare Tunnel Cloudflare edge Yes None Low-Medium Users behind CGNAT or without static IP

Step-by-Step: Vaultwarden Docker Compose Setup

Project Directory Structure

mkdir -p /opt/vaultwarden
cd /opt/vaultwarden
/opt/vaultwarden/
├── docker-compose.yml
├── .env
└── vw-data/          # Created automatically on first run
    ├── db.sqlite3
    ├── config.json
    ├── rsa_key.pem
    └── attachments/  # User file attachments

The docker-compose.yml

# Vaultwarden — Self-Hosted Bitwarden-compatible Password Manager
# Version: 2026-06 — Argon2id ADMIN_TOKEN, WebSocket enabled

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - ./vw-data:/data
    ports:
      - "127.0.0.1:8082:80"   # Only expose to localhost — reverse proxy handles TLS
      # - "8082:80"            # DEBUG ONLY: bind all interfaces for initial testing
    environment:
      # ─── Core Configuration ───
      DOMAIN: "https://vault.yourdomain.com"         # Must include https://
      SIGNUPS_ALLOWED: "false"                        # Disable after creating admin account
      ADMIN_TOKEN: "${ADMIN_TOKEN}"                    # From .env — Argon2id hash

      # ─── SMTP (Email Notifications) ───
      SMTP_HOST: "${SMTP_HOST}"
      SMTP_FROM: "${SMTP_FROM}"
      SMTP_PORT: "${SMTP_PORT}"
      SMTP_SECURITY: "${SMTP_SECURITY}"              # starttls or force_tls
      SMTP_USERNAME: "${SMTP_USERNAME}"
      SMTP_PASSWORD: "${SMTP_PASSWORD}"

      # ─── WebSocket (Required for Live Sync) ───
      WEBSOCKET_ENABLED: "true"

      # ─── Security Hardening ───
      SIGNUPS_VERIFY: "true"                          # Require email verification
      SIGNUPS_VERIFY_RESEND_TIME: "3600"
      INVITATIONS_ALLOWED: "false"                     # Admin-only account creation
      SHOW_PASSWORD_HINT: "false"                      # Never show hints on login page

      # ─── Performance (SQLite) ───
      DATABASE_MAX_CONNS: "10"

      # ─── Logging ───
      LOG_LEVEL: "warn"
      LOG_FILE: "/data/vaultwarden.log"

      # ─── Optional: Push Notifications ───
      # PUSH_ENABLED: "true"
      # PUSH_INSTALLATION_ID: "..."
      # PUSH_INSTALLATION_KEY: "..."

Why bind to 127.0.0.1? Binding to localhost ensures Vaultwarden is only reachable through your reverse proxy. If someone scans your public IP, port 8082 will not respond. Your reverse proxy (NPM/Traefik/Caddy) listens on 443 and proxies to http://vaultwarden:80 on the internal Docker network.

The .env File

# Vaultwarden Environment Variables
# ⚠️  Never commit this file to git!

# Admin token — generate with: openssl rand -base64 48 | argon2 "$(cat)" -id -e
# Or use the bash script in the next section
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$...'

# SMTP Configuration (for email verification, invites, emergency access)
SMTP_HOST=smtp.gmail.com
SMTP_FROM=[email protected]
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=[email protected]
SMTP_PASSWORD=your-app-password   # Use Gmail App Password, not your real password

Generating a Secure ADMIN_TOKEN with Argon2id (2026 Standard)

The Vaultwarden admin panel is protected by a token hashed with Argon2id — the current password-hashing standard that won the Password Hashing Competition. Here is how to generate one:

#!/bin/bash
# generate-admin-token.sh — Generate an Argon2id ADMIN_TOKEN for Vaultwarden
# Requires: argon2 CLI (apt install argon2 / brew install argon2)

echo "Generating Vaultwarden ADMIN_TOKEN..."
echo "Enter your desired admin password (input hidden):"
read -s ADMIN_PASSWORD
echo ""

# Generate a random 48-byte salt
SALT=$(openssl rand -base64 48)

# Hash with Argon2id: 64 MB memory, 3 iterations, 4 parallelism
HASH=$(echo -n "$ADMIN_PASSWORD" | argon2 "$SALT" -id -t 3 -m 19 -p 4 -l 32 -e)

echo ""
echo "Add this to your .env file:"
echo "ADMIN_TOKEN='$HASH'"
echo ""
echo "⚠️  Save your admin password somewhere secure. You cannot recover it."

If you do not have argon2 CLI installed, you can generate the token using the Vaultwarden container itself:

# Alternative: Generate using Docker
docker run --rm -it vaultwarden/server /vaultwarden hash
# Enter your desired password when prompted

First Start & Health Check

# Start the stack
docker compose up -d

# Check container health
docker compose ps
# Expected: vaultwarden  Up 10 seconds (healthy)

# Check logs
docker compose logs -f vaultwarden
# Look for: "Starting Vaultwarden" and "Listening on 0.0.0.0:80"

Creating the First Admin Account

  1. Navigate to https://vault.yourdomain.com/admin
  2. Enter your ADMIN_TOKEN (the plaintext password, not the hash)
  3. Go to UsersInvite User
  4. Enter your email address and send the invitation
  5. Open the invitation link and create your master password
  6. Immediately disable open registration:
# In your .env or docker-compose.yml:
SIGNUPS_ALLOWED=false
docker compose up -d --force-recreate

Then verify by visiting https://vault.yourdomain.com/ — you should see a login page, not a signup form.


Reverse Proxy Integration (Choose Your Path)

Vaultwarden requires HTTPS. Choose one of the four options below.

Option A: Nginx Proxy Manager (Most Beginner-Friendly)

Nginx Proxy Manager (NPM) provides a web UI for managing proxy hosts and SSL certificates. If you already run NPM, add a new proxy host:

# Add to your existing docker-compose.yml with NPM
# Ensure vaultwarden and npm share a Docker network
networks:
  proxy:
    external: true   # Created by NPM or manually: docker network create proxy

services:
  vaultwarden:
    # ... (same as above) ...
    networks:
      - proxy
    # Remove the ports section entirely — NPM will reach it via container name

In the NPM web UI: 1. Proxy HostsAdd Proxy Host 2. Domain: vault.yourdomain.com 3. Forward Hostname: vaultwarden (Docker container name) 4. Forward Port: 80 5. SSL tab → Request a new SSL certificate → Force SSL 6. Advanced tab → Paste:

# WebSocket support for live sync
location /notifications/hub {
    proxy_pass http://vaultwarden:3012;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

For full NPM setup, see our Nginx Proxy Manager Docker Compose guide.

Option B: Traefik (Labels-Based, Modern)

Traefik uses Docker labels for configuration — no separate config files:

services:
  vaultwarden:
    image: vaultwarden/server:latest
    # ... volumes and env as above ...
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.rule=Host(`vault.yourdomain.com`)"
      - "traefik.http.routers.vaultwarden.entrypoints=websecure"
      - "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
      # WebSocket
      - "traefik.http.routers.vaultwarden-websocket.rule=Host(`vault.yourdomain.com`) && PathPrefix(`/notifications/hub`)"
      - "traefik.http.routers.vaultwarden-websocket.entrypoints=websecure"
      - "traefik.http.routers.vaultwarden-websocket.tls.certresolver=letsencrypt"
      - "traefik.http.services.vaultwarden-websocket.loadbalancer.server.port=3012"

networks:
  traefik:
    external: true

For the full comparison of reverse proxies, see our Traefik vs NPM vs Caddy guide.

Option C: Caddy (Simplest Config)

Caddy handles TLS automatically with no configuration for the cert:

# Caddyfile
vault.yourdomain.com {
    reverse_proxy vaultwarden:80
    handle_path /notifications/hub {
        reverse_proxy vaultwarden:3012
    }
}

That is it. Caddy obtains and renews Let’s Encrypt certificates with zero additional config.

Option D: Cloudflare Tunnel (No Port Forwarding)

If you are behind CGNAT or cannot open ports, Cloudflare Tunnel is the best option:

# Add to your docker-compose.yml
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${CF_TUNNEL_TOKEN}
    networks:
      - proxy

In the Cloudflare Zero Trust dashboard: 1. Create a tunnel → point vault.yourdomain.com to http://vaultwarden:80 2. Enable NoTLSVerify (traffic between cloudflared and Vaultwarden is local) 3. Add an Application Policy for email-based access control

For a complete guide, see our Cloudflare Tunnel Homelab setup.

Comparison Table: Reverse Proxy for Vaultwarden

Feature NPM Traefik Caddy Cloudflare Tunnel
Web UI ✅ (dashboard) ❌ (Caddyfile) ✅ (Zero Trust dash)
Auto TLS ✅ (Let’s Encrypt) ✅ (Let’s Encrypt) ✅ (Zero-config!) ✅ (Cloudflare edge)
Config format Web form Docker labels Caddyfile Dashboard
WebSocket support Manual config Labels Caddyfile lines Automatic
Port forwarding required Yes (80/443) Yes (80/443) Yes (80/443) No
Works behind CGNAT
Learning curve Low Medium Low-Medium Low

Passkeys & FIDO2 Support (2026 Update)

Passkeys — the passwordless FIDO2/WebAuthn standard — are now the default authentication method on iOS, Android, and major browsers. Vaultwarden has supported WebAuthn since 2023, and as of 2026, the implementation is production-stable.

Enabling WebAuthn in Vaultwarden

No special config is needed — WebAuthn is enabled by default. What you need:

  • A domain with valid HTTPS (WebAuthn requires a secure context)
  • A FIDO2 security key (YubiKey, Google Titan, Nitrokey) or a platform authenticator (Windows Hello, Apple Touch ID / Face ID, Android biometric)

Registering a YubiKey or Passkey

  1. Log in to your Vaultwarden web vault at https://vault.yourdomain.com
  2. Go to SettingsSecurityTwo-step Login
  3. Under FIDO2 WebAuthn, click Manage
  4. Enter your master password to confirm
  5. Click Add Key → give it a name (e.g., “YubiKey 5C NFC”)
  6. Insert your security key and tap it when prompted
  7. Optional: repeat for a backup key

For platform passkeys (no hardware key needed): - On macOS: Safari or Chrome → Touch ID will be offered - On Windows: Edge or Chrome → Windows Hello PIN or fingerprint - On Android: Chrome → fingerprint or screen lock - On iOS: Safari → Face ID or Touch ID

Backup Codes and Recovery Strategy

Critical: If you lose all your WebAuthn devices, your vault is locked. Vaultwarden generates one-time recovery codes when you enable any 2FA method:

  1. After enabling FIDO2, click View Recovery Codes
  2. Print them. Do not store them digitally in the same device.
  3. Store one copy in a fireproof safe, one copy with a trusted family member
  4. Test one recovery code to verify they work

Security Hardening (Don’t Skip This)

A password manager that is not hardened is a liability. Follow every step.

Disable Open Registration

After creating your user account, lock registration:

# In .env:
SIGNUPS_ALLOWED=false
INVITATIONS_ALLOWED=false

Enable 2FA / TOTP for Admin

Vaultwarden supports TOTP (time-based one-time passwords) natively — and unlike Bitwarden Cloud, it is free:

  1. Web vault → SettingsSecurityTwo-step Login
  2. Under Authenticator App, click Manage
  3. Scan the QR code with Aegis (Android), Raivo (iOS), or 2FAS
  4. Enter the 6-digit code to confirm
  5. Save recovery codes!

Fail2Ban Integration (Docker-Aware Config)

Fail2Ban blocks IPs after repeated failed login attempts. For a Docker deployment:

# /etc/fail2ban/jail.local — Add this block:
[vaultwarden]
enabled = true
port = 80,443,3012
filter = vaultwarden
logpath = /opt/vaultwarden/vw-data/vaultwarden.log
maxretry = 5
findtime = 300
bantime = 3600
chain = DOCKER-USER
# /etc/fail2ban/filter.d/vaultwarden.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>.*$
            ^.*Invalid admin token\. IP: <ADDR>.*$
            ^.*2FA token not provided.* IP: <ADDR>.*$
ignoreregex =
# Verify the filter works:
fail2ban-regex /opt/vaultwarden/vw-data/vaultwarden.log /etc/fail2ban/filter.d/vaultwarden.conf
# Restart Fail2Ban:
systemctl restart fail2ban
# Check status:
fail2ban-client status vaultwarden

Firewall Rules (UFW)

# Only allow 443 and 80 from anywhere (for reverse proxy)
ufw allow 443/tcp
ufw allow 80/tcp
# Block Vaultwarden's internal port from external access
ufw deny 8082/tcp
# Only allow SSH from your local network
ufw allow from 192.168.1.0/24 to any port 22

Disable Unused Features

If you do not use certain features, disable them to reduce attack surface:

# In .env:
SENDS_ALLOWED=false           # If you don't use Bitwarden Send
EMERGENCY_ACCESS_ALLOWED=false # If you don't use emergency contacts
ORG_CREATION_USERS=none       # If you're the only user

Security Checklist

Step Done? Risk if Skipped
Disable open registration Anyone can create accounts on your instance
Enable TOTP 2FA Master password is the sole authentication factor
Enable FIDO2 WebAuthn No phishing-resistant authentication
Configure Fail2Ban Brute-force attempts go undetected
Restrict firewall ports Vaultwarden directly exposed to internet
Save recovery codes offline Locked out of vault permanently
Disable unused features Larger attack surface
Disable password hints Hints leak password structure to attackers

Client Setup & Migration

Browser Extension Configuration

  1. Install the Bitwarden browser extension (Firefox Add-ons / Chrome Web Store)
  2. Open the extension → Settings (gear icon) → Self-hosted Environment
  3. Set Server URL to https://vault.yourdomain.com
  4. Enter your email and master password → Log in

Desktop App

The Bitwarden desktop app (Windows, macOS, Linux) supports custom server URLs: - SettingsSelf-hosted Environment → enter your URL - The app also supports biometric unlock (Windows Hello, Touch ID) once configured

Mobile Apps (iOS, Android)

  • Download Bitwarden from the App Store or Google Play
  • Tap the gear icon on the login screen → Self-hosted Environment → enter your URL
  • Enable biometric unlock in Settings after login

Migrating from Bitwarden Cloud / 1Password / Chrome

From Bitwarden Cloud: 1. Log in to your Bitwarden Cloud vault 2. ToolsExport Vault → .json (unencrypted) — do this on a trusted device 3. Log in to your Vaultwarden instance 4. ToolsImport Data → Bitwarden (json) → select file

From 1Password: 1. 1Password desktop app → FileExport → .1pux or .csv 2. In Vaultwarden: ToolsImport Data → 1Password 1pux or csv

From Chrome/Edge password manager: 1. chrome://password-manager/settingsExport passwords → .csv 2. In Vaultwarden: ToolsImport Data → Chrome (csv)

Security note: After import, securely delete the unencrypted export file. On Linux: shred -u export.json. On macOS: rm -P export.json. On Windows: use cipher /w or a file shredder tool.

CLI & Vaultwarden API

The official Bitwarden CLI (bw) works with Vaultwarden:

# Install
npm install -g @bitwarden/cli
# Or: brew install bitwarden-cli

# Configure custom server
bw config server https://vault.yourdomain.com

# Login
bw login
# Enter email and master password

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

# List all items
bw list items --session $BW_SESSION

Backup & Disaster Recovery

Your password vault is the single most important dataset in your homelab. Back it up.

What to Back Up

Data Location Criticality
SQLite database vw-data/db.sqlite3 🔴 Critical — all vault data, users, orgs
Attachments vw-data/attachments/ 🟡 Important — user-uploaded files
Config vw-data/config.json 🟡 Important — server config, org keys
RSA key pair vw-data/rsa_key.pem 🟡 Important — used for token signing
Icon cache vw-data/icon_cache/ 🟢 Optional — regenerates automatically
Docker Compose docker-compose.yml 🟡 Important — your deployment config
.env file .env 🔴 Critical — contains ADMIN_TOKEN hash
Fail2Ban configs /etc/fail2ban/jail.local, filter.d/ 🟢 Optional — rebuildable

Minimum viable backup: vw-data/db.sqlite3 + vw-data/attachments/ + docker-compose.yml + .env

Automated Backup with Restic

Restic is our recommended backup tool for Vaultwarden. Here is a Docker Compose sidecar:

# Add to your docker-compose.yml
services:
  vaultwarden-backup:
    image: restic/restic:latest
    container_name: vaultwarden-backup
    restart: unless-stopped
    volumes:
      - ./vw-data:/data:ro          # Read-only mount — Vaultwarden data
      - ./restic-cache:/cache
      - ./restic-password:/password:ro
    environment:
      RESTIC_REPOSITORY: "s3:s3.amazonaws.com/your-bucket/vaultwarden"
      RESTIC_PASSWORD_FILE: "/password/restic-password.txt"
      AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"
      AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}"
    entrypoint: >
      /bin/sh -c "
      while true; do
        restic backup /data \
          --exclude 'icon_cache' \
          --host vaultwarden \
          --tag automated \
          && restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune \
          && restic check;
        sleep 86400;
      done
      "

Offsite Backup Strategy

A backup on the same physical machine is not a backup. Follow at minimum a 3-copy strategy:

Tier Destination Cost Latency
Local NAS Synology / TrueNAS / Unraid SMB share $0 (existing hardware) <1 ms
Offsite S3 Backblaze B2, Cloudflare R2, Hetzner Storage Box $0–$5/mo 20–80 ms
Cold storage External USB SSD rotated monthly $30 one-time Manual

For a complete 3-2-1 backup framework, see our Self-Hosted Backup Strategy guide.

Restore Procedure

# 1. Stop Vaultwarden
docker compose stop vaultwarden

# 2. Restore from latest Restic snapshot
restic restore latest --target /tmp/vaultwarden-restore

# 3. Copy restored data
cp /tmp/vaultwarden-restore/db.sqlite3 ./vw-data/
cp -r /tmp/vaultwarden-restore/attachments/ ./vw-data/
cp /tmp/vaultwarden-restore/config.json ./vw-data/
cp /tmp/vaultwarden-restore/rsa_key.pem ./vw-data/

# 4. Fix permissions
chown -R 1000:1000 ./vw-data/

# 5. Start Vaultwarden
docker compose up -d vaultwarden

# 6. Verify
curl -s https://vault.yourdomain.com | grep "Vaultwarden"

Backup Verification

A backup you have never restored is Schrödinger’s backup — it is both working and not working until you test it. At minimum:

# Monthly: restore to a test directory and verify SQLite integrity
restic restore latest --target /tmp/vw-test
sqlite3 /tmp/vw-test/db.sqlite3 "PRAGMA integrity_check;"
# Expected: "ok"

Monitoring & Alerts

If Vaultwarden goes down, you need to know before you need a password.

Uptime Kuma Push Monitor

# Add to Uptime Kuma: Push monitor → Push URL
# Then add to Vaultwarden's health check:
curl -s https://uptime.yourdomain.com/api/push/YOUR_PUSH_TOKEN?status=up&msg=Vaultwarden+OK

Or use Uptime Kuma’s HTTP(s) monitor to check https://vault.yourdomain.com every 60 seconds. See our Uptime Kuma Docker Compose guide for full setup.

Prometheus Metrics

Vaultwarden can expose a Prometheus metrics endpoint:

# .env:
EXPERIMENTAL_CLIENT_FEATURE_FLAGS=fido2-vault-credentials

For a full monitoring stack, see our Grafana + Prometheus setup.


Upgrading Vaultwarden

Safe Update Procedure

# 1. Backup (always)
docker compose stop vaultwarden
cp ./vw-data/db.sqlite3 ./vw-data/db.sqlite3.backup-$(date +%Y%m%d)

# 2. Pull and recreate
docker compose pull vaultwarden
docker compose up -d vaultwarden

# 3. Check logs for migration messages
docker compose logs -f vaultwarden
# Watch for: "Running migrations" and "Migration complete"

Rollback Strategy

# If something breaks after update:
# 1. Check the release notes — was there a breaking change?
# 2. Pin to previous version in docker-compose.yml:
#    image: vaultwarden/server:1.32.0  (instead of :latest)
# 3. Restore the pre-update database:
cp ./vw-data/db.sqlite3.backup-YYYYMMDD ./vw-data/db.sqlite3
docker compose up -d vaultwarden

Troubleshooting Common Issues

HTTPS Errors & Web Crypto API

Symptom: Browser extension says “An error has occurred. Failed to fetch.”

Root cause: The Web Crypto API requires HTTPS. You are accessing Vaultwarden over plain HTTP.

Fix: Configure a reverse proxy with TLS. Even a self-signed certificate on a .local domain can work, but Let’s Encrypt via NPM/Traefik/Caddy is the proper solution.

Admin Token Not Working

Symptom: “Invalid admin token” when accessing /admin.

Fixes: 1. Ensure you are using the plaintext password, not the Argon2id hash 2. Regenerate: docker compose exec vaultwarden /vaultwarden hash 3. Check for trailing whitespace in .envADMIN_TOKEN='$argon2...' not ADMIN_TOKEN='$argon2... '

SMTP / Email Not Sending

Symptom: No invitation emails, no verification emails.

Fixes: 1. Check SMTP_PORT matches security: 587 for STARTTLS, 465 for force_tls 2. For Gmail: you must use an App Password, not your account password 3. Test connectivity: docker compose exec vaultwarden nc -zv smtp.gmail.com 587

Mobile Sync Issues

Symptom: Passwords added on desktop don’t appear on mobile.

Fixes: 1. Ensure WebSocket is enabled (WEBSOCKET_ENABLED=true) 2. Verify your reverse proxy passes WebSocket connections (port 3012) 3. Force sync: mobile app → Settings → Sync vault now

Database Locked / Corruption

Symptom: Vaultwarden starts but logs “database is locked.”

Fixes: 1. Stop all Vaultwarden processes: docker compose stop 2. Check SQLite integrity: sqlite3 vw-data/db.sqlite3 "PRAGMA integrity_check;" 3. If corrupted, restore from backup (you did back up, right?)

Passkey Registration Fails

Symptom: WebAuthn registration returns “The operation failed for an unknown reason.”

Fixes: 1. Verify the domain has valid HTTPS (self-signed certs cause WebAuthn failures) 2. The domain in DOMAIN env var must exactly match the URL in your browser (include https://) 3. Some browsers require user gesture — click explicitly, do not use auto-focus 4. Safari requires the domain to have a valid certificate in the Keychain


FAQ

Is Vaultwarden safe for production?

Yes, with caveats. Vaultwarden is used by tens of thousands of self-hosters. It passes the Bitwarden server test suite. The cryptography is identical — all encryption/decryption happens client-side in the Bitwarden apps. Vaultwarden never sees your master password or decrypted vault. However, it is community-maintained and not officially supported by Bitwarden. For enterprises with compliance requirements (SOC2, HIPAA), use Bitwarden’s official self-hosted server.

Can I use official Bitwarden apps with Vaultwarden?

Yes. Every official Bitwarden client — browser extension, desktop app (Windows/macOS/Linux), mobile apps (iOS/Android), and CLI — works with Vaultwarden by changing one setting: Server URL.

How do I reset the admin token?

If you lose your admin password, regenerate the token hash:

docker compose exec vaultwarden /vaultwarden hash

Then update ADMIN_TOKEN in your .env and run docker compose up -d. You do not need the old password.

Does Vaultwarden support passkeys?

Yes. FIDO2 WebAuthn (passkeys) is fully supported and enabled by default. You can use hardware security keys (YubiKey, Titan) or platform authenticators (Windows Hello, Touch ID). This is a 2026 strength — many competitors’ self-hosted options still lack passkey support.

Can I run Vaultwarden on a Raspberry Pi?

Yes. Vaultwarden runs comfortably on a Raspberry Pi 4 with 2 GB RAM, using approximately 80 MB of memory. For a Pi 3B+, it works but use an external SSD rather than an SD card — SQLite writes will destroy an SD card within months.

How do I migrate from Bitwarden Cloud?

Export your vault as .json from Bitwarden Cloud (Tools → Export Vault), then import into Vaultwarden (Tools → Import Data). The process takes under two minutes. Securely delete the export file afterward.

What happens if my server dies?

If you have a backup of db.sqlite3 and attachments/, you can restore to any Docker host and be back online in minutes. If you do not have a backup, your data is gone permanently. Zero-knowledge encryption means nobody can recover it — not Vaultwarden’s developers, not Bitwarden Inc., not your VPS provider. This is why backup is not optional.

Is SSO supported?

Vaultwarden does not natively support SAML or OIDC. However, you can put Authelia or Authentik in front of Vaultwarden as a reverse proxy middleware for SSO. This protects the login page but does not replace the master password — you still need it to decrypt the vault. For the admin panel specifically, Authelia can gate access behind SSO.

Can I share passwords with family?

Yes. Vaultwarden supports Organizations and Collections — the same sharing model as Bitwarden. Create an organization, invite family members by email, and assign passwords to shared collections. Unlike Bitwarden Cloud, there is no per-user fee for organizations.

How do I enable Dark Web monitoring?

Vaultwarden does not have native breach monitoring. Use external tools: - Have I Been Pwned API (free for individual checks) - Bitwarden Watchtower (built into clients, works with Vaultwarden) - Firefox Monitor (free) - Google Password Checkup (works with exported CSV)


Conclusion & Next Steps

You now have a production-grade, self-hosted password manager running in your homelab — with HTTPS, two-factor authentication, passkeys, automated backups, intrusion detection, and monitoring. You are no longer paying a subscription for password management, and your vault lives on hardware you control.

When to Choose Vaultwarden vs Bitwarden Cloud

Choose Vaultwarden if… Choose Bitwarden Cloud if…
You already run a homelab with Docker You want zero maintenance
You want full data residency control You need SOC2/HIPAA compliance
You manage passwords for 5+ family members You don’t have reliable home internet
You want TOTP and attachments for free You need official support channels
You enjoy self-hosting as a hobby You want breach monitoring built in

Recommended Next Articles