Skip to content

Deploy Vaultwarden

Vaultwarden is a Rust rewrite of Bitwarden server, compatible with all official Bitwarden clients (browser extensions, desktop, mobile). Lighter resource usage than the official server — runs comfortably on a Raspberry Pi.

  • Vaultwarden at vault.example.com with TLS
  • SQLite backend (default; PostgreSQL option below)
  • Admin panel enabled for user management
  • Nightly encrypted backups off-host

Stacks → New stack → name vaultwarden:

services:
vaultwarden:
image: vaultwarden/server:latest
restart: unless-stopped
environment:
DOMAIN: https://vault.example.com
ADMIN_TOKEN: ${ADMIN_TOKEN}
SIGNUPS_ALLOWED: "false"
INVITATIONS_ALLOWED: "true"
SHOW_PASSWORD_HINT: "false"
WEB_VAULT_ENABLED: "true"
SMTP_HOST: ${SMTP_HOST}
SMTP_FROM: ${SMTP_FROM}
SMTP_PORT: "587"
SMTP_SECURITY: "starttls"
SMTP_USERNAME: ${SMTP_USERNAME}
SMTP_PASSWORD: ${SMTP_PASSWORD}
TZ: ${TZ:-Europe/Berlin}
volumes:
- vw_data:/data
volumes:
vw_data:
  • ADMIN_TOKEN — long random token (64 chars). Access the admin panel at https://vault.example.com/admin with this token. Generate:
    Terminal window
    openssl rand -base64 48
  • SMTP_* — your outbound email credentials. Required for email verification, password resets, and user invitations. See SMTP setup if you don’t have this yet.

Deploy the stack. Then add a reverse proxy route:

  • Domain: vault.example.com
  • Target: vaultwarden_vaultwarden_1
  • Port: 80
  • TLS: Automatic

TLS is non-negotiable for Vaultwarden. The mobile apps refuse to connect to plain HTTP.

  1. Visit https://vault.example.com/admin
  2. Paste ADMIN_TOKEN
  3. Users → Invite — send invitations to team members
  4. Invitees get an email with a signup link (valid 5 days by default)

With SIGNUPS_ALLOWED: "false" and INVITATIONS_ALLOWED: "true" (our default), only invited users can register. This is the safe default for a team vault.

For a single-user setup (just you), set SIGNUPS_ALLOWED: "true" temporarily, register, then set back to false.

Vaultwarden’s /data volume contains:

  • db.sqlite3 — all vault data (encrypted at rest by Bitwarden clients)
  • attachments/ — file attachments
  • sends/ — Bitwarden Send files
  • icon_cache/ — site icons (reproducible, can skip)
  • rsa_key.* — RSA keys for JWT signing

Backups → Jobs → New job:

  • Stacks: vaultwarden
  • Target: off-host
  • Schedule: Daily
  • Retention: Keep last 30
  • Encryption: age passphrase (store in your other password manager or on paper)

Skip the icon_cache/ directory to save space — it rebuilds automatically.

Vaultwarden exposes /alive for health checks. Add an alert rule:

  • Metric: container.health
  • Scope: stack vaultwarden
  • Condition: not healthy for 5m
  • Severity: critical
  • Channels: your on-call channel

Losing access to the password manager in an outage is stressful. Get paged fast.

For multi-instance HA or if you standardize on Postgres, use:

environment:
DATABASE_URL: postgresql://vault:${DB_PASSWORD}@db/vault

Add the db: service from other tutorials. Note: Vaultwarden with Postgres is well-supported but most home-labbers stick with SQLite — simpler backups, faster.

Point the official Bitwarden browser extension / desktop app / mobile app at your server:

  1. Settings → Self-hosted Environment
  2. Server URL: https://vault.example.com
  3. Save, log in with the account you created via the admin invitation flow
  • Vault content is encrypted client-side before it reaches the server — even with full server access, attackers can’t decrypt vaults without the master password
  • Rotate ADMIN_TOKEN quarterly. The admin panel bypasses the vault encryption model for some operations
  • Enable 2FA on every user account (TOTP, YubiKey, Duo all supported)
  • Disable SIGNUPS_ALLOWED after initial setup
  • Consider a Cloudflare Access / Tailscale layer in front if you want IP-restricted access