Vaultwarden: Self-Hosted Bitwarden Password Manager Complete Setup Guide
π― Key Takeaways
- Table of Contents
- Why Self-Host Your Password Manager
- Vaultwarden vs Official Bitwarden Server
- Prerequisites
- Deploying Vaultwarden with Docker Compose
π Table of Contents
- Table of Contents
- Why Self-Host Your Password Manager
- Vaultwarden vs Official Bitwarden Server
- Prerequisites
- Deploying Vaultwarden with Docker Compose
- Nginx Reverse Proxy with TLS
- Initial Setup: Admin Panel and First User
- Connecting Bitwarden Clients
- Configuring Email (SMTP) for Invitations and Alerts
- Enabling Two-Factor Authentication
- Organizations and Shared Collections for Teams
- Backup and Restore Strategy
- Security Hardening
- Upgrading Vaultwarden
- Conclusion
Vaultwarden is a lightweight, open-source reimplementation of the Bitwarden server, written in Rust and designed to run on minimal hardware. Where the official Bitwarden server requires multiple Docker containers and several gigabytes of RAM, Vaultwarden runs in a single container using under 10 MB of memory at idle. Every official Bitwarden client β browser extensions, desktop apps, iOS, and Android β connects to Vaultwarden exactly as it does to Bitwarden’s hosted service. This guide covers deploying Vaultwarden on Linux, configuring it for production use, connecting clients, enabling two-factor authentication, and hardening it for team use.
π Table of Contents
- Table of Contents
- Why Self-Host Your Password Manager
- Vaultwarden vs Official Bitwarden Server
- Prerequisites
- Deploying Vaultwarden with Docker Compose
- Using PostgreSQL for Larger Deployments
- Nginx Reverse Proxy with TLS
- Initial Setup: Admin Panel and First User
- Connecting Bitwarden Clients
- Configuring Email (SMTP) for Invitations and Alerts
- Enabling Two-Factor Authentication
- Organizations and Shared Collections for Teams
- Backup and Restore Strategy
- Security Hardening
- Upgrading Vaultwarden
- Conclusion
Table of Contents
- Why Self-Host Your Password Manager
- Vaultwarden vs Official Bitwarden Server
- Prerequisites
- Deploying Vaultwarden with Docker Compose
- Nginx Reverse Proxy with TLS
- Initial Setup: Admin Panel and First User
- Connecting Bitwarden Clients
- Configuring Email (SMTP) for Invitations and Alerts
- Enabling Two-Factor Authentication
- Organizations and Shared Collections for Teams
- Backup and Restore Strategy
- Security Hardening
- Upgrading Vaultwarden
Why Self-Host Your Password Manager
Password managers are among the most security-sensitive applications in an organization. Self-hosting Vaultwarden keeps your encrypted vault on infrastructure you control, with no third-party service involved in storing or transmitting your credentials. Practical reasons to self-host:
- Data sovereignty: Your encrypted vault never touches an external server. Even in the event of a third-party breach, your passwords stay on your infrastructure.
- Cost: Bitwarden’s hosted Teams plan costs $4/user/month. Vaultwarden runs on a $5 VPS with unlimited users at no per-seat cost.
- Offline access: Vaultwarden works on an internal LAN with no internet access required β useful for air-gapped or restricted environments.
- All Bitwarden features included: Organizations, shared collections, emergency access, and TOTP β all enabled by default in Vaultwarden.
Vaultwarden vs Official Bitwarden Server
| Feature | Vaultwarden | Official Bitwarden Server |
|---|---|---|
| RAM at idle | <10 MB | ~2 GB (multiple services) |
| Language | Rust (single binary) | .NET + multiple containers |
| Database | SQLite (default) or PostgreSQL/MySQL | MSSQL |
| Client compatibility | All official Bitwarden clients | All official Bitwarden clients |
| Organizations/sharing | Yes (all tiers) | Yes (requires paid plan for teams) |
| TOTP authenticator | Yes | Requires paid plan |
| SSO (SAML/OIDC) | Not supported | Enterprise plan only |
| Official support | Community | Bitwarden Inc. |
The primary limitation is SSO support β if your organization requires SAML or OIDC integration with Keycloak or Okta, the official Bitwarden server is the better choice. For all other use cases, Vaultwarden is a drop-in replacement.
Prerequisites
- A Linux server with Docker and Docker Compose installed
- A domain name pointing to the server (e.g.,
vault.example.com) - Port 443 open in your firewall
- An SMTP server or relay for email notifications (optional but recommended)
Deploying Vaultwarden with Docker Compose
mkdir -p /opt/vaultwarden && cd /opt/vaultwarden
cat > docker-compose.yml << 'COMPOSE'
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: https://vault.example.com
SIGNUPS_ALLOWED: "false" # Disable open registration after first user
INVITATIONS_ALLOWED: "true" # Allow admin to invite users
ADMIN_TOKEN: "" # Set securely β see hardening section
WEBSOCKET_ENABLED: "true"
SENDS_ALLOWED: "true"
EMERGENCY_ACCESS_ALLOWED: "true"
# Database (SQLite is fine for up to ~100 users)
DATABASE_URL: /data/vaultwarden.db
# Email β fill in with your SMTP details
SMTP_HOST: smtp.example.com
SMTP_PORT: "587"
SMTP_SECURITY: starttls
SMTP_USERNAME: vault@example.com
SMTP_PASSWORD: smtp_password_here
SMTP_FROM: vault@example.com
SMTP_FROM_NAME: Vaultwarden
LOG_LEVEL: warn
LOG_FILE: /data/vaultwarden.log
volumes:
- ./data:/data
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:3012:3012" # WebSocket notifications
COMPOSE
docker compose up -d
docker compose logs -f vaultwarden
The data directory (./data) contains the SQLite database and all vault data. Back this up regularly β it is the single most important file on the server.
Using PostgreSQL for Larger Deployments
cat >> docker-compose.yml << 'COMPOSE'
vaultwarden-db:
image: postgres:16-alpine
container_name: vaultwarden-db
restart: unless-stopped
environment:
POSTGRES_DB: vaultwarden
POSTGRES_USER: vaultwarden
POSTGRES_PASSWORD: changeme_strong_password
volumes:
- ./postgres:/var/lib/postgresql/data
COMPOSE
# Update DATABASE_URL in the vaultwarden service:
# DATABASE_URL: postgresql://vaultwarden:changeme_strong_password@vaultwarden-db/vaultwarden
Nginx Reverse Proxy with TLS
certbot certonly --standalone -d vault.example.com \
--email admin@example.com --agree-tos -n
cat > /etc/nginx/sites-available/vaultwarden << 'NGINX'
server {
listen 80;
server_name vault.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name vault.example.com;
ssl_certificate /etc/letsencrypt/live/vault.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vault.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
client_max_body_size 128m; # Allow large file attachments
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket for real-time vault notifications
location /notifications/hub {
proxy_pass http://127.0.0.1:3012;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /notifications/hub/negotiate {
proxy_pass http://127.0.0.1:8080;
}
}
NGINX
ln -s /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Initial Setup: Admin Panel and First User
# Generate a secure admin token
openssl rand -base64 48
# Copy this value and set it as ADMIN_TOKEN in docker-compose.yml
# Then recreate the container:
docker compose up -d
# Access the admin panel at: https://vault.example.com/admin
# Login with the ADMIN_TOKEN value
# The admin panel lets you:
# - Create and manage user accounts
# - Send invitations
# - View diagnostics and server info
# - Enable/disable features
# - Force 2FA for all users
Create the first admin user via the admin panel or by temporarily enabling SIGNUPS_ALLOWED: "true", registering, then disabling signups again. The admin panel user management page is the preferred approach for team deployments.
Connecting Bitwarden Clients
# All official Bitwarden clients support custom server URLs
# Browser extension (Chrome, Firefox, Edge, Safari):
# Click the extension β Settings icon β Self-hosted server
# Server URL: https://vault.example.com
# (Leave API and Identity URL blank β Vaultwarden auto-detects them)
# Desktop app (Windows, macOS, Linux):
# Open Bitwarden β Settings β Server URL β https://vault.example.com
# Mobile (iOS and Android):
# Tap the region selector on the login screen
# β Self-hosted β https://vault.example.com
# CLI (bitwarden-cli):
bw config server https://vault.example.com
bw login
bw sync
Configuring Email (SMTP) for Invitations and Alerts
# Email is required for:
# - User registration invitations
# - Email verification (if enabled)
# - Emergency access requests
# - 2FA login codes (if using email 2FA)
# Test email configuration from the admin panel:
# https://vault.example.com/admin/diagnostics β Send test email
# Common SMTP configurations:
# Gmail/Google Workspace:
# SMTP_HOST: smtp.gmail.com
# SMTP_PORT: 587
# SMTP_SECURITY: starttls
# SMTP_USERNAME: your@gmail.com
# SMTP_PASSWORD: app-specific-password (generate at myaccount.google.com)
# Mailgun:
# SMTP_HOST: smtp.mailgun.org
# SMTP_PORT: 587
# SMTP_USERNAME: postmaster@mg.example.com
# SMTP_PASSWORD: mailgun-smtp-password
Enabling Two-Factor Authentication
# Users enable 2FA per-account in Bitwarden's web vault:
# https://vault.example.com β Account Settings β Security β Two-step Login
# Supported 2FA methods in Vaultwarden:
# - Authenticator app (TOTP β Google Authenticator, Aegis, etc.)
# - Email code
# - Duo Security
# - YubiKey OTP
# - FIDO2/WebAuthn hardware keys
# Force 2FA for all users (admin panel):
# Admin Panel β Users β select user β "Deauthorize Sessions"
# Then set policy via: Admin Panel β Settings β Require 2FA = On
# Users who haven't set up 2FA will be blocked from logging in
# until they configure it
Organizations and Shared Collections for Teams
# Organizations allow teams to share passwords securely
# Create an organization: Web Vault β New Organization
# Collection structure example:
# Organization: "ACME Corp"
# βββ Collection: Infrastructure Passwords
# β βββ Server root credentials
# β βββ Database passwords
# βββ Collection: Web Services
# β βββ AWS IAM keys
# β βββ GitHub tokens
# βββ Collection: HR Department (restricted)
# βββ Payroll system credentials
# Invite users to the organization via email
# Assign roles: Owner, Admin, Manager, User, Custom
# Members see only collections they're granted access to
# Even Vaultwarden admins cannot read encrypted vault contents
Backup and Restore Strategy
# SQLite database backup (single file β the entire vault)
# Stop Vaultwarden before backup for consistency
docker compose stop vaultwarden
cp /opt/vaultwarden/data/vaultwarden.db /backups/vaultwarden-$(date +%Y%m%d).db
docker compose start vaultwarden
# Online backup using SQLite's backup API (no downtime)
sqlite3 /opt/vaultwarden/data/vaultwarden.db ".backup '/backups/vaultwarden-$(date +%Y%m%d).db'"
# Automate with a systemd timer or cron
cat > /etc/cron.d/vaultwarden-backup << 'CRON'
0 2 * * * root sqlite3 /opt/vaultwarden/data/vaultwarden.db ".backup '/backups/vaultwarden-$(date +\%Y\%m\%d).db'" && find /backups -name "vaultwarden-*.db" -mtime +30 -delete
CRON
# Restore
docker compose stop vaultwarden
cp /backups/vaultwarden-20260430.db /opt/vaultwarden/data/vaultwarden.db
docker compose start vaultwarden
Security Hardening
# 1. Use a hashed admin token (prevents token exposure in process list)
# Generate a PHC string:
echo -n "your-admin-password" | argon2 --iterations 3 --memory 65536 --parallelism 4 -id -e
# Set ADMIN_TOKEN to the $argon2id$... output
# 2. Disable user signups permanently
SIGNUPS_ALLOWED: "false"
# 3. Restrict to specific email domains only
SIGNUPS_DOMAINS_WHITELIST: "example.com"
# 4. Disable the admin panel entirely when not in use
# Comment out ADMIN_TOKEN β panel becomes inaccessible
# 5. Set login attempt limits
LOGIN_RATELIMIT_MAX_BURST: "10"
LOGIN_RATELIMIT_SECONDS: "60"
# 6. Restrict Vaultwarden to internal network only
# In docker-compose.yml, bind only to internal interface:
# ports:
# - "10.0.0.1:8080:80"
# 7. Enable HSTS in nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Upgrading Vaultwarden
# Always backup the database before upgrading
sqlite3 /opt/vaultwarden/data/vaultwarden.db ".backup '/backups/pre-upgrade-$(date +%Y%m%d).db'"
# Pull the latest image and recreate the container
cd /opt/vaultwarden
docker compose pull
docker compose up -d
# Verify the new version
docker compose logs vaultwarden | head -20
curl -s https://vault.example.com/api/config | jq .version
# Vaultwarden automatically runs database migrations on startup
# No manual schema updates required
Conclusion
Vaultwarden gives individuals and teams a fully-featured, self-hosted password manager that is indistinguishable from Bitwarden's commercial service from the perspective of every client application. The combination of extremely low resource requirements, SQLite simplicity for small teams, and complete compatibility with the mature Bitwarden client ecosystem makes Vaultwarden the best password management option for anyone running their own infrastructure. Configure SMTP early so invitations and 2FA codes work from day one, enable mandatory 2FA for all organization members, and set up an automated nightly database backup β those three steps cover the vast majority of operational concerns. Your passwords stay encrypted on your hardware, your team gets the same polished Bitwarden experience across all their devices, and you pay nothing per seat.
Was this article helpful?
About Ramesh Sundararamaiah
Red Hat Certified Architect
Expert in Linux system administration, DevOps automation, and cloud infrastructure. Specializing in Red Hat Enterprise Linux, CentOS, Ubuntu, Docker, Ansible, and enterprise IT solutions.