Self-host Vaultwarden: your password manager in 14 MB of RAM

Published 2026-10-08 · tested on Ubuntu 24.04, Intel Core Ultra 7 255H, Docker 29

TESTED — we actually deployed this

Vaultwarden is an unofficial, lightweight server for Bitwarden clients — the entire Bitwarden experience (browser extensions, mobile apps, web vault) backed by a server you own, written in Rust. Bitwarden’s own self-host deployment wants multiple containers and ~2 GB of RAM; Vaultwarden runs in 14 MB. Not a typo — we measured it.

Every Bitwarden client works with it: point the official apps at your server URL and everything syncs.

Before you start: the HTTPS wall

Here’s the thing every first-timer hits (we hit it too, deliberately): the web vault refuses to work over plain HTTP. The browser crypto APIs Bitwarden clients use require a secure context. Deploy on http://localhost:8080, try to create an account, and you get:

Error: Insecure URL not allowed. All URLs must use HTTPS.

So unlike most self-hosted apps, TLS isn’t a “later” step — it’s step one. The cleanest fix is running Caddy alongside, which handles certificates automatically. That’s what we do below.

The Compose file (Vaultwarden + Caddy)

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    environment:
      - DOMAIN=https://vault.example.com
      - SIGNUPS_ALLOWED=true
    volumes:
      - vw-data:/data
    restart: unless-stopped

  caddy:
    image: caddy:2
    container_name: vw-caddy
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
    restart: unless-stopped

volumes:
  vw-data:
  caddy-data:

And the Caddyfile:

vault.example.com {
  reverse_proxy vaultwarden:80
}

With a real domain pointed at your server, Caddy obtains a Let’s Encrypt certificate automatically — zero TLS configuration. For LAN-only/homelab use without a domain, change the Caddyfile site to localhost:8443 with tls internal (self-signed, you accept the browser warning) — that’s exactly how we ran our test — or better, use Tailscale and its built-in HTTPS certs.

Note Vaultwarden itself exposes no host port — only Caddy is reachable. That’s intentional.

docker compose up -d

First account, then lock the door

  1. Open your vault URL → Create account → use a long master passphrase you’ve never used anywhere else. There is no recovery: lose the master password, lose the vault.
  2. Immediately after creating your account, disable public signups — this server is on the internet and open registration on a password manager is a standing invitation:
    environment:
      - SIGNUPS_ALLOWED=false

docker compose up -d again to apply. Existing accounts are unaffected; new registrations are blocked.

  1. Point your clients at it: Bitwarden browser extension / mobile app → settings gear at the login screen → “self-hosted” → your URL.

Vaultwarden web vault with a saved login item

What it costs to run (measured)

Metric Measured value
Image size 86 MB
RAM (vault active, 1 user) 14 MB
Caddy alongside 19 MB
CPU idle 0.00%
Data volume (1 user, SQLite) 0.4 MB
Restart to ready 1 s

This is the lightest self-hosted app we’ve tested — 30x lighter than n8n, 10x lighter than Uptime Kuma. It runs on anything: a Pi Zero, the smallest VPS in existence, or squeezed alongside everything else on a free Oracle VM without noticing.

Backups are not optional here

This isn’t a media server where losing data means re-ripping DVDs. This is every password you have. The entire state lives in the vw-data volume (SQLite + attachments + RSA keys):

docker run --rm -v vaultwarden_vw-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/vw-backup-$(date +%F).tar.gz -C /data .

Cron it daily, keep copies in two places (one off-site — even a private git repo or rclone to any object storage), and test a restore once. Also: each client keeps a full offline cache of the vault, which is an accidental extra backup — but don’t rely on it.

Gotchas

When NOT to self-host this

What we actually ran this on