Self-Hosting Guide: Deploy Bitwarden (Vaultwarden) 2026
Bitwarden is the most popular open source password manager. Self-hosting with Vaultwarden (a lightweight, community-maintained Bitwarden-compatible server) gives you all premium features for free — TOTP, file attachments, organizations, and Bitwarden Send — using a fraction of the resources.
Why Vaultwarden?
| Feature | Official Bitwarden Server | Vaultwarden |
|---|---|---|
| RAM | 2+ GB (C#/.NET) | 50-100 MB (Rust) |
| Containers | 10+ services | 1 container |
| Premium features | Paid ($10/year) | Free |
| Organizations | Paid ($4/user/month) | Free |
| Compatibility | Full API | Full API |
| License | AGPL | GPL-3.0 |
Requirements
- VPS with 512 MB RAM minimum
- Docker
- Domain name (e.g.,
vault.yourdomain.com) - HTTPS required (Bitwarden clients refuse HTTP)
- 5+ GB disk
Step 1: Deploy with Docker
docker run -d \
--name vaultwarden \
--restart unless-stopped \
-p 8080:80 \
-v vw-data:/data \
-e DOMAIN=https://vault.yourdomain.com \
-e SIGNUPS_ALLOWED=true \
-e ADMIN_TOKEN=your-long-random-admin-token \
vaultwarden/server:latest
Generate admin token:
openssl rand -hex 32
Step 2: Reverse Proxy (Caddy) — HTTPS Required
# /etc/caddy/Caddyfile
vault.yourdomain.com {
reverse_proxy localhost:8080
}
sudo systemctl restart caddy
HTTPS is mandatory. Bitwarden clients will not connect over HTTP.
Step 3: DNS
Add an A record: vault.yourdomain.com → your server IP
Step 4: Create Your Account
- Open
https://vault.yourdomain.com - Click Create Account
- Set a strong master password (this is the only password you need to remember)
Important: After creating your account, disable sign-ups:
docker stop vaultwarden
docker rm vaultwarden
docker run -d \
--name vaultwarden \
--restart unless-stopped \
-p 8080:80 \
-v vw-data:/data \
-e DOMAIN=https://vault.yourdomain.com \
-e SIGNUPS_ALLOWED=false \
-e ADMIN_TOKEN=your-long-random-admin-token \
vaultwarden/server:latest
Or use the admin panel to invite specific users.
Step 5: Install Clients
All official Bitwarden clients work with Vaultwarden:
| Platform | Client | Custom Server URL |
|---|---|---|
| Browser | Bitwarden extension (Chrome, Firefox, Safari) | Settings → Self-hosted → https://vault.yourdomain.com |
| Desktop | Bitwarden Desktop (Mac, Windows, Linux) | Login → Self-hosted → https://vault.yourdomain.com |
| iOS | Bitwarden iOS app | Login → Self-hosted → https://vault.yourdomain.com |
| Android | Bitwarden Android app | Login → Self-hosted → https://vault.yourdomain.com |
| CLI | bw config server https://vault.yourdomain.com | CLI flag |
Step 6: Configure SMTP (For Invitations)
docker run -d \
--name vaultwarden \
--restart unless-stopped \
-p 8080:80 \
-v vw-data:/data \
-e DOMAIN=https://vault.yourdomain.com \
-e SIGNUPS_ALLOWED=false \
-e ADMIN_TOKEN=your-admin-token \
-e SMTP_HOST=smtp.resend.com \
-e SMTP_PORT=587 \
-e SMTP_SECURITY=starttls \
-e SMTP_USERNAME=resend \
-e SMTP_PASSWORD=re_your_api_key \
-e SMTP_FROM=vault@yourdomain.com \
vaultwarden/server:latest
Step 7: Admin Panel
Access at https://vault.yourdomain.com/admin
Admin capabilities:
- Invite users (bypasses sign-up restriction)
- View all users and their status
- Delete users
- View organization details
- Configure server settings
- Check diagnostics
Step 8: Set Up Organizations (Team Sharing)
- Login to web vault
- Settings → Organizations → New Organization
- Invite team members
- Create Collections (shared folders):
- Engineering passwords
- Infrastructure secrets
- Marketing accounts
- Shared company logins
Permissions:
- Owner → full control
- Admin → manage collections and members
- User → access assigned collections
- Custom → granular permissions per collection
Step 9: Enable 2FA
In your vault → Settings → Two-step Login:
| Method | Setup |
|---|---|
| Authenticator app | Scan QR with Google Authenticator, Authy, etc. |
| Receive code via email | |
| YubiKey | Hardware key (premium feature — free in Vaultwarden) |
| WebAuthn/FIDO2 | Fingerprint, Face ID, security key |
Always set up 2FA. Your master password protects all other passwords.
Step 10: Import Existing Passwords
-
Export from your current password manager:
- 1Password →
.1puxor CSV - LastPass → CSV
- Chrome → CSV (
chrome://settings/passwords→ Export) - KeePass →
.kdbxor CSV
- 1Password →
-
In Bitwarden web vault → Tools → Import data
-
Select format and upload
-
Verify imported entries
Production Hardening
Docker Compose (recommended):
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
ports:
- "8080:80"
volumes:
- vw-data:/data
environment:
- DOMAIN=https://vault.yourdomain.com
- SIGNUPS_ALLOWED=false
- ADMIN_TOKEN=your-admin-token
- SMTP_HOST=smtp.resend.com
- SMTP_PORT=587
- SMTP_SECURITY=starttls
- SMTP_USERNAME=resend
- SMTP_PASSWORD=re_your_api_key
- SMTP_FROM=vault@yourdomain.com
- LOG_LEVEL=warn
- WEBSOCKET_ENABLED=true
volumes:
vw-data:
Backups (CRITICAL — this is your password vault):
# Daily backup of the data directory
docker run --rm -v vw-data:/data -v /backups:/backup alpine \
tar czf /backup/vaultwarden-$(date +%Y%m%d).tar.gz /data
# Copy backup off-server (S3, another VPS, or local)
rclone copy /backups/vaultwarden-$(date +%Y%m%d).tar.gz remote:backups/
Set up multiple backup locations. If you lose this data, you lose all passwords.
Updates:
docker pull vaultwarden/server:latest
docker stop vaultwarden
docker rm vaultwarden
# Re-run docker run command (data persists in volume)
Security:
- Strong admin token (64+ characters)
- Disable sign-ups after creating accounts
- Enable 2FA for all users
- Regular backups to off-site locations
- Monitor for unauthorized access in admin panel
- Keep Vaultwarden updated
Resource Usage
| Users | RAM | CPU | Disk |
|---|---|---|---|
| 1-10 | 50 MB | 1 core | 100 MB |
| 10-50 | 100 MB | 1 core | 500 MB |
| 50-200 | 256 MB | 1 core | 1 GB |
Vaultwarden is incredibly lightweight — it can easily share a VPS with other services.
VPS Recommendations
| Provider | Spec | Price |
|---|---|---|
| Hetzner | 2 vCPU, 2 GB RAM | €4.50/month |
| DigitalOcean | 1 vCPU, 1 GB RAM | $6/month |
| Linode | 1 vCPU, 1 GB RAM | $5/month |
vs Bitwarden Teams ($4/user/month): A 20-person team saves $960/year with self-hosted Vaultwarden.
Why Self-Host Bitwarden (Vaultwarden)
Bitwarden's commercial plans are actually reasonably priced compared to 1Password and LastPass. The individual Premium plan is $10/year — genuinely affordable. But team and enterprise costs add up: Bitwarden Teams is $4/user/month, meaning a 20-person company pays $960/year. A 50-person company pays $2,400/year. 1Password Teams runs $7.99/user/month — $4,794/year for 50 people. LastPass Teams is $4/user/month. Over three years with modest team growth, password manager costs for medium-sized companies routinely reach $10,000–20,000.
Self-hosted Vaultwarden provides every feature of Bitwarden's Premium and Teams plans — TOTP generation, organizations, collections, Bitwarden Send, emergency access, file attachments, and WebAuthn/FIDO2 — at zero license cost. The savings for a 20-person team are $960/year. For a 100-person company, the savings exceed $4,800/year against Bitwarden Teams or $9,500/year against 1Password. The operational cost (one developer spending a few hours per year on maintenance) is minimal by comparison.
Full data control for credentials: A password manager holds the keys to your entire digital infrastructure. Self-hosting means those credentials are encrypted and stored only on servers you control. No vendor breach can expose your vault data. No vendor business changes affect your access. This is the most compelling case for self-hosting any tool — credentials are uniquely sensitive.
All premium features for free: The comparison table above captures the key difference between Vaultwarden and the official Bitwarden server: Vaultwarden's maintainers have implemented all premium API endpoints, so features that cost money on the official server (TOTP, file attachments, organizations, YubiKey 2FA) are free. A solo developer who needs TOTP support but doesn't want to pay $10/year can self-host instead.
When NOT to self-host Bitwarden: Password vault availability is critical — if your vault server goes down, your team can't access credentials. A misconfigured or poorly maintained server is a security liability. If you or your team lacks the technical capacity to ensure uptime and keep the server updated, the risk of self-hosting outweighs the cost savings. Bitwarden's $10/year individual plan is genuinely good value for individuals who want managed hosting. For teams, do the math honestly: at small scale (under 10 people), the operational overhead may not justify the savings.
Prerequisites (Expanded)
512 MB RAM minimum: Vaultwarden is written in Rust and has an exceptionally small memory footprint — 50 MB at idle for a single-user instance. The 512 MB minimum is generous; in practice, Vaultwarden shares a server comfortably with other services. The key hardware requirement is not RAM but reliability — your password vault needs high uptime.
HTTPS required: This is non-negotiable. Every Bitwarden client (browser extension, desktop app, mobile app) refuses to connect to a server over plain HTTP. Caddy makes HTTPS automatic and free via Let's Encrypt. The configuration in this guide handles certificate provisioning automatically — you don't need to manually manage certificates.
Domain name: The domain you use for Vaultwarden becomes permanently baked into your vault's configuration. Changing domains later requires updating the server URL in every client. Choose a domain you control long-term — vault.yourdomain.com is a good pattern.
5+ GB disk: Vaultwarden stores vault data in an SQLite database and a small data directory. For most users, the database stays well under 50 MB even with thousands of vault items. The 5 GB minimum provides headroom for file attachments (if enabled) and long-term growth.
For server selection, Vaultwarden's low resource requirements mean you can run it on the cheapest tier at any major provider. See the VPS comparison for self-hosters for a comparison of entry-tier options — Hetzner's CX11 (€3.79/month) and DigitalOcean's $6/month Droplet both work well for Vaultwarden.
Production Security Hardening
Your password vault is the highest-value target in your infrastructure. Compromise here means compromise of everything. Apply every hardening step — no exceptions.
Firewall with UFW: Vaultwarden runs on port 8080 internally. Only expose ports 80, 443, and 22.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Fail2ban: Protect against brute-force login attempts on the vault.
sudo apt install fail2ban
Create /etc/fail2ban/filter.d/vaultwarden.conf:
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =
Add to /etc/fail2ban/jail.local:
[vaultwarden]
enabled = true
port = http,https
filter = vaultwarden
logpath = /path/to/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400
Never commit secrets to version control: Your ADMIN_TOKEN, SMTP credentials, and any other environment variables must stay out of Git. Use a .env file excluded from version control, or pass environment variables directly to docker run.
Use a 64-character admin token: The example uses openssl rand -hex 32 (generates 64 hex characters). Shorter tokens are less resistant to brute-force attacks on the admin endpoint. Use 64 characters minimum.
Disable sign-ups immediately after setup: With SIGNUPS_ALLOWED=true, anyone who finds your vault URL can create an account. Disable this the moment your accounts are created. You can still invite users via the admin panel.
Disable SSH password authentication:
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Enable automatic security updates:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Off-site backups — this is critical: The backup command in the Production Hardening section creates a local backup. Local backups alone are insufficient — disk failure or server deletion destroys them too. Set up automated off-site backups using automated server backups with restic. Store encrypted backup copies in at least two locations (e.g., Backblaze B2 + a second VPS). Test your restore procedure before you need it.
For the complete hardening checklist applicable to any self-hosted service, see the self-hosting security checklist.
Troubleshooting Common Issues
Bitwarden clients say "invalid server URL" or refuse to connect
Check that the URL in the client exactly matches DOMAIN in your Vaultwarden configuration — including the https:// prefix and no trailing slash. If you recently changed your domain, Vaultwarden may still have the old domain cached. Restart the container after any domain change. Also verify that your SSL certificate is valid:
curl -I https://vault.yourdomain.com
Admin panel is accessible from the internet
The admin panel at /admin should be restricted. Your admin token is the only thing protecting it. Consider adding IP-based restrictions in Caddy:
vault.yourdomain.com {
handle /admin* {
@not_my_ip not remote_ip YOUR_IP
respond @not_my_ip 403
reverse_proxy localhost:8080
}
handle {
reverse_proxy localhost:8080
}
}
2FA tokens are invalid ("Invalid TOTP code")
TOTP codes are time-based and require synchronized clocks. If your server's system clock is drifted, tokens generated by your phone will be rejected. Check server time:
timedatectl
If the time is wrong, synchronize NTP:
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
Organization invitations aren't being received
SMTP must be configured for email invitations. Without SMTP, Vaultwarden cannot send invitation emails. Check the admin panel's SMTP configuration under Settings and send a test email. Also check that the invited email address is valid and check spam folders — invitation emails from self-hosted servers sometimes land there initially.
Container data not persisting after restart
This indicates the Docker volume isn't mounted correctly. The -v vw-data:/data flag in the docker run command creates a named Docker volume. Verify with:
docker volume ls | grep vw-data
docker volume inspect vw-data
If you're using Docker Compose, ensure the volumes: section is correctly defined and that you're using docker compose down (not docker compose down -v) — the -v flag deletes volumes.
Browser extension stops working after Vaultwarden update
Vaultwarden occasionally changes its API in ways that require client updates. If the extension suddenly stops syncing after a Vaultwarden update, check that you're running the latest version of the Bitwarden browser extension and that your Vaultwarden version is compatible with the client. The Vaultwarden GitHub releases page lists known client compatibility requirements.
Compare password managers on OSSAlt — features, security, and pricing side by side.
See open source alternatives to Bitwarden on OSSAlt.