Introduction
Bitwarden cloud is fine. But paying €10/month for family use or having your secrets on a third-party server may not appeal to you. Vaultwarden is the self-hosted alternative:
- 100% Bitwarden API compatible
- Runs on ~50 MB RAM
- All official Bitwarden clients work (web, iOS/Android, browser extensions, CLI)
- Free premium features: built-in TOTP, sharing, attachments
- Family / team (organizations) without limit
A €5/month VPS handles 50 users.
Prerequisites
- Linux VPS (Debian/Ubuntu recommended) with Docker installed
- Domain pointing to the VPS (e.g.
vault.your-domain.com) - Reverse proxy (Nginx, Caddy or Traefik) with HTTPS
Step 1: Prepare the server
sudo mkdir -p /opt/vaultwarden/data
cd /opt/vaultwarden
Step 2: docker-compose.yml
sudo nano docker-compose.yml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: "https://vault.your-domain.com"
SIGNUPS_ALLOWED: "true"
INVITATIONS_ALLOWED: "true"
ADMIN_TOKEN: "YOUR_GENERATED_ADMIN_TOKEN"
WEBSOCKET_ENABLED: "true"
LOG_FILE: "/data/vaultwarden.log"
LOG_LEVEL: "warn"
SMTP_HOST: "smtp.example.com"
SMTP_FROM: "[email protected]"
SMTP_PORT: 587
SMTP_SECURITY: "starttls"
SMTP_USERNAME: "your_smtp_user"
SMTP_PASSWORD: "your_smtp_password"
volumes:
- ./data:/data
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:3012:3012"
Generate an admin token:
openssl rand -base64 48
Paste into ADMIN_TOKEN.
⚠️ Once your accounts are created, set SIGNUPS_ALLOWED: "false".
Step 3: Start
sudo docker compose up -d
sudo docker compose logs -f
You must see:
Rocket has launched from http://0.0.0.0:80
Step 4: Reverse proxy Nginx + Let's Encrypt
sudo nano /etc/nginx/sites-available/vaultwarden
server {
listen 80;
listen [::]:80;
server_name vault.your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name vault.your-domain.com;
ssl_certificate /etc/letsencrypt/live/vault.your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vault.your-domain.com/privkey.pem;
client_max_body_size 128M;
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;
}
location /notifications/hub {
proxy_pass http://127.0.0.1:3012;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /notifications/hub/negotiate {
proxy_pass http://127.0.0.1:8080;
}
}
sudo ln -s /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/
sudo certbot --nginx -d vault.your-domain.com
sudo nginx -t && sudo systemctl reload nginx
Step 5: Create your account
Open https://vault.your-domain.com → Create account. Choose a strong master password you'll never forget.
Step 6: Install clients
- Browser extension: Chrome / Firefox / Edge → Bitwarden → Settings → Server URL:
https://vault.your-domain.com - Mobile iOS / Android: Bitwarden app → Settings → Server URL
- Desktop: Settings → Server URL
- CLI:
bw config server https://vault.your-domain.com
Step 7: Enable 2FA TOTP
- Web UI → Account Settings → Two-step Login
- Click Authenticator app
- Scan QR with Google Authenticator / Authy / Aegis
- Save recovery codes
Step 8: Disable signups
SIGNUPS_ALLOWED: "false"
sudo docker compose up -d
Step 9: Admin page
Open https://vault.your-domain.com/admin → enter ADMIN_TOKEN. You can:
- List / delete users
- Invite via email
- See organizations
- View logs
Step 10: Daily backups
sudo nano /usr/local/bin/backup-vaultwarden.sh
#!/bin/bash
DATE=$(date +%Y-%m-%d)
DEST=/backup/vaultwarden
mkdir -p "$DEST"
docker compose -f /opt/vaultwarden/docker-compose.yml stop
tar czf "$DEST/vaultwarden-$DATE.tar.gz" -C /opt/vaultwarden data/
docker compose -f /opt/vaultwarden/docker-compose.yml start
find "$DEST" -name "vaultwarden-*.tar.gz" -mtime +30 -delete
sudo chmod +x /usr/local/bin/backup-vaultwarden.sh
echo "0 3 * * * /usr/local/bin/backup-vaultwarden.sh" | sudo crontab -
Step 11: Migrate to PostgreSQL (large deployments)
environment:
DATABASE_URL: "postgresql://vault:password@db:5432/vaultwarden"
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: vault
POSTGRES_PASSWORD: password
POSTGRES_DB: vaultwarden
volumes:
- ./pgdata:/var/lib/postgresql/data
Step 12: Domain whitelist
SIGNUPS_DOMAINS_WHITELIST: "your-domain.com"
Step 13: Performance
- 100 users: 1 vCPU / 1 GB RAM VPS
- 1000 users: 2 vCPU / 2 GB RAM + PostgreSQL
- Sync: ~10 KB (light)
Troubleshooting
"Trouble connecting to your server"
curl -I https://vault.your-domain.com
Check SSL cert valid.
Push notifications broken
WebSockets broken. Check Nginx config for /notifications/hub.
Admin page 401
Check ADMIN_TOKEN then restart container.
Invitation email not sent
docker compose logs vaultwarden | grep -i smtp
Test: admin page → Send test email.
Useful commands
docker compose ps
docker compose logs -f vaultwarden
docker compose exec vaultwarden sqlite3 /data/db.sqlite3 "SELECT email FROM users;"
sudo du -sh /opt/vaultwarden/data/
docker compose exec vaultwarden sqlite3 /data/db.sqlite3 ".backup /data/backup.db"
docker compose pull && docker compose up -d
Conclusion
Vaultwarden gives you:
- Full Bitwarden without subscription
- 100% control over your data
- Free premium features (TOTP, sharing, files)
Going further:
- Enable OIDC SSO for teams
- Set up uptime monitoring
- Combine with HashiCorp Vault for infra secrets
Resources
- Vaultwarden Wiki: https://github.com/dani-garcia/vaultwarden/wiki
- Docker image: https://hub.docker.com/r/vaultwarden/server
- Bitwarden docs: https://bitwarden.com/help/
- Bitwarden clients: https://bitwarden.com/download/


















