Handing your entire password vault to a third party cloud service is a leap of trust many people would rather not make — especially after the last decade of br…
Handing your entire password vault to a third-party cloud service is a leap of trust many people would rather not make — especially after the last decade of breach headlines. Vaultwarden is a lightweight, open-source, Bitwarden-compatible server that lets you run your own password manager backend, using the same polished official Bitwarden apps and browser extensions you'd otherwise point at someone else's infrastructure. This guide sets up a secure, self-hosted instance from scratch, behind HTTPS, in under an hour.
Why Vaultwarden Instead of the Official Bitwarden Server
Bitwarden's official self-hosted server is a heavier, multi-container .NET stack meant for larger deployments. Vaultwarden is a from-scratch Rust reimplementation of the same API, built specifically to be lightweight enough to run comfortably on a Raspberry Pi or a $5 VPS, while staying fully compatible with every official Bitwarden client. For a personal or small-team setup, it's the far more practical choice.
Prerequisites / What You'll Need
- A Linux server or VPS with Docker and Docker Compose installed
- A domain name (or subdomain) pointed at that server — Bitwarden clients require HTTPS to function, no exceptions
- Basic familiarity with Docker Compose
- 45–60 minutes
Step 1: Set Up DNS
Before anything else, point a subdomain at your server's IP — for example vault.yourdomain.com — via an A record in your DNS provider. This needs to propagate before you can get a certificate in a later step, so do it first and let it sit while you work through the rest.
Step 2: Create the Docker Compose Setup
Create a project directory and a docker-compose.yml:
services:
vaultwarden:
image: vaultwarden/server:latest
restart: unless-stopped
environment:
DOMAIN: "https://vault.yourdomain.com"
SIGNUPS_ALLOWED: "false"
ADMIN_TOKEN: ${ADMIN_TOKEN}
volumes:
- vw_data:/data
expose:
- "80"
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- vaultwarden
volumes:
vw_data:
caddy_data:
caddy_config:
A few deliberate choices here:
SIGNUPS_ALLOWED: "false" — once you've created your own account, this locks the door behind you so a stranger who finds your vault URL can't self-register. This is one of the most important settings in the entire setup.
- Caddy as the reverse proxy — unlike Nginx, Caddy handles Let's Encrypt HTTPS certificates automatically with essentially zero configuration, which makes it the simplest option for a single-service setup like this.
expose instead of ports for Vaultwarden — it's only reachable through Caddy, never directly.
Step 3: Generate an Admin Token
The admin panel (used for managing users, disabling signups later, etc.) needs a secure token. Generate one:
openssl rand -base64 48
Create a .env file in the same directory:
ADMIN_TOKEN=<paste the generated value here>
Add .env to .gitignore if this directory is version-controlled — this token grants full administrative access to your vault server.
Step 4: Configure Caddy for Automatic HTTPS
Create a Caddyfile:
vault.yourdomain.com {
reverse_proxy vaultwarden:80
}
That's genuinely the entire config. Caddy will automatically request and renew a Let's Encrypt certificate for the domain the first time it starts, as long as DNS is already pointing at the server and ports 80/443 are reachable.
Step 5: Launch the Stack
docker compose up -d
Watch the logs on first boot to confirm the certificate issues successfully:
docker compose logs -f caddy
You're looking for a line confirming the certificate was obtained — if DNS hasn't propagated yet, this step will fail and retry automatically, so give it a few minutes if needed.
Step 6: Create Your Account
Visit https://vault.yourdomain.com in a browser. You should see the Bitwarden web vault login screen, served over valid HTTPS. Create your account here — since SIGNUPS_ALLOWED is still true at this point (the default), this is the one window where registration is open.
Step 7: Lock Down Signups
Now that your account exists, close the door:
nano .env
Update:
SIGNUPS_ALLOWED=false
Restart to apply:
docker compose up -d
From this point forward, nobody — including you, on a second attempt — can create a new account without you re-enabling this flag. If you need to add a household or team member later, use the admin panel to invite them instead of reopening signups.
Step 8: Connect the Official Bitwarden Apps
Install the official Bitwarden browser extension or mobile app. Before logging in, go to the extension's settings and change the server URL:
- Open the Bitwarden extension → Settings (gear icon) → Self-hosted
- Enter your server URL:
https://vault.yourdomain.com
- Log in with the account you just created
From here, it behaves exactly like the cloud-hosted version — autofill, generator, sync across devices — just talking to your own server instead of Bitwarden's.
Step 9: Enable Two-Factor Authentication
With your vault holding literally every password you own, protecting the master login itself matters enormously. In the web vault:
- Go to Settings → Security → Two-step Login
- Enable an authenticator app (TOTP) method
- Save the recovery code somewhere separate from the vault itself — if you lose 2FA access and can't get into your vault, that code is the only way back in
Common Pitfalls / Troubleshooting
- Certificate never issues. Almost always DNS hasn't finished propagating, or ports 80/443 aren't actually reachable from the internet (check your firewall/VPS provider's network rules). Verify with
dig vault.yourdomain.com from an external machine.
- Leaving
SIGNUPS_ALLOWED=true after setup. This is the single most important step to not skip — an open signup page on a vault server is an open invitation.
- Losing the
ADMIN_TOKEN. Without it, you can't reach the admin panel to manage settings later. Store it in your (now-working) password manager, ironically, or another secure location.
- Forgetting the 2FA recovery code. If you enable TOTP and later lose your authenticator device without a saved recovery code, regaining access requires manual database intervention — genuinely painful. Save it before you need it.
- Running this without backups. Your entire password vault lives in the
vw_data Docker volume. Back it up like you would any other critical data — see a dedicated backup setup (rsync, or offsite sync) for this volume specifically.
- Exposing the admin panel publicly without extra protection. Consider restricting
/admin to your home IP or VPN via a Caddy matcher, since the admin token alone is a single point of failure if it ever leaks.
Wrapping Up
You now have a fully self-hosted, standards-compliant password manager, reachable from every device via the official Bitwarden apps, with HTTPS handled automatically and no monthly subscription. The tradeoff is that you're now responsible for keeping it patched, backed up, and online — which is exactly why the setup above leans on tools (Docker Compose, Caddy) that minimize ongoing maintenance. From here, sensible next steps include wiring the vw_data volume into the rsync backup pattern for offsite redundancy, restricting the /admin path behind an IP allowlist or your WireGuard VPN, and enabling Vaultwarden's built-in email notifications for new device logins if you configure an SMTP relay.
Further Reading