Last updated: March 21, 2026

Vaultwarden is a free, open-source password manager compatible with Bitwarden clients. Unlike cloud-hosted password managers, you control the server, no company between you and your encrypted vault. This guide covers complete setup: Docker deployment, reverse proxy configuration, automated backups, HTTPS, and admin panel hardening.

Table of Contents

Why Self-Host Vaultwarden?

Advantages:

Tradeoffs:

Best for - Developers, privacy-conscious individuals, teams wanting complete control. Not for non-technical users.

Prerequisites

Estimated cost - $5/month hosting + $10/year domain = $70/year total

Step 1 - Set Up VPS and SSH

Using DigitalOcean as example (Ubuntu 24.04):

SSH into VPS
ssh root@your.vps.ip

Update system
apt update && apt upgrade -y

Install Docker and Docker Compose
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

Verify Docker installed
docker --version

Step 2 - Create Vaultwarden Docker Compose

Create /root/vaultwarden/docker-compose.yml:

version: '3'
services:
  vaultwarden:
    image: vaultwarden/server:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      DOMAIN: "https://vault.yourdomain.com"
      SIGNUPS_ALLOWED: "false"
      INVITATIONS_ORG_ALLOW_USER: "false"
      SEND_FOLDER: "true"
      EXTENDED_LOGGING: "true"
      LOG_FILE: "/data/vaultwarden.log"
      # Admin panel access token (generate: openssl rand -base64 48)
      ADMIN_TOKEN: "your-secret-admin-token-here"
      # SMTP for email invitations (optional, see below)
      MAIL_ENABLED: "false"
    volumes:
      - ./data:/data
      - ./certs:/certs
    networks:
      - vaultwarden-network

  # Caddy reverse proxy with automatic HTTPS
  caddy:
    image: caddy:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      DOMAIN: "vault.yourdomain.com"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./data/caddy_data:/data
      - ./data/caddy_config:/config
    networks:
      - vaultwarden-network
    depends_on:
      - vaultwarden

networks:
  vaultwarden-network:
    driver: bridge

Step 3 - Configure Reverse Proxy (Caddy)

Create /root/vaultwarden/Caddyfile:

vault.yourdomain.com {
  encode gzip

  # Reverse proxy to Vaultwarden container
  reverse_proxy localhost:80 {
    # Forward real IP
    header_upstream X-Real-IP {http.request.remote.host}
    header_upstream X-Forwarded-For {http.request.remote.host}
    header_upstream X-Forwarded-Proto {http.request.scheme}
  }

  # Rate limiting (prevent brute force)
  rate_limit 10r/s

  # Security headers
  header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
  header X-Content-Type-Options "nosniff"
  header X-Frame-Options "DENY"
  header X-XSS-Protection "1; mode=block"
  header Referrer-Policy "no-referrer"
  header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; font-src 'self'"

  # TLS certificate auto-renewal
  tls internal
}

Step 4 - Launch Vaultwarden

cd /root/vaultwarden

Generate secure admin token
openssl rand -base64 48

Update docker-compose.yml with the token you just generated
Edit ADMIN_TOKEN in docker-compose.yml

Create data directory
mkdir -p data

Start containers
docker compose up -d

Verify running
docker compose ps
docker compose logs -f vaultwarden

Expected output:

vaultwarden | [INFO] Vaultwarden is ready
vaultwarden | Rocket has launched from http://0.0.0.0:80
caddy | caddy started successfully

Step 5 - Access Admin Panel

Open browser to https://vault.yourdomain.com/admin

You’ll see login prompt. Enter your admin token (from Step 3) into the “Master Password Hash” field.

Admin panel options:

Disable logins to admin panel after setup:

Edit docker-compose.yml
Add environment variable:
ADMIN_DISABLE_2FA: "true"
ADMIN_SESSION_LIFETIME - 5  # Session expires after 5 minutes

Restart:

docker compose restart vaultwarden

Step 6 - Add First User

Two options:

Option A: Admin panel (easiest)

  1. Go to vault.yourdomain.com/admin
  2. Click “Users”
  3. Click “New User”
  4. Enter email, set temporary password
  5. Share link with user

Option B - Manual command (if admin panel fails)

docker compose exec -it vaultwarden \
  /vaultwarden hash --preset owasp --input yourpassword

Step 7 - Enable SMTP for Email Invitations

Edit docker-compose.yml:

environment:
  MAIL_ENABLED: "true"
  MAIL_FROM: "vault@yourdomain.com"
  MAIL_FROM_NAME: "Vaultwarden"
  # Example: Gmail with app-specific password
  MAIL_SMTP_HOST: "smtp.gmail.com"
  MAIL_SMTP_SECURITY: "force_tls"
  MAIL_SMTP_PORT: "587"
  MAIL_SMTP_AUTH: "Login"
  MAIL_SMTP_USERNAME: "your-email@gmail.com"
  MAIL_SMTP_PASSWORD: "app-specific-password"

For Gmail:

  1. Enable 2-factor authentication on your Google Account
  2. Generate app password: https://myaccount.google.com/apppasswords
  3. Use app password above (not your regular password)

Restart:

docker compose restart vaultwarden

Step 8 - Automated Backups

Create backup script /root/vaultwarden/backup.sh:

#!/bin/bash

BACKUP_DIR="/root/vaultwarden/backups"
DB_PATH="/root/vaultwarden/data/db.sqlite3"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

Create backup directory
mkdir -p $BACKUP_DIR

Backup database
cp $DB_PATH $BACKUP_DIR/db_$TIMESTAMP.sqlite3

Backup attachments and sends
tar -czf $BACKUP_DIR/vaultwarden_$TIMESTAMP.tar.gz \
  /root/vaultwarden/data/attachments \
  /root/vaultwarden/data/sends \
  /root/vaultwarden/data/icon_cache

Delete backups older than 30 days
find $BACKUP_DIR -mtime +30 -delete

Upload to remote storage (optional)
aws s3 cp $BACKUP_DIR/db_$TIMESTAMP.sqlite3 s3://your-bucket/backups/

Make executable and add to cron:

chmod +x /root/vaultwarden/backup.sh

Edit crontab
crontab -e

Add line (daily backup at 2am):
0 2 * * * /root/vaultwarden/backup.sh

Verify:

Run backup manually
/root/vaultwarden/backup.sh

Check results
ls -la /root/vaultwarden/backups/

Step 9 - Enable Two-Factor Authentication (2FA)

In admin panel:

  1. Settings → Authentication
  2. Set TWOFACTOR options:
    • TWOFACTOR_EMAIL: Allow email-based 2FA
    • TWOFACTOR_AUTHENTICATOR: Allow authenticator app (Google Authenticator, Authy)
environment:
  TWOFACTOR: "true"
  TWOFACTOR_EMAIL: "true"
  TWOFACTOR_AUTHENTICATOR: "true"
  TWOFACTOR_REMEMBER: "true"
  TWOFACTOR_REMEMBER_EXPIRES_IN: 30

Step 10 - Configure Organization (Optional)

If you want to share passwords with family/team:

  1. Log in to web vault: vault.yourdomain.com
  2. Click “New Organization”
  3. Name it (“Family Passwords” or “Work Team”)
  4. Add users via admin panel or send invitations
  5. Create collections (folders) and assign to users

Example org structure:

Organization - MyFamily
 Collection: Banking (shared with spouse)
 Collection: Streaming (shared with all)
 Collection: Personal (only me)

Client Setup

Desktop (Windows, Mac, Linux):

  1. Download Bitwarden client (works with Vaultwarden)
  2. Login with your email
  3. Settings → Server URL → https://vault.yourdomain.com
  4. Restart client, re-authenticate

Mobile (iOS, Android):

  1. Download Bitwarden app
  2. Settings → Server URL → https://vault.yourdomain.com
  3. Login with email
  4. Pin app to home screen

Browser Extension:

  1. Install Bitwarden extension (Chrome, Firefox, Safari, Edge)
  2. Click icon → Settings → Server URL → https://vault.yourdomain.com
  3. Login once
  4. Auto-fill works normally

Monitoring and Maintenance

Weekly:

Monthly:

Quarterly:

Troubleshooting

Connection refused when accessing admin panel:

Check if containers running
docker compose ps

Check logs
docker compose logs caddy
docker compose logs vaultwarden

Restart all
docker compose restart

Email not sending:

Test SMTP connection
docker compose exec -it vaultwarden \
  /vaultwarden test-mail your-email@gmail.com

Database locked error:

Stop containers, wait 10 seconds, restart
docker compose down
sleep 10
docker compose up -d

Forgotten admin password: You can’t reset it directly. Instead:

  1. Stop Vaultwarden
  2. Replace database with backup
  3. Restart

This is why backups are critical.

Security Hardening Checklist

Cost Breakdown

Annual cost:

vs. Bitwarden Premium:

but you pay in time:

Alternatives

Bitwarden Cloud ($10/month):

1Password ($36-99/year):

KeePass (free, local):

Frequently Asked Questions

How long does it take to set up self-hosted password manager vaultwarden?

For a straightforward setup, expect 30 minutes to 2 hours depending on your familiarity with the tools involved. Complex configurations with custom requirements may take longer. Having your credentials and environment ready before starting saves significant time.

What are the most common mistakes to avoid?

The most frequent issues are skipping prerequisite steps, using outdated package versions, and not reading error messages carefully. Follow the steps in order, verify each one works before moving on, and check the official documentation if something behaves unexpectedly.

Do I need prior experience to follow this guide?

Basic familiarity with the relevant tools and command line is helpful but not strictly required. Each step is explained with context. If you get stuck, the official documentation for each tool covers fundamentals that may fill in knowledge gaps.

Is this approach secure enough for production?

The patterns shown here follow standard practices, but production deployments need additional hardening. Add rate limiting, input validation, proper secret management, and monitoring before going live. Consider a security review if your application handles sensitive user data.

Where can I get help if I run into issues?

Start with the official documentation for each tool mentioned. Stack Overflow and GitHub Issues are good next steps for specific error messages. Community forums and Discord servers for the relevant tools often have active members who can help with setup problems.

Related Articles