Vaultwarden on a VPS: Self-Hosted Bitwarden-Compatible Password Manager for Teams

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

  1. Visit https://vault.yourdomain.com/admin
  2. Enter the ADMIN_TOKEN from your .env file
  3. 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

  1. Create an account at https://vault.yourdomain.com
  2. Vaultwarden Web UI → Organizations → New Organization
  3. Name: “Acme Team”, billing: none (self-hosted bypasses billing)
  4. Members → Invite by email → assign roles (Owner, Admin, Manager, User, Custom)
  5. Collections → create password groups: “Engineering”, “Finance”, “Shared Credentials”
  6. 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.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!