2026-09-18
How to Self-Host Vaultwarden on a Raspberry Pi 5 with Automatic HTTPS and Backups
Vaultwarden runs comfortably on a Raspberry Pi 5 and gives you a fully functional, self-hosted Bitwarden-compatible password manager in under an hour. This guide covers exactly how I set it up on my own Pi 5 — NVMe boot, Docker, Caddy for automatic HTTPS, and encrypted off-site backups — with the real numbers from my build.
My Hardware
- Board: Raspberry Pi 5 Model B Rev 1.1 with 15 Gi RAM (the 16 GB SKU) Raspberry Pi 5 16GB
- NVMe: Fanxiang S501Q 512 GB, booting directly from
/dev/nvme0n1p2 - OS: Debian GNU/Linux 13 (trixie), kernel 6.18.34+rpt-rpi-2712
- PCIe: Gen 2 (the Pi 5 default)
Sequential reads land at 453 MB/s and writes at 438 MB/s; random 4K reads hit 16,433 IOPS. For a SQLite-backed password vault that rarely exceeds a few megabytes, this is wildly more than enough. SoC temperature sat at 49.4 °C idle and actually dropped to 48.8 °C under load during a sustained fio run — the active cooler on my Pi 5 clearly had headroom to spare.
If you want to keep your NVMe drive portable for cloning or offline backups, an external enclosure like M.2 NVMe SSD Enclosure – USB-C 10Gbps with Magnetic Closure makes swapping and imaging painless.
Prerequisites
You need a domain name pointing to your home IP (or a VPS IP). I use a cheap domain from Namecheap. You also need port 443 forwarded on your router to the Pi's local IP, or a reverse tunnel if your ISP uses CGNAT.
Ensure Docker and Docker Compose are installed:
sudo apt update && sudo apt install -y docker.io docker-compose-v2
sudo usermod -aG docker $USER
# Log out and back in
Step 1: Directory Structure
mkdir -p ~/vaultwarden/{data,caddy_data,caddy_config,backups}
cd ~/vaultwarden
Step 2: Docker Compose File
Create docker-compose.yml:
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: "https://vault.yourdomain.com"
SIGNUPS_ALLOWED: "false"
ADMIN_TOKEN: "" # set via argon2 hash, see below
volumes:
- ./data:/data
expose:
- "80"
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "443:443"
- "80:80"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy_data:/data
- ./caddy_config:/config
Generate the Admin Token
Don't put a plaintext password in the compose file. Generate an Argon2 hash:
docker run --rm vaultwarden/server /vaultwarden hash --preset owasp
Paste your password when prompted, then put the full $argon2id$... output string into the ADMIN_TOKEN field.
Step 3: Caddyfile for Automatic HTTPS
Create Caddyfile in the same directory:
vault.yourdomain.com {
reverse_proxy vaultwarden:80
}
That's it. Caddy handles Let's Encrypt certificate issuance and renewal automatically. No certbot cron jobs, no nginx config.
Step 4: Start Everything
docker compose up -d
Visit https://vault.yourdomain.com — you should see the Bitwarden web vault. Create your first account, then immediately set SIGNUPS_ALLOWED: "false" (already done in the compose file above) and restart:
docker compose restart vaultwarden
The admin panel lives at https://vault.yourdomain.com/admin.
Step 5: Automatic Encrypted Backups
The Vaultwarden SQLite database lives in ./data/db.sqlite3. It's small — typically under 10 MB even with hundreds of entries. Back it up nightly.
Local Backup Script
Create backup.sh:
#!/bin/bash
BACKUP_DIR="/home/$USER/vaultwarden/backups"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
DB_PATH="/home/$USER/vaultwarden/data"
# Use sqlite3 .backup for a consistent copy
sqlite3 "$DB_PATH/db.sqlite3" ".backup '$BACKUP_DIR/db-$TIMESTAMP.sqlite3'"
# Encrypt with age (or gpg)
age -p -o "$BACKUP_DIR/db-$TIMESTAMP.sqlite3.age" "$BACKUP_DIR/db-$TIMESTAMP.sqlite3"
rm "$BACKUP_DIR/db-$TIMESTAMP.sqlite3"
# Keep only last 30 backups locally
ls -t "$BACKUP_DIR"/*.age | tail -n +31 | xargs -r rm
chmod +x backup.sh
sudo apt install -y age sqlite3
Cron It
crontab -e
# Add:
0 3 * * * /home/$USER/vaultwarden/backup.sh
Off-Site Copy
I push the encrypted .age files to a Backblaze B2 B2 bucket using rclone:
sudo apt install -y rclone
rclone config # set up a B2 remote called "b2vault"
Append to backup.sh:
rclone copy "$BACKUP_DIR" b2vault:your-bucket-name/vaultwarden --max-age 24h
B2's first 10 GB of storage is free — you'll never hit that with password vault backups.
Alternatively, if you'd rather keep everything on your own infrastructure, a small VPS on Hetzner Cloud running an rsync target works well for a few euros per month.
Step 6: Hardening Checklist
- Disable signups after creating your account(s).
- Fail2Ban: Vaultwarden logs failed attempts to
/data/vaultwarden.log. A Fail2Ban jail on the Pi watching that log blocks brute-force attempts. - Firewall: Only ports 80 and 443 need to be exposed. Use
ufwornftables. - Updates: Pin a Vaultwarden image tag in production, but check for releases monthly.
docker compose pull && docker compose up -dis the entire upgrade. - Separate VLAN: If your router supports it, isolate the Pi on its own VLAN with only HTTPS egress.
Performance Reality Check
On my Pi 5, the Vaultwarden container uses roughly 25–40 MB of RAM and near-zero CPU at rest. Logins and vault syncs from the Bitwarden app are effectively instant — the 16K random-read IOPS from the NVMe are never the bottleneck; the SQLite database is tiny. With 15 Gi of RAM, you can comfortably run Vaultwarden alongside other services (reverse proxy, monitoring, Home Assistant, etc.) without contention.
Thermals are a non-issue. My SoC sits under 50 °C even under synthetic load. If you're running a fanless passive case, your numbers will be higher — reportedly 65–70 °C under load based on community reports — but still within the Pi 5's thermal throttle threshold of 85 °C. If dust buildup becomes a concern with active cooling, JAKEHOE Fan Cleaner – Dust Removal Tool for Server & NAS Fans is handy for periodic maintenance.
Who Should NOT Do This
- If you don't have a static IP or reliable DDNS, your vault will become unreachable when your IP changes. Consider a VPS on DigitalOcean or Vultr instead — Vaultwarden runs fine on their smallest instances.
- If you can't commit to maintaining backups and updates, a hosted Bitwarden subscription is $10/year and someone else handles uptime.
- If your household can't tolerate downtime during power outages or SD card failures — though NVMe boot (as in