How to Install Vaultwarden on Ubuntu 24.04 — Self-Hosted Bitwarden-Compatible Password Manager
Every password you type, every credit card you save in a browser, every MFA recovery code tucked into a note — all of it eventually ends up in a password manager. That makes the choice of vault deeply personal: you are handing the keys to your digital life to a piece of software and, in most cases, to the company that runs its servers. This guide shows you how to keep those keys under your own roof by installing Vaultwarden, a lightweight Rust-based server that speaks the Bitwarden protocol, on an Ubuntu 24.04 VPS.
Want the fastest path? Deploy a hardened Vaultwarden stack with TLS, backups, and fail2ban on our Starter VPS plan and follow this guide end to end — you will be logged into your own vault within 25 minutes.
Table of Contents
What is Vaultwarden?
Vaultwarden is an unofficial, open-source reimplementation of the Bitwarden server written in Rust. It speaks the exact same API as the official Bitwarden backend, which means every Bitwarden client — the web vault, iOS and Android apps, desktop apps for macOS, Windows, and Linux, every browser extension, the CLI, and the directory connector — talks to Vaultwarden without knowing the difference.
What it changes is what runs on your server. The official Bitwarden stack is a microservices architecture of roughly a dozen .NET containers plus Microsoft SQL Server, sized for enterprise workloads and realistically needing 4 GB of RAM just to idle. Vaultwarden packs the same functionality into a single Rust binary that starts in milliseconds, uses SQLite by default, and runs comfortably in 50 MB of RAM. On top of that, features that require a paid subscription in official Bitwarden — attachments, password history, organizations, TOTP generation, emergency access, Bitwarden Send — are enabled out of the box.
Vaultwarden is maintained primarily by Daniel García and a community of contributors. It is not affiliated with or endorsed by Bitwarden Inc., but it tracks upstream API changes closely and is widely used in home labs, small businesses, and even some larger deployments where operational simplicity matters more than commercial support.
Why Self-Host vs. LastPass or 1Password?
The password manager market has spent the last few years giving users reasons to reconsider cloud-hosted vaults. LastPass disclosed a catastrophic breach in 2022 in which attackers exfiltrated encrypted vault backups; while vaults remained encrypted, every user with a weak master password suddenly faced an offline brute-force attack they could not detect, stop, or rotate around. 1Password has had a cleaner track record but charges per-seat subscriptions indefinitely and still stores your encrypted blobs on infrastructure you do not control. Dashlane, Keeper, and NordPass all run the same cloud model.
Self-hosting changes the threat model in several concrete ways:
- You control the blast radius. An attacker who breaches Bitwarden Inc. potentially affects tens of millions of vaults. An attacker who breaches your VPS affects exactly one. You are a target of one, not a target of opportunity inside a target of millions.
- No subscription, ever. Vaultwarden is free, open source, and ships every paid-tier feature — organizations, collections, emergency access, unlimited attachments, TOTP — with no license file or feature flag. A EUR 5–20/month VPS replaces a EUR 3–10/month per-seat subscription that scales linearly with your family or team.
- You decide the retention policy. LastPass still held encrypted backups from users who had deleted their accounts years earlier. On your own server,
rmmeans rm. - Compliance control. Host in the EU for GDPR, in Switzerland for Swiss data protection, or on-premises for regulated industries. You sign your own data processing agreement with yourself.
- No vendor lock-in. If you ever want to leave, export to the standard Bitwarden JSON format and import into any compatible manager. If Vaultwarden itself disappears tomorrow, the official Bitwarden server will accept your database with minor migration.
- Client-side encryption is identical. Your master password never reaches the server in any form. Argon2 (or PBKDF2) derives an encryption key on your device; the server only ever sees opaque ciphertext. Self-hosting does not weaken the cryptography — it strengthens the surrounding threat model.
Cost Comparison
| Plan | Users | Monthly Cost | Attachments | TOTP | Emergency Access |
|---|---|---|---|---|---|
| Bitwarden Free | 1 | $0 | No | No | No |
| Bitwarden Premium | 1 | ~$0.83/mo | 1 GB | Yes | Yes |
| Bitwarden Families | 6 | ~$3.33/mo | 1 GB each | Yes | Yes |
| 1Password Individual | 1 | $2.99/mo | 1 GB | Yes | No |
| 1Password Family | 5 | $4.99/mo | 1 GB each | Yes | Limited |
| Vaultwarden on Starter VPS | Unlimited | EUR 7.99/mo | Unlimited (disk-bound) | Yes | Yes |
Prerequisites
Before you start, make sure you have:
- An Ubuntu 24.04 LTS VPS with root or sudo access
- SSH access to the server
- A domain name (for example,
vault.example.com) with an A record pointing to your VPS's public IP - Port 80 and 443 open on the server firewall
- At least 1 GB of RAM and 20 GB of storage (Vaultwarden itself needs far less, but leave headroom for backups)
Recommended Plan: Starter VPS>
Vaultwarden is not resource-intensive, but you want enough headroom for Nginx, fail2ban, automated backups, and OS updates. The Starter plan gives you:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered traffic
- EU or US data centers>
This is also enough room to co-host a lightweight identity provider like Authelia or Authentik on the same box if you want SSO in front of your vault.
Connect to your server:
ssh root@your-server-ipStep 1: Update System Packages
sudo apt update && sudo apt upgrade -yIf the kernel was upgraded, reboot:
sudo rebootPoint the DNS A record for your chosen hostname (for example, vault.example.com) at your server's public IPv4 address before continuing — Let's Encrypt will need it to resolve during certificate issuance.
Step 2: Install Docker and Docker Compose
Add Docker's official APT repository and install the latest Engine plus the Compose plugin:
sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpgecho \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu noble stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify:
sudo docker --version
sudo docker compose versionExpected output:
Docker version 27.x.x, build xxxxx
Docker Compose version v2.29.xEnable Docker on boot:
sudo systemctl enable --now dockerStep 3: Deploy the Vaultwarden Container
Create a dedicated directory for the stack:
sudo mkdir -p /opt/vaultwarden/data
cd /opt/vaultwardenCreate a docker-compose.yml file:
sudo tee /opt/vaultwarden/docker-compose.yml > /dev/null <<'EOF'
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
env_file: .env
volumes:
- ./data:/data
ports:
- "127.0.0.1:8080:80"
EOFThe key points:
- The image is
vaultwarden/server:latest— the official community image. Pin to a specific tag like1.32.5in production so updates are deliberate. ./data:/datapersists the SQLite database, attachments, RSA signing keys, icon cache, and sends. Everything that matters lives in this folder.- The container binds only to
127.0.0.1:8080— Nginx will proxy public traffic to it over TLS. Vaultwarden is never directly reachable from the internet.
Step 4: Configure Environment Variables
Generate a strong admin token. The admin panel is gated behind this value, so treat it like a root password:
openssl rand -base64 48Copy the output. Now create the environment file:
sudo tee /opt/vaultwarden/.env > /dev/null <<'EOF'
--- Core ---
DOMAIN=https://vault.example.com
SIGNUPS_ALLOWED=true
INVITATIONS_ALLOWED=true
SHOW_PASSWORD_HINT=false--- Admin panel ---
Paste the openssl output from above. Argon2-hash it later (see Step 7).
ADMIN_TOKEN=REPLACE_WITH_OPENSSL_OUTPUT--- Security ---
ROCKET_PORT=80
WEB_VAULT_ENABLED=true
SENDS_ALLOWED=true
EMERGENCY_ACCESS_ALLOWED=true--- Logging ---
LOG_LEVEL=warn
EXTENDED_LOGGING=true
EOFReplace vault.example.com with your real hostname and paste your generated token in place of REPLACE_WITH_OPENSSL_OUTPUT.
The three variables you must understand:
ADMIN_TOKEN— Gates/admin. If unset, the admin panel is disabled entirely, which is the safest default after first-run setup. For the initial install, set it so you can configure SMTP and invite users through the UI.DOMAIN— Must exactly match the URL clients will use, includinghttps://and any subdomain. Vaultwarden uses this to construct WebAuthn relying-party IDs, email invite links, and CORS headers. Mismatches here cause "invalid domain" errors on every client.SIGNUPS_ALLOWED— Leave astruelong enough to register your own account, then set tofalseand restart the container. This is the most important post-install step: an unattended Vaultwarden with open signups is an account factory for anyone who finds the URL.
sudo chmod 600 /opt/vaultwarden/.env
cd /opt/vaultwarden
sudo docker compose up -dCheck the logs:
sudo docker compose logs -fYou should see:
[INFO] Rocket has launched from http://0.0.0.0:80Press Ctrl+C to exit the log stream — the container keeps running.
Step 5: Nginx Reverse Proxy with TLS
Vaultwarden requires HTTPS. Bitwarden clients refuse to connect to anything other than localhost over plain HTTP, and WebAuthn mandates a secure context. Nginx terminates TLS and forwards plaintext HTTP to the container on loopback.
Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxCreate a server block:
sudo tee /etc/nginx/sites-available/vaultwarden > /dev/null <<'EOF' server { listen 80; server_name vault.example.com; return 301 https://$host$request_uri; }server { listen 443 ssl http2; server_name vault.example.com;
# Certificates are filled in by Certbot on first run ssl_certificate /etc/letsencrypt/live/vault.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/vault.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
# Security headers add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header Referrer-Policy "same-origin" always;
# Large attachments client_max_body_size 525M;
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;
# Required for WebSocket notifications proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 90; } } EOF
Replace vault.example.com with your hostname throughout the file. Enable the site and obtain a certificate:
sudo ln -s /etc/nginx/sites-available/vaultwarden /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo certbot --nginx -d vault.example.com
sudo systemctl reload nginxCertbot writes the certificate, adjusts the Nginx config, and sets up a systemd timer for automatic renewal. Confirm by opening https://vault.example.com in your browser — you should see the Bitwarden web vault login page.
Step 6: Connect Bitwarden Clients
Your Vaultwarden server is ready. Every official Bitwarden client connects the same way: point it at your self-hosted URL before logging in for the first time.
Web vault — Already served at https://vault.example.com. Click "Create account" to register your first user (remember, SIGNUPS_ALLOWED=true is still set).
Desktop apps (Windows, macOS, Linux) — Download from bitwarden.com/download. On the login screen, click the gear icon, choose "Self-hosted", and enter https://vault.example.com as the Server URL.
iOS and Android — Install the Bitwarden app from the App Store or Google Play. On the login screen, tap the gear icon and set "Self-hosted environment" → Server URL to https://vault.example.com. Save and log in.
Browser extensions — Install Bitwarden for Chrome, Firefox, Edge, Safari, or Brave. Click the settings icon on the login screen, pick "Self-hosted", enter your Server URL, save, and log in. The extension will offer to autofill and save credentials on every site you visit.
CLI (bw) — For scripted vault access:
npm install -g @bitwarden/cli
bw config server https://vault.example.com
bw login [email protected]Once signed in, register your personal account through the web vault, then immediately disable signups:
sudo sed -i 's/SIGNUPS_ALLOWED=true/SIGNUPS_ALLOWED=false/' /opt/vaultwarden/.env
cd /opt/vaultwarden && sudo docker compose up -dAdditional users can now be invited from the admin panel or from within an organization.
Step 7: Admin Panel, SMTP, and WebAuthn
Navigate to https://vault.example.com/admin and paste your ADMIN_TOKEN. You will see a dashboard with server status, users, organizations, and a "Settings" tab exposing every environment variable.
Hash the admin token
Storing the token in plaintext is fine for an initial bootstrap but should be upgraded to an Argon2 hash so a leaked .env does not compromise the admin panel:
sudo docker compose exec vaultwarden /vaultwarden hashEnter the same plaintext token when prompted. The command prints an $argon2id$ string. Replace the ADMIN_TOKEN value in .env with that full string (wrap it in single quotes) and restart:
sudo docker compose up -dYou still type the original plaintext token at the login screen; Vaultwarden verifies it against the hash.
Configure SMTP for email notifications
Invitations, emergency access requests, password-change verifications, and new-device warnings all rely on outbound email. In the admin panel, open SMTP Email Settings and fill in your provider's details — for example, for a freshly installed Mailcow or a transactional provider like Postmark, Mailgun, or Amazon SES:
SMTP Host: smtp.mail.example.com
SMTP Port: 587
SMTP Security: STARTTLS
SMTP From: [email protected]
SMTP From Name: Vaultwarden
SMTP Username: [email protected]
SMTP Password: your-smtp-passwordSave, then click "Send test email" and confirm it arrives. Everything Vaultwarden emails — invites, alerts, 2FA recovery — now flows through your own SMTP.
Enable WebAuthn (U2F hardware keys and passkeys)
WebAuthn is the strongest second factor available: a hardware security key like a YubiKey, a Titan Key, or a platform authenticator (Touch ID, Windows Hello, Android biometrics). Because you configured DOMAIN=https://vault.example.com in Step 4, WebAuthn relying-party IDs are already correct — no additional server config is needed.
To enable it on your account:
https://vault.example.com.Register at least two keys (one primary, one backup stored offsite) and generate a one-time recovery code. Do the same for every user as a matter of policy — enforcing 2FA across an organization is available under Organizations → Policies in Vaultwarden with no premium license required.
Step 8: Backups of the Data Folder and SQLite
Every piece of state Vaultwarden needs to rebuild itself — user accounts, vaults, attachments, organizations, sends, icon cache, and the RSA keys it uses to sign tokens — lives in /opt/vaultwarden/data. Back up that folder and you can restore the entire service to any fresh VPS in minutes. Lose it and no amount of uptime will bring your vaults back.
Nightly backup script
Create /usr/local/bin/vaultwarden-backup.sh:
sudo tee /usr/local/bin/vaultwarden-backup.sh > /dev/null <<'EOF' #!/usr/bin/env bash set -euo pipefailBACKUP_DIR="/var/backups/vaultwarden" DATA_DIR="/opt/vaultwarden/data" STAMP="$(date +%Y%m%d-%H%M%S)" KEEP_DAYS=14
mkdir -p "$BACKUP_DIR"
1. Online SQLite backup (safe while Vaultwarden is running)
sqlite3 "$DATA_DIR/db.sqlite3" ".backup '$BACKUP_DIR/db-$STAMP.sqlite3'"2. Tar the rest of the data folder (attachments, sends, rsa_key, config.json)
tar --exclude='db.sqlite3*' -czf "$BACKUP_DIR/data-$STAMP.tar.gz" -C "$DATA_DIR" .3. Rotate old backups
find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -delete
echo "[$(date -Iseconds)] Backup complete: $STAMP" EOF sudo chmod +x /usr/local/bin/vaultwarden-backup.sh
Install sqlite3 if it is not already present (sudo apt install -y sqlite3) and schedule a nightly cron job:
echo "15 3 * root /usr/local/bin/vaultwarden-backup.sh >> /var/log/vaultwarden-backup.log 2>&1" | \
sudo tee /etc/cron.d/vaultwarden-backupShip backups offsite
On-server backups protect against data corruption but not against losing the whole VPS. Push them to S3, Backblaze B2, or a second server. A minimal rclone example:
sudo apt install -y rclone
sudo rclone config # set up remote "offsite:"Add to the backup script before rotation:
rclone copy "$BACKUP_DIR" offsite:vaultwarden-backups/ --max-age 1dTest the restore
Untested backups are wishful thinking. Once a quarter, restore to a fresh VPS:
# On a new Ubuntu box with Docker installed: sudo mkdir -p /opt/vaultwarden/data sudo tar -xzf data-YYYYMMDD-HHMMSS.tar.gz -C /opt/vaultwarden/data sudo cp db-YYYYMMDD-HHMMSS.sqlite3 /opt/vaultwarden/data/db.sqlite3
Copy docker-compose.yml and .env, then: docker compose up -d
If your clients log in and see their vaults, your backup strategy works.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Client shows "We were unable to process your request" | DOMAIN in .env does not exactly match the URL the client is using | Make sure DOMAIN=https://vault.example.com matches scheme, host, and port. Restart container. |
| "The name on the security certificate is invalid" | Certbot issued for the wrong hostname or certificate did not renew | Run sudo certbot certificates to check, then sudo certbot renew --force-renewal |
| WebAuthn key registration fails | Relying-party ID mismatch from DOMAIN drift or non-HTTPS access | Verify TLS is working and DOMAIN is correct. Remove and re-register the key. |
/admin returns 404 | ADMIN_TOKEN is unset or empty | Set it in .env and restart. An empty token disables the admin panel by design. |
| Emails not arriving | SMTP credentials wrong, firewall blocking port 587, or DMARC rejection | Send test email from admin panel, check container logs for SMTP errors, verify SPF/DKIM records on sending domain. |
| "Too many requests" during login | Vaultwarden's built-in rate limiter | Wait 5 minutes, or tune LOGIN_RATELIMIT_SECONDS and LOGIN_RATELIMIT_MAX_BURST in .env |
| Container fails to start, logs show "database is locked" | Previous container did not shut down cleanly | docker compose down, then docker compose up -d. If persistent, restore db.sqlite3 from last backup. |
cd /opt/vaultwarden && sudo docker compose logs -fFAQ
Is Vaultwarden safe to self-host?
Yes, when configured correctly. Vaultwarden uses the same client-side encryption as Bitwarden: your vault is encrypted with a key derived from your master password before it ever leaves your device. The server only stores encrypted blobs. Combine that with TLS, a strong ADMIN_TOKEN, WebAuthn for admin access, and regular offsite backups and you have a deployment that matches or exceeds the security posture of commercial password managers. The attack surface is also smaller — you are one target among millions rather than the juiciest target on someone's list.
Is Vaultwarden the same as Bitwarden?
Vaultwarden is an unofficial, community-maintained server implementation written in Rust that speaks the same API as the official Bitwarden server. It is fully compatible with every official Bitwarden client but uses a fraction of the resources and ships all premium features by default. It is not affiliated with Bitwarden Inc., and it does not come with commercial support. For most individuals, families, and small teams that distinction does not matter; for regulated enterprises that require a vendor with an SLA, the official Bitwarden self-hosted edition is the correct choice.
What are the minimum VPS specs for Vaultwarden?
Vaultwarden is exceptionally lightweight. Idle RAM use is under 50 MB and CPU usage is effectively zero between requests. A 1 vCPU, 2 GB RAM VPS with 20 GB of storage comfortably runs Vaultwarden for a family, small team, or hundreds of users. The Starter plan at 2 vCPU / 4 GB RAM gives you headroom for Nginx, fail2ban, and automated backups on the same server, plus room to co-host a related service like an identity provider later.
Does Vaultwarden require HTTPS?
Yes, TLS is mandatory in practice. Bitwarden clients refuse to connect to servers over plain HTTP except on localhost, and the WebAuthn/U2F features require a secure context. This guide uses Nginx plus Let's Encrypt to terminate TLS with an automatically renewing certificate. Self-signed certificates can work for the desktop and web clients but break mobile apps and browser extensions, so always use a publicly trusted certificate.
How do I migrate from LastPass or 1Password?
Export your vault from LastPass (Advanced Options → Export → LastPass CSV File) or 1Password (File → Export → 1PIF or CSV), then open the Bitwarden web vault pointed at your Vaultwarden instance and use Tools → Import data. Bitwarden supports native importers for LastPass, 1Password, Dashlane, KeePass, Chrome, Firefox, and over 50 other formats. Once import completes and you have verified a few entries unlock correctly, securely delete the plaintext export file with shred -u or srm.
Can I put Vaultwarden behind my SSO / identity provider?
Yes. Vaultwarden exposes a standard HTTP surface, so any reverse-proxy-based identity provider can front the web vault and admin panel while leaving the client API endpoints open for mobile and desktop clients. Common patterns include Authelia for lightweight forward-auth, Authentik for a full OIDC/SAML identity platform, or Keycloak for enterprise-grade federation. Be careful not to gate the /identity/, /api/, /notifications/, and /icons/ paths behind SSO — those are consumed by Bitwarden clients and breaking them breaks every app.
How often should I back up?
Daily at minimum. The entire state lives in the data volume (SQLite database, attachments, RSA keys, icon cache). The nightly cron job in Step 8 takes an online SQLite backup, tars the rest of the data folder, and rotates older files. Add rclone to ship a copy offsite. Test the restore procedure at least once per quarter on a throwaway VPS — untested backups have a way of failing exactly when you need them.
Next Steps
With Vaultwarden running, you have the foundation of a self-hosted identity stack. Useful follow-ups:
- Add fail2ban for login protection — Vaultwarden emits structured log lines on failed logins. A fail2ban jail watching
/opt/vaultwarden/data/vaultwarden.logcan ban brute-force attackers at the firewall level. See the Vaultwarden wiki.
- Deploy an identity provider for SSO — Install Authelia, Authentik, or Keycloak alongside Vaultwarden to add forward-auth or OIDC to other self-hosted services (Nextcloud, Grafana, internal dashboards) using the same user directory.
- Migrate from SQLite to PostgreSQL — For large deployments (500+ users, high concurrent request rate), switch the
DATABASE_URLto a local PostgreSQL instance. The Vaultwarden wiki documents the procedure for MariaDB and PostgreSQL.
- Set up uptime monitoring — A password manager that is down is a password manager you cannot trust in an emergency. Monitor the
/aliveendpoint with Uptime Kuma, UptimeRobot, or your existing monitoring stack, with SMS alerts for downtime.
- Explore the wiki — The Vaultwarden wiki on GitHub is the canonical reference for every environment variable, backup strategy, database migration, and integration recipe. Bookmark it.
Save Your Passwords, Not Your Subscription>
Self-hosted Vaultwarden on a Starter VPS is the most cost-effective password manager for families, teams, and privacy-conscious individuals. Every premium Bitwarden feature, unlimited users, your data on your server, and no monthly per-seat fees.>
- 2 vCPU, 4 GB RAM, 50 GB NVMe — from EUR 7.99/month
- EU and US data centers, Ubuntu 24.04 LTS images
- Nightly snapshots included
- 24/7 support from a team that self-hosts too>
Deploy Your VPS and start following this guide.