Vaultwarden on a VPS: Self-Hosted Bitwarden-Compatible Password Manager for Teams
Vaultwarden is an unofficial, lightweight Bitwarden-compatible server written in Rust. It implements the Bitwarden API so all official Bitwarden clients — browser extensions, desktop apps, and the mobile app — work identically against a self-hosted Vaultwarden instance. Bitwarden Teams costs $4/user/month. Vaultwarden on a VPS provides the full team feature set for any number of users at infrastructure cost only.
Vaultwarden vs Official Bitwarden Self-Host
- Vaultwarden: Single Rust binary, 10 MB RAM idle, supports all Bitwarden client features including Teams/Organizations, TOTP, and emergency access. Community-maintained.
- Official Bitwarden self-host: Docker stack of 7+ containers, 2+ GB RAM required, official support. For organizations with compliance requirements.
- Choose Vaultwarden: Teams up to 100 people, minimal resource footprint, easy to maintain. The Bitwarden clients never know the difference.
Step 1: Docker Compose Setup
<code">mkdir -p /opt/vaultwarden && cd /opt/vaultwarden nano docker-compose.yml
<code">version: '3.8'
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
ports:
- "127.0.0.1:8080:80"
environment:
DOMAIN: https://vault.yourdomain.com
SIGNUPS_ALLOWED: "false" # Disable open signups — invite only
INVITATIONS_ALLOWED: "true" # Allow admin to invite users
ADMIN_TOKEN: ${ADMIN_TOKEN} # Admin panel password
WEBSOCKET_ENABLED: "true" # Real-time sync between clients
PUSH_ENABLED: "false" # Mobile push (requires Bitwarden account)
LOG_LEVEL: warn
EXTENDED_LOGGING: "true"
# Database — SQLite (default) or PostgreSQL
DATABASE_URL: /data/db.sqlite3
# For PostgreSQL:
# DATABASE_URL: postgresql://vaultwarden:${POSTGRES_PASSWORD}@vaultwarden-db/vaultwarden
volumes:
- ./data:/data
volumes:
vaultwarden_data:
<code"># Generate a strong admin token echo "ADMIN_TOKEN=$(openssl rand -base64 48)" > .env chmod 600 .env mkdir -p data docker compose up -d docker compose logs -f vaultwarden
Step 2: Nginx with HTTPS (Required)
Bitwarden clients require HTTPS — the server will reject HTTP connections.
<code">sudo nano /etc/nginx/sites-available/vaultwarden
<code">server {
listen 80;
server_name vault.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name vault.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/vault.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vault.yourdomain.com/privkey.pem;
# Security headers for password manager
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy no-referrer always;
client_max_body_size 128M;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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 sync (requires WEBSOCKET_ENABLED=true)
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';
proxy_set_header Host $host;
}
}
<code">sudo ln -s /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx sudo certbot --nginx -d vault.yourdomain.com
Step 3: Admin Panel
- Visit
https://vault.yourdomain.com/admin - Enter the
ADMIN_TOKENfrom your.envfile - Key admin settings:
- Invitations: Send invite links to new users
- Users: View all accounts, delete accounts, deauthorize sessions
- Organizations: Create team vaults (shared passwords)
- Settings: SMTP for email notifications, 2FA policy enforcement
Step 4: Configure Email (Password Reset)
<code"># Add to docker-compose.yml environment: SMTP_HOST: smtp.mailgun.org SMTP_PORT: 587 SMTP_SSL: "false" SMTP_EXPLICIT_TLS: "false" SMTP_USERNAME: postmaster@mg.yourdomain.com SMTP_PASSWORD: your_mailgun_password SMTP_FROM: vault@yourdomain.com SMTP_FROM_NAME: "Vaultwarden" # Email enables: # - Password reset links # - Organization invite emails # - Two-step login verification (email OTP)
Step 5: Set Up Team Organization
- Create an account at
https://vault.yourdomain.com - Vaultwarden Web UI → Organizations → New Organization
- Name: “Acme Team”, billing: none (self-hosted bypasses billing)
- Members → Invite by email → assign roles (Owner, Admin, Manager, User, Custom)
- Collections → create password groups: “Engineering”, “Finance”, “Shared Credentials”
- Members can access assigned collections from all Bitwarden clients
Step 6: Configure Bitwarden Clients
<code"># Browser Extension (Chrome, Firefox, Safari): # Settings → Self-hosted Environment → Server URL: # https://vault.yourdomain.com # Desktop App (Windows, macOS, Linux): # Settings → Self-hosted Environment → Server URL: # https://vault.yourdomain.com # Mobile App (iOS, Android): # Settings → Self-hosted Environment → Server URL: # https://vault.yourdomain.com # All clients auto-sync via WebSocket (WEBSOCKET_ENABLED=true)
Step 7: Security Hardening
<code"># Add to docker-compose.yml environment: # Require 2FA for all users REQUIRE_DEVICE_EMAIL: "true" # Verify new device via email # Limit failed login attempts LOGIN_RATELIMIT_SECONDS: 60 LOGIN_RATELIMIT_MAX_BURST: 10 # Disable password hints (security risk) SHOW_PASSWORD_HINT: "false" # Session timeout SESSION_JWT_EXPIRATION: 120 # Minutes (2 hours) # Disable account creation after your team is set up: SIGNUPS_ALLOWED: "false" INVITATIONS_ALLOWED: "false" # Lock down completely
Backup Strategy
<code"># Vaultwarden data is in /opt/vaultwarden/data/db.sqlite3 # Daily backup with Restic: docker compose stop vaultwarden # Stop for consistent backup cp /opt/vaultwarden/data/db.sqlite3 /opt/backups/vaultwarden-$(date +%Y%m%d).sqlite3 docker compose start vaultwarden # Or use SQLite online backup (no downtime): docker exec vaultwarden sqlite3 /data/db.sqlite3 ".backup /data/backup.sqlite3" # Then copy /opt/vaultwarden/data/backup.sqlite3 to safe storage
Getting Started
Vaultwarden is the most resource-efficient service you can run on a VPS — 10 MB RAM idle, single binary, SQLite database for small teams. It runs comfortably alongside many other services on a 1 GB Ubuntu VPS at VPS.DO. For teams needing a password manager with organization features, Vaultwarden on a $5/month VPS replaces Bitwarden Teams at $4/user/month — a breakeven of just 2 users.
Conclusion
Vaultwarden provides the full Bitwarden experience — browser extensions, desktop and mobile apps, team organizations, shared collections, TOTP, emergency access — on a Rust binary using 10 MB RAM. All official Bitwarden clients work unchanged; users point them at your server URL instead of bitwarden.com. For small and medium teams, self-hosted Vaultwarden is the most cost-effective and privacy-preserving password management solution available.