Deploy Vaultwarden on Docker: Self-Hosted Bitwarden Server for Your HomeLab

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

Quick Start (5 Min)

Managing credentials across multiple devices gets messy fast as your homelab grows. Vaultwarden solves this problem cleanly. It re-implements the Bitwarden server API in Rust, slashing resource usage down to roughly 30MB of RAM compared to the 3GB to 4GB required by the official .NET and MSSQL stack.

Grab this production-ready docker-compose.yml file to deploy Vaultwarden with persistent storage and real-time push sync enabled:

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      - WEBSOCKET_ENABLED=true
      - SIGNUPS_ALLOWED=true
    volumes:
      - ./vw-data:/data
    ports:
      - 8080:80
      - 3012:3012

Bring up the container from your terminal:

mkdir -p ~/vaultwarden && cd ~/vaultwarden
# Save the configuration above into docker-compose.yml
docker compose up -d
docker compose logs -f vaultwarden

Check the logs. Once the engine boots, navigate to http://<your-server-ip>:8080 in your browser. Register your primary admin account immediately before opening any ports to external networks.

Deep Dive

Why Choose Vaultwarden Over Official Bitwarden?

Official Bitwarden targets enterprise infrastructure. It relies on a dozen microservice containers, an expensive Microsoft SQL Server instance, and heavy memory reserves. In contrast, Vaultwarden packages every required service into a single compiled Rust binary.

By default, it uses an embedded SQLite engine with WAL mode enabled, though you can plug in PostgreSQL or MariaDB if your workload demands it. Even a $35 Raspberry Pi 4 with 2GB of RAM can handle a library of 5,000 passwords across 10 concurrent active users without latency spikes.

The HTTPS Requirement and Web Crypto API

Try logging into a remote Vaultwarden instance over plain HTTP, and the web app will immediately fail with cryptographic errors. This behavior is deliberate. Modern browsers enforce a secure context requirement on the native crypto.subtle Web Crypto API.

Without TLS, client browsers refuse to derive encryption keys from your master password. You can satisfy this requirement using a lightweight reverse proxy like Caddy to terminate SSL via Let’s Encrypt certificates automatically:

vault.homelab.local {
    reverse_proxy vaultwarden:80

    # WebSocket reverse proxy rules for instant push updates
    reverse_proxy /notifications/hub vaultwarden:3012
    reverse_proxy /notifications/hub/negotiate vaultwarden:80
}

Architecture and Real-Time Synchronization

Vaultwarden uses two network pathways to maintain full compatibility with upstream Bitwarden apps:

  • Port 80: Powers standard REST API endpoints, user authentication flows, static web vault assets, and encrypted vault reads and writes.
  • Port 3012: Listens for WebSocket connections. When you update an entry on your desktop extension, this socket immediately triggers a delta push to your phone and tablet, eliminating manual sync clicks.

Advanced Usage

Securing the Admin Dashboard with Argon2id

Vaultwarden provides an emergency maintenance dashboard at /admin to configure server variables and manage user invites. Leaving this endpoint protected by a plain text password in your Compose file is a major security risk. Generate a salted cryptographic hash using Vaultwarden’s built-in utility instead:

docker run --rm -it vaultwarden/server:latest /vaultwarden hash --preset owasp

The CLI will output an Argon2id string formatted like this:

$argon2id$v=19$m=65536,t=3,p=4$q+...$aK...

Insert this hash into your docker-compose.yml file. While editing, turn off open registrations to lock out unwanted users:

    environment:
      - WEBSOCKET_ENABLED=true
      - SIGNUPS_ALLOWED=false
      - ADMIN_TOKEN='$$argon2id$$v=19$$m=65536,t=3,p=4$$q+...$$aK...'
      - INVITATIONS_ALLOWED=true
      - DOMAIN=https://vault.homelab.local

Note: Escape each dollar sign by doubling it ($$) in Docker Compose files. Otherwise, the Compose engine tries to interpolate the string as an unset system variable.

Hardening Authentication: 2FA and Hardware Keys

Once you sign in, go to Account Settings > Security > Two-step Login. Vaultwarden supports standard TOTP authenticators such as Aegis and Ente Auth, alongside hardware security tokens like Yubikeys using FIDO2 and WebAuthn.

WebAuthn requires strict origin validation. Your DOMAIN variable must match the exact HTTPS URL you enter in your browser’s address bar, including the scheme and port if non-standard.

Practical Tips

Atomic Database Backups Without Downtime

Never copy active SQLite database files like db.sqlite3 with raw commands like cp. You risk capturing uncommitted journal transactions from WAL files, which corrupts the resulting backup snapshot. Instead, invoke the SQLite online backup API via host CLI tools:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/opt/backups/vaultwarden"
DATA_DIR="${HOME}/vaultwarden/vw-data"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
mkdir -p "${BACKUP_DIR}"

# Safely dump an atomic SQLite snapshot without stopping the container
sqlite3 "${DATA_DIR}/db.sqlite3" ".backup '${BACKUP_DIR}/vault_${TIMESTAMP}.sqlite3'"

# Archive cryptographic keys and file attachments
tar -czf "${BACKUP_DIR}/data_${TIMESTAMP}.tar.gz" -C "${DATA_DIR}" attachments rsa_key.pem

# Purge archives older than 14 days
find "${BACKUP_DIR}" -type f -mtime +14 -delete

This script executes in under 200 milliseconds on modest systems. Run it nightly at 03:00 via cron, and mirror the backup directory offsite to an encrypted storage target such as Backblaze B2 or a remote TrueNAS server.

Connecting Official Bitwarden Client Apps

You can use standard, unmodified Bitwarden apps across iOS, Android, macOS, Linux, and Windows. To link your client to your self-hosted server:

  1. Open the Bitwarden extension or native mobile application.
  2. Click the Settings gear on the login screen before typing credentials.
  3. Enter your domain in the Server URL field: https://vault.homelab.local.
  4. Save the setting, enter your email and master password, and complete your 2FA prompt.

Your vault entries now sync instantly through your private server, with zero telemetry or plain text credentials leaving your home network.

Share: