Self-hosting Bitwarden on a Linux server gives you full control over your encrypted password vault — no third-party cloud storage, no subscription required for most features, and full audit visibility over who accesses what. The recommended approach in 2026 is to use Bitwarden Unified (the single-Docker-container deployment) on a Ubuntu 22.04 or Debian 12 server, which replaces the older multi-container stack and is significantly easier to maintain for individuals and small teams.
Prerequisites / What You'll Need
- Server OS: Ubuntu 22.04 LTS or Debian 12 (Bookworm) — 64-bit only
- RAM: Minimum 2 GB; 4 GB recommended for teams of 5 or more
- Storage: 10 GB free disk space minimum
- Docker: Version 24.x or later
- Docker Compose: Version 2.20 or later (included in Docker Desktop; standalone plugin for server installs)
- Domain name: A fully qualified domain name (FQDN) with an A record pointing to your server's public IP — e.g.,
vault.yourdomain.com - Ports open: 80 (HTTP, for Let's Encrypt challenge) and 443 (HTTPS)
- SMTP credentials: An outbound email account for user verification emails (Gmail App Password, Mailgun, or similar)
- Bitwarden account: A free bitwarden.com account to generate an Installation ID and Installation Key at https://bitwarden.com/host/
Step 1: Update Your Server and Install Docker
SSH into your server and bring the system up to date before touching anything else.
sudo apt update && sudo apt upgrade -y
Install Docker's official GPG key and repository:
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.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") 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
Add your user to the docker group so you don't need sudo for every Docker command:
sudo usermod -aG docker $USER
newgrp docker
Verify: Run docker --version — you should see output like Docker version 26.1.4, build .... Run docker compose version — you should see Docker Compose version v2.27.x.
Common gotcha: On Debian 12, replace ubuntu with debian in the repository URL. Using the wrong OS string causes a "no packages found" error.
Step 2: Get Your Installation ID and Key
Navigate to https://bitwarden.com/host/ and log in with your free bitwarden.com account. Click Generate to create an Installation ID and Installation Key pair tied to your domain name.
Save both values somewhere secure — you cannot retrieve the Installation Key after leaving that page. These values let Bitwarden's licensing server validate your self-hosted instance and are required even for the free tier.
Step 3: Download and Configure the Unified Deployment
Create a working directory and download the official Docker Compose file:
mkdir ~/bitwarden && cd ~/bitwarden
curl -Lo docker-compose.yml https://raw.githubusercontent.com/bitwarden/self-host/main/docker/docker-compose.unified.yml
curl -Lo settings.env https://raw.githubusercontent.com/bitwarden/self-host/main/docker/settings.unified.env
Open settings.env with your editor of choice and configure the required fields:
nano settings.env
Key values to set:
BW_DOMAIN=vault.yourdomain.com
BW_DB_DATABASE=bitwarden_vault
BW_DB_USERNAME=bitwarden
BW_DB_PASSWORD=<strong-random-password>
BW_INSTALLATION_ID=<your-installation-id>
BW_INSTALLATION_KEY=<your-installation-key>
[email protected]
globalSettings__mail__smtp__host=smtp.gmail.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__ssl=false
[email protected]
globalSettings__mail__smtp__password=<gmail-app-password>
Leave BW_SSL_MANAGED_LETS_ENCRYPT=true if you want the container to handle Let's Encrypt automatically (recommended). If you're supplying your own certificate, set it to false and mount your cert files.
Common gotcha: If your SMTP password contains special characters like $ or !, wrap it in single quotes or escape each character — unescaped variables break the container startup silently.
Step 4: Start Bitwarden
From your ~/bitwarden directory, pull the image and start the stack:
docker compose up -d
The first pull downloads approximately 500 MB. Subsequent starts are fast. Watch the logs to confirm everything initializes cleanly:
docker compose logs -f
You're looking for a line like:
bitwarden-unified | Now listening on: https://[::]:8080
The Let's Encrypt certificate provisioning happens automatically on first start and takes 30–90 seconds. If port 80 isn't reachable from the internet, this step fails.
Step 5: Create the Admin Account
Open a browser and navigate to https://vault.yourdomain.com. You should see the Bitwarden login page with your custom domain in the address bar and a valid HTTPS padlock.
Click Create Account, fill in your email and a strong master password. Your vault data is encrypted locally with AES-256-CBC before being sent to the server; the server stores only the encrypted ciphertext. Key derivation uses PBKDF2-SHA256 (minimum 600,000 iterations as of the 2023 client update, configurable upward).
To access the admin panel for user management, navigate to https://vault.yourdomain.com/admin. You'll need to set an adminSettings__admins email in settings.env and restart the container.
Step 6: Enable Two-Factor Authentication
Log into your vault, go to Account Settings → Security → Two-step Login. Bitwarden self-hosted supports:
- TOTP (Google Authenticator, Authy, any RFC 6238-compatible app) — free tier
- Email OTP — free tier
- WebAuthn / FIDO2 hardware keys (YubiKey, Passkey-capable devices) — requires Bitwarden Premium at $10/year per user
- Duo Security push — requires Bitwarden Families or Teams plan
Enable TOTP at minimum before storing any credentials in your vault.
Verification Checks
After completing setup, confirm these specific states:
https://vault.yourdomain.comloads with a valid TLS certificate (not self-signed, not expired)docker psshows thebitwarden-unifiedcontainer with statusUp X minutes (healthy)- You receive a verification email when registering a new account
- The Bitwarden mobile app (iOS or Android) can connect by entering
https://vault.yourdomain.comas the Self-hosted environment URL in Settings - The browser extension (Chrome, Firefox, Safari, Edge) syncs successfully after pointing it to your custom server URL
Recommended Tools to Complement Your Self-Hosted Setup
Self-hosting solves data sovereignty, but it introduces operational responsibility — backups, uptime, and access management. These two products pair well depending on your situation.
Keeper Security — Best for Teams Migrating Off Self-Hosted
If you're running Bitwarden self-hosted for a team and find the maintenance burden growing, Keeper Security is worth evaluating as a managed alternative. Keeper uses AES-256-GCM encryption with PBKDF2-SHA256 key derivation and stores zero plaintext data. It's headquartered in Chicago, Illinois, subject to US data-protection law, and has completed SOC 2 Type II audits by third-party assessors. MFA options include TOTP, WebAuthn/FIDO2, hardware security keys (YubiKey 5 series), Duo push, and RSA SecurID.
Keeper Business pricing is $4.00/user/month billed annually, 5-seat minimum, which comes to $240/year for a 5-person team. Keeper Enterprise starts at $5.00/user/month billed annually with SCIM provisioning and AD integration. Personal plans run $2.92/user/month billed annually ($35/year).
The trade-off versus self-hosted Bitwarden: you lose direct control over the database, but you gain 24/7 uptime, automated backups, and breach-watch monitoring without running your own infrastructure. Our enterprise password manager review covers Keeper's team features in depth.
Try Keeper Security — managed alternative if self-hosting overhead outweighs the control benefits.
1Password — Best for Individuals Who Want a Fallback
1Password works alongside a self-hosted Bitwarden instance as a fallback vault or a migration target. 1Password is headquartered in Toronto, Canada, under PIPEDA and GDPR compliance frameworks. It uses AES-256-GCM encryption with PBKDF2-SHA256 key derivation and a unique Secret Key architecture that prevents server-side brute force even if the encrypted database is stolen. Third-party security audits have been completed by Cure53 (penetration test, 2022) and an ongoing bug bounty program runs on HackerOne.
MFA methods: TOTP, WebAuthn/FIDO2, hardware keys (YubiKey 5 NFC, YubiKey 5C), and Duo integration. Supported platforms: Windows, macOS, Linux (native app), iOS, Android, Chrome, Firefox, Edge, Safari, Brave.
Pricing: $2.99/user/month billed annually for Personal (1 user), $4.99/month billed annually for Families (up to 5 users), $7.99/user/month billed annually for Teams Starter (up to 10 users), $19.95/user/month billed annually for Business (unlimited users, advanced reporting, 5 guest accounts per team member).
1Password doesn't offer a self-hosted deployment option, which is a real limitation if data residency is your primary driver for self-hosting Bitwarden in the first place.
Try 1Password — solid fallback vault with Secret Key protection if your self-hosted instance goes down.
Troubleshooting
1. Let's Encrypt certificate fails to issue
Error: Error: Failed to obtain certificate: acme: error: 400 :: urn:ietf:params:acme:error:connection
Fix: Port 80 must be reachable from the public internet at the moment of certificate issuance. Check your firewall (sudo ufw status) and your cloud provider's security group rules. Run curl -I http://vault.yourdomain.com from an external machine to confirm port 80 responds. The A record for your domain must resolve to your server's current public IP — check with dig +short vault.yourdomain.com.
2. Container exits immediately on startup
Error: bitwarden-unified exited with code 1 (visible in docker compose logs)
Fix: Almost always a malformed settings.env. Open the file and check for unescaped special characters in passwords, missing values for required fields (BW_DOMAIN, BW_INSTALLATION_ID, BW_INSTALLATION_KEY), or trailing whitespace after values. Run docker compose config to validate the compose file itself before starting.
3. Email verification never arrives
Error: No error in logs, but users never receive the verification email.
Fix: Check globalSettings__mail__smtp__ values in settings.env. For Gmail, you must use an App Password (not your account password) with 2FA enabled on the Google account. Confirm the SMTP port — Gmail requires port 587 with STARTTLS (ssl=false) or port 465 with SSL (ssl=true). Test by sending a password hint from the Bitwarden web vault.
4. Bitwarden app can't connect to self-hosted server
Error: "An error has occurred" or "Invalid URL" in the Bitwarden mobile or desktop app.
Fix: In the app, go to Settings → Self-hosted environment and enter the full URL including https:// — e.g., https://vault.yourdomain.com. The URL must not have a trailing slash. Confirm the TLS certificate is valid by visiting the URL in a browser first. If you're using a self-signed cert, the app will reject it by default.
5. Admin panel access denied
Error: "You are not authorized" when visiting /admin.
Fix: In settings.env, set [email protected] (comma-separated for multiple admins), then restart the container with docker compose restart. The email must match exactly — including case — the email used to register the Bitwarden account.
Frequently Asked Questions
Is self-hosting Bitwarden actually more secure than using bitwarden.com?
Self-hosting shifts the security responsibility to you — it's not inherently more or less secure than Bitwarden's cloud. Bitwarden's cloud servers have been independently audited (Cure53 penetration test, 2022; SOC 2 Type II). Your self-hosted instance is only as secure as your server hardening, firewall configuration, backup strategy, and update discipline. The end-to-end encryption model is identical in both cases: AES-256-CBC with PBKDF2-SHA256 key derivation at a minimum of 600,000 iterations, meaning neither Bitwarden nor your server ever sees plaintext credentials. The main advantage of self-hosting is data residency control, not encryption improvement.
What does Bitwarden self-hosting cost?
The self-hosted Bitwarden server software is free and open source under the AGPL-3.0 license. You pay only for your server infrastructure — a basic 2 GB RAM VPS runs $6–$12/month on providers like DigitalOcean, Linode, or Hetzner. Individual users on a self-hosted instance get most vault features free. Premium features (advanced MFA like WebAuthn/FIDO2, encrypted file attachments