Vaultwarden is an unofficial Bitwarden server implementation rewritten in Rust by the open-source community. This project is fully compatible with all official Bitwarden clients, such as browser extensions, desktop applications, Android, and iOS, so the end-user experience is identical to the official Bitwarden.
Architecturally, Vaultwarden runs as a single lightweight binary that includes the web vault interface, REST API, and WebSocket server in one Docker container. The default database used is SQLite. This makes it extremely easy to deploy and backup without external dependencies.
Why Choose Vaultwarden?
There are several strong reasons to run Vaultwarden on your own server instead of relying on third-party cloud services:
- Free premium features: Vaultwarden enables all Bitwarden Premium features for free, including TOTP Authenticator, Bitwarden Send, Emergency Access, File Attachments, and Organizations/Sharing, without any subscription fees.
- Resource efficient: Vaultwarden's RAM consumption is only around 10–30 MB when idle. This is far more efficient than the official Bitwarden Server, which requires a .NET + MSSQL stack with a minimum RAM requirement of 2 GB.
- Full privacy: All encrypted data is stored on your own server. No data is sent to Bitwarden, Inc. or any third party.
- Full control: You determine registration policies, data retention, and backup frequency according to your needs.
| Aspect | Vaultwarden | Bitwarden Official (Self-Hosted) |
|---|---|---|
| Language / Runtime | Rust (single binary) | .NET + ASP.NET Core |
| Default database | SQLite (optional PostgreSQL/MySQL) | Microsoft SQL Server |
| Minimum RAM requirement | ~256 MB (including OS) | ~2 GB (full stack) |
| Premium features | Free, all enabled | Requires paid license |
| Official status | Unofficial, community | Official from Bitwarden, Inc. |
| Deployment complexity | Single Docker container | Multi-container (10+ services) |
| Security audit | Available (see official wiki) | Available (internal + external) |
Preparation and System Requirements
Hardware Requirements
Vaultwarden is very lightweight and runs comfortably on various hardware. Below are minimum recommendations based on usage scale:
| Scenario | Hardware | Example devices |
|---|---|---|
| Personal / family (<10 users) | 1 vCPU, 512 MB RAM, 5 GB storage | Entry-level VPS, Raspberry Pi 2+, Synology NAS |
| Small team (10–50 users) | 1 vCPU, 1 GB RAM, 20 GB storage | Standard cloud VPS |
| Organization (50+ users) | 2 vCPU, 2 GB RAM, 40 GB storage | Medium cloud VPS, bare metal |
Software Requirements
Ensure your operating system (Ubuntu 24.04 LTS or Debian 13 recommended) has the following packages installed:
- Docker Engine version 24.0 or newer.
- Docker Compose plugin version 2.x (integrated in modern Docker Engine).
curlandopensslfor configuration purposes.
Install Docker Engine
Run the following command to install Docker Engine:
sudo sh -c "curl -fsSL https://get.docker.com/ | sh"Domain and SSL Requirements
HTTPS is a mandatory requirement to run Vaultwarden functionally. Bitwarden clients (browser extensions, mobile apps) require an HTTPS connection to access the server. Features such as synchronization, push notifications, and two-factor authentication will not work without SSL.
There are two main approaches to obtaining HTTPS:
- Domain + Reverse Proxy + Let's Encrypt: This method is most recommended. Use Nginx Proxy Manager or Traefik to manage automatic SSL certificates via Let's Encrypt.
- Cloudflare Tunnel: This method is an alternative that does not require opening ports 80/443 on the server firewall. This is suitable for networks behind NAT or without a public IP.
Ensure you already have an active domain name (e.g., vault.example.com) and access to your DNS panel before proceeding to the installation stage.
Vaultwarden Installation Steps
Step 1: Create docker-compose.yml File
Create a dedicated directory for Vaultwarden. Separating this directory is important to make the backup process easier and isolated from other Docker services.
sudo mkdir /opt/vaultwarden
cd /opt/vaultwardenConfigure docker-compose.yml
Create a docker-compose.yml file inside the /opt/vaultwarden/ directory.
sudo nano docker-compose.ymlEnter the configuration:
services:
vaultwarden:
image: vaultwarden/server:1.35.7
container_name: vaultwarden
restart: unless-stopped
env_file:
- .env
volumes:
# Mount data folder into container
- ./vw-data:/data
ports:
# Bind to localhost only — no need to expose to public
# Port 80 for HTTP (reverse proxy handles HTTPS)
- "127.0.0.1:8080:80"
# WebSocket port (required if WEBSOCKET_ENABLED: true)
- "127.0.0.1:3012:3012"
networks:
- internal
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
npm:
image: jc21/nginx-proxy-manager:2.14.0
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "81:81"
- "443:443"
environment:
DB_SQLITE_FILE: "/data/database.sqlite"
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
depends_on:
- vaultwarden
networks:
- internal
networks:
internal:Configure .env for Vaultwarden
Before creating the .env file, generate an ADMIN_TOKEN using argon2. The latest Vaultwarden version recommends tokens in Argon2id hashed format for better security:
# Install argon2 if not already present
sudo apt install -y argon2
# Generate token: replace 'your_secret_password' with a strong password
echo -n "your_secret_password" \
| argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4Copy the generated Argon2id hash output (format starts with $argon2id$v=...). This hash will be used as the value for ADMIN_TOKEN.
Create the .env file:
sudo nano .envEnter the configuration:
# Public URL of Vaultwarden — must be filled with your domain
DOMAIN: "https://vault.example.com"
# Admin panel — fill with the Argon2id hash that was generated
# Access admin panel: https://vault.example.com/admin
ADMIN_TOKEN: '$argon2id$v=19$m=65540,t=3,p=4$...'
# Disable new account registration after creating the first account
SIGNUPS_ALLOWED: "false"
# Disable invitation feature (optional, for extra security)
INVITATIONS_ALLOWED: "false"
# Enable WebSocket for real-time notifications in browser/desktop
WEBSOCKET_ENABLED: "true"
# Server time zone
TZ: "Asia/Jakarta"
# Log level (use "warn" in production to reduce noise)
LOG_LEVEL: "warn"Step 2: Run Docker Compose
Run docker compose:
sudo docker compose up -dCheck the status of containers in docker compose:
sudo docker compose psThe output should look like this:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx-proxy-manager jc21/nginx-proxy-manager:2.14.0 "/init" npm 33 minutes ago Up 33 minutes 0.0.0.0:80-81->80-81/tcp, [::]:80-81->80-81/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp
vaultwarden vaultwarden/server:1.35.7 "/start.sh" vaultwarden 33 minutes ago Up 33 minutes (healthy) 127.0.0.1:3012->3012/tcp, 127.0.0.1:8080->80/tcpCheck the vaultwarden container logs:
sudo docker logs vaultwardenThe log output should look like this:
/--------------------------------------------------------------------\
| Starting Vaultwarden |
| Version 1.35.7 |
|--------------------------------------------------------------------|
| This is an *unofficial* Bitwarden implementation, DO NOT use the |
| official channels to report bugs/features, regardless of client. |
| Send usage/configuration questions or feature requests to: |
| https://github.com/dani-garcia/vaultwarden/discussions or |
| https://vaultwarden.discourse.group/ |
| Report suspected bugs/issues in the software itself at: |
| https://github.com/dani-garcia/vaultwarden/issues/new |
\--------------------------------------------------------------------/Check the nginx-proxy-manager container logs:
sudo docker logs nginx-proxy-managerThe log output should look like this:
-------------------------------------
_ _ ____ __ __
| \ | | _ \| \/ |
| \| | |_) | |\/| |
| |\ | __/| | | |
|_| \_|_| |_| |_|
-------------------------------------
User: npm PUID:0 ID:0 GROUP:0
Group: npm PGID:0 ID:0
-------------------------------------
❯ Starting nginx ...
❯ Starting backend ...Verify port binding at the host level:
ss -tulnp | grep -E '80|81|443|8080|3012'The output should look like this:
tcp LISTEN 0 4096 0.0.0.0:81 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:443 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:3012 0.0.0.0:*
tcp LISTEN 0 4096 [::]:81 [::]:*
tcp LISTEN 0 4096 [::]:80 [::]:*
tcp LISTEN 0 4096 [::]:443 [::]:*Step 3: Configure Proxy Host
Configure Proxy Host for Vaultwarden in NPM:
- Log in to the NPM dashboard at
http://IP_SERVER:81. - Click
Proxy Hosts → Add Proxy Host. - Enter
Domain Names: vault.example.com. - Enter
Forward Hostname/IP: vaultwarden. - Enter
Forward Port: 80. - Check
Websockets Support(required for real-time sync). - In the SSL tab, select
Request a new SSL Certificate, then enableForce SSLandHTTP/2 Support. - In the
Settingstab, enter custom Nginx configuration for WebSocket:
location /notifications/hub {
proxy_pass http://vaultwarden:3012;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}Open a browser and access https://vault.example.com. If the Vaultwarden login page appears, the installation was successful.
Initial Configuration and Security
Creating the First Account
Immediately after installation, create your administrator account before disabling public registration:
- Open https://vault.example.com in your browser.
- Click Create Account.
- Enter your email address, name, and a strong master password (minimum 12 characters, combination of uppercase/lowercase letters, numbers, and symbols).
- Click Submit. The account is activated immediately without email verification by default.
Warning: Master password cannot be recovered if forgotten. Store it in a safe offline location. Bitwarden or Vaultwarden uses end-to-end encryption. This means even the server administrator cannot access your vault if they do not know the master password.
Enabling and Securing the Admin Panel
The Vaultwarden admin panel can be accessed at https://vault.example.com/admin using the ADMIN_TOKEN that was configured earlier. You can manage users, view statistics, send invitations, and change server configuration in real-time through the admin panel.
Recommended admin panel security steps:
- Use an Argon2id token (not plaintext) as configured in the previous step.
- Restrict access by IP at the reverse proxy level. Add the following rule in the Nginx configuration to restrict /admin access only from specific IPs:
# Add inside the Nginx server block (before location /)
location /admin {
# Allow only your admin IP
allow 203.0.113.10; # Replace with your public IP
deny all;
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;
}- Completely disable the admin panel if not needed by removing or emptying the
ADMIN_TOKENvariable indocker-compose.yml, then restart the container.
Disabling New Account Registration
After all required accounts have been created, disable public registration to prevent strangers from signing up on your server. Ensure the following values are present in the .env configuration:
# Disable account registration
SIGNUPS_ALLOWED: "false"
# Also disable invitation feature (optional, for extra security)
INVITATIONS_ALLOWED: "false"Restart the container for changes to take effect after modifying the configuration:
sudo docker compose restart vaultwardenRe-enable SIGNUPS_ALLOWED: "true" temporarily if you need to add new users later. Create the account, then disable it again or use the invitation feature through the admin panel.
Enabling Two-Factor Authentication (2FA)
2FA is highly recommended for every account on your Vaultwarden server. Vaultwarden supports various 2FA methods:
- Authenticator App (TOTP): Google Authenticator, Aegis (Android), Raivo (iOS).
- Email OTP: Requires SMTP configuration.
- YubiKey OTP: Hardware security key.
- FIDO2 / WebAuthn: Passkeys, hardware keys (YubiKey 5, SoloKey).
- Duo: Duo Security service integration.
Enabling 2FA via Authenticator App (TOTP)
- Log in to your vault at
https://vault.example.com. - Click
profile name → Account Settings. - Select the
Security → Two-step Logintab. - Click
Manageon theAuthenticator Approw. Scan the QR codewith yourauthenticator appon your phone.- Enter the
6-digit codefor verification, then clickEnable. Save recovery codesin a safe offline location.
SMTP Configuration
Configure SMTP for email notifications; optional but recommended. Email is required for email verification features, new login notifications, and account management. Add SMTP variables to .env:
# ... other variables ...
SMTP_HOST: "smtp.gmail.com"
SMTP_FROM: "[email protected]"
SMTP_FROM_NAME: "Vaultwarden"
SMTP_SECURITY: "starttls" # Options: "starttls", "force_tls", "off"
SMTP_PORT: "587"
SMTP_USERNAME: "[email protected]"
SMTP_PASSWORD: "your-app-password" # Use Google App Password
# Require email verification before account is active
REQUIRE_DEVICE_EMAIL: "true"Install Fail2Ban
Install Fail2Ban to automatically block IPs that perform brute-force login attempts.
Install fail2ban:
sudo apt install -y fail2banCreate a filter for Vaultwarden:
sudo tee /etc/fail2ban/filter.d/vaultwarden.conf <<'EOF'
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=docker.service
EOF
# Create jail for Vaultwarden
sudo tee /etc/fail2ban/jail.d/vaultwarden.conf <<'EOF'
[vaultwarden]
enabled = true
port = 80,443,8080
filter = vaultwarden
logpath = /opt/vaultwarden/data/vaultwarden.log
maxretry = 5
bantime = 3600
findtime = 600
EOFRestart fail2ban:
sudo systemctl restart fail2ban
sudo fail2ban-client status vaultwardenMigration and Daily Usage
Importing Data from Other Password Managers
Vaultwarden accepts the same import formats as Bitwarden. The import process is done through the web vault interface:
From Bitwarden Cloud
- Log in to
https://vault.bitwarden.com. - Click
Tools → Export Vault. - Select
JSON (Encrypted)format for best security, or JSON for direct import. - Log in to your
Vaultwardenserver, then clickTools → Import Data. - Select
Bitwarden (json)as the format, upload the file, then clickImport Data.
From Google Chrome Password Manager
- Open
Chrome → Settings → Passwords. - Click the
three dots icon on the right → Export Passwords → save as CSV. - In your Vaultwarden vault:
Tools → Import Data → select Chrome (csv) → upload file.
From LastPass
- Log in to
LastPass → Advanced Options → Export. Save the downloaded CSV file.- In Vaultwarden:
Tools → Import Data → select LastPass (csv) → upload.
From KeePass / KeePassX
- Export the
KeePassdatabase toXMLformat. - In Vaultwarden:
Tools → Import Data → select KeePass 2 (xml) → upload.
Security during import: CSV files from Chrome or LastPass contain passwords in plaintext. Delete these files immediately after the import process is complete. Use
shred -u filename.csvon Linux to securely delete.
Client Setup: Connecting to Your Own Server
All official Bitwarden clients support custom server URL configuration. Here's how to connect them to your Vaultwarden instance:
Browser Extensions (Chrome, Firefox, Edge, Safari)
- Install the
Bitwarden extensionfrom your browser's extension store. - Open the extension, then click the gear icon (
Settings) or click theserver regionon the login screen. - Select
Self-hosted. - Enter Server URL:
https://vault.example.com. - Click
Save, thenlog inwith your account.
Mobile Apps (Android / iOS)
- Install the
Bitwardenapp from theGoogle Play StoreorApple App Store. - On the login screen, tap
Logging in on: or theSelf-hostedicon. - Enter Server URL:
https://vault.example.com. - Tap Save, then log in.
Desktop Apps (Windows, macOS, Linux)
- Download
Bitwarden Desktopfromhttps://bitwarden.com/download. - On the login screen, click
Accessing: → Self-hosted. - Enter
Server URL, clickSave, thenlog in.
Organization Features and Password Sharing
Vaultwarden fully supports Bitwarden Organizations features. This is ideal for sharing passwords within a family or small team:
- Creating an Organization: Log in to the web vault, click profile name → New Organization → enter name and billing email (you can use a dummy email for self-hosted).
- Inviting Members: In the Organization dashboard, select the Members tab → Invite Member → enter member's email.
- Creating Collections: Collections are shared folders within an Organization. Create collections based on categories, such as "Family", "Work", or "Server Credentials".
- Sharing Items: Select the appropriate Organization and Collection when adding or editing vault items so that the item can be accessed by all members.
Maintenance and Backup
How to Update Vaultwarden
Vaultwarden regularly releases updates with security fixes and new features. The update process using Docker is very simple:
cd /opt/vaultwarden
# Pull the latest image from Docker Hub
sudo docker compose pull
# Recreate container with new image (downtime around 5–10 seconds)
sudo docker compose up -d --remove-orphans
# Verify container is running with the latest image
sudo docker compose ps
sudo docker inspect vaultwarden | grep ImageCheck the Vaultwarden Releases page before updating to read the changelog and ensure there are no breaking changes that require migration preparation.
Database Backup Strategy
This is the most critical part of managing Vaultwarden. Losing vault data is equivalent to losing access to all stored accounts.
All Vaultwarden data is stored in the /opt/vaultwarden directory with the following structure:
/opt/vaultwarden
├── docker-compose.yml
├── npm-data
├── npm-letsencrypt
└── vw-data
├── db.sqlite3
├── db.sqlite3-shm
├── db.sqlite3-wal
├── rsa_key.pem
└── tmpSQLite has a WAL (Write-Ahead Logging) mechanism that requires a special approach for backup to ensure data consistency. Use the sqlite3 command with online backup mode.
Install sqlite3:
sudo apt install -y sqlite3Create a backup bash script:
sudo nano /opt/vaultwarden/backup.shEnter the script:
#!/bin/bash
# /opt/vaultwarden/backup.sh
BACKUP_DIR="/backup/vaultwarden"
DATA_DIR="/opt/vaultwarden/vw-data"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/vaultwarden_$DATE.tar.gz"
# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"
# Backup SQLite database online (safe while container is running)
sqlite3 "$DATA_DIR/db.sqlite3" ".backup '$BACKUP_DIR/db_$DATE.sqlite3'"
# Create archive including database and attachments folder
tar -czf "$BACKUP_FILE" \
-C "$BACKUP_DIR" "db_$DATE.sqlite3" \
-C "$DATA_DIR" .
# Delete temporary db file
rm "$BACKUP_DIR/db_$DATE.sqlite3"
# Delete backups older than 30 days
find "$BACKUP_DIR" -name "vaultwarden_*.tar.gz" -mtime +30 -delete
echo "Backup completed: $BACKUP_FILE"
echo "Size: $(du -sh "$BACKUP_FILE" | cut -f1)"Run the bash script:
# Give execute permission to the script
sudo chmod u+x /opt/vaultwarden/backup.sh
# Test run manually
sudo /opt/vaultwarden/backup.shSchedule automatic backup daily at 02:00 WIB:
# Edit root crontab
sudo crontab -e
# Add the following line:
0 2 * * * /opt/vaultwarden/backup.sh >> /var/log/vaultwarden-backup.log 2>&1Verify Backup Integrity
A backup that has never been tested is equivalent to having no backup. Perform restore tests periodically, at least once every month:
# Extract backup to temporary directory
mkdir -p /tmp/vaultwarden-restore
tar -xzf /backup/vaultwarden/vaultwarden_YYYYMMDD_HHMMSS.tar.gz \
-C /tmp/vaultwarden-restore
# Verify SQLite database integrity
sqlite3 /tmp/vaultwarden-restore/db_YYYYMMDD_HHMMSS.sqlite3 "PRAGMA integrity_check;"
# Correct output: "ok"
# Clean up temporary directory
rm -rf /tmp/vaultwarden-restoreConclusion
Vaultwarden is a superior self-hosted password manager solution in terms of resource efficiency, feature completeness, and ease of management. You get the entire Bitwarden ecosystem through a Rust-based single-container architecture, including premium features that are usually paid, only at the cost of an entry-level VPS.


