Self-Host Vaultwarden (Bitwarden) with Docker Compose
Run your own password manager with Vaultwarden, a lightweight Bitwarden-compatible server. A working Docker Compose file, HTTPS setup, the admin panel, and the security settings that matter.
Vaultwarden is an unofficial, Bitwarden-compatible server written in Rust. It speaks the same API as the official Bitwarden server, which means every official Bitwarden client — browser extensions, mobile apps, desktop apps, the CLI — connects to it without modification. The difference is footprint: Vaultwarden runs in a single small container, comfortably on a Raspberry Pi, and unlocks features (TOTP storage, attachments, organizations) that Bitwarden gates behind a paid plan on their hosted service.
This guide gets Vaultwarden running in Docker Compose, puts it behind HTTPS (which it requires to be fully functional), and locks down the settings that matter for a password manager you’re trusting with your entire digital life.
Why HTTPS Is Non-Negotiable Here
A password manager is the one service you should never run over plain HTTP. Two concrete reasons:
- The Bitwarden browser extension and mobile apps refuse to connect to a non-HTTPS server (except
localhost). This isn’t optional — the Web Crypto APIs the clients depend on are only available in secure contexts. - Vaultwarden itself needs to know it’s being served over HTTPS for attachments and other features to work correctly. The official docs state plainly that “vaultwarden needs to know it’s https to work properly with attachments.”
So this guide treats a reverse proxy as part of the install, not an afterthought.
Prerequisites
- Docker and Docker Compose installed
- A domain name (or subdomain) you can point at your server, e.g.
vault.yourdomain.com - A reverse proxy for TLS. We’ll use Traefik; Caddy and Nginx Proxy Manager work equally well.
Step 1: Create the Service Directory
mkdir -p ~/services/vaultwarden
cd ~/services/vaultwarden
All of Vaultwarden’s state — the SQLite database, attachments, keys — lives in one data directory, which makes backups trivial.
Step 2: Write the Compose File
Create ~/services/vaultwarden/docker-compose.yml. This is the minimal configuration from the official wiki, adapted with Traefik labels for HTTPS:
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
- DOMAIN=https://vault.yourdomain.com
- SIGNUPS_ALLOWED=true
volumes:
- ./vw-data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`vault.yourdomain.com`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
networks:
- traefik-proxy
networks:
traefik-proxy:
external: true
The important details:
- The container listens on port 80 internally. That’s why the Traefik label is
loadbalancer.server.port=80— Traefik terminates TLS and forwards to port 80 inside the container. There’s no published port on the host because Traefik handles all inbound traffic. DOMAINmust be the fullhttps://URL you’ll access Vaultwarden at. Set it correctly from the start; some features misbehave if it’s wrong.SIGNUPS_ALLOWED=truelets you register the first account. You will turn this off in the next step../vw-data:/datais the single directory holding everything. Back it up.
Step 3: Start It and Create Your Account
docker compose up -d
docker compose logs -f
Once the logs show Vaultwarden listening, visit https://vault.yourdomain.com. You should see a valid certificate (the padlock in your browser) and the Bitwarden web vault login screen. Click Create account and register your user. This first account is yours.
Step 4: Disable Open Signups
This is the step people forget, and it’s the one that matters most. With SIGNUPS_ALLOWED=true, anyone who finds your server URL can create an account on it. Once your own account exists, turn registration off.
Edit the Compose file:
environment:
- DOMAIN=https://vault.yourdomain.com
- SIGNUPS_ALLOWED=false
Then recreate the container:
docker compose up -d
Now the registration form is closed. If you need to add family members later, you’ll invite them through an organization, or briefly flip the flag back on, register them, and turn it off again.
Step 5: Enable the Admin Panel (Carefully)
Vaultwarden has an admin page at /admin for managing users, organizations, and server settings. It’s disabled by default, and you enable it by setting an ADMIN_TOKEN. Generate a strong token — Vaultwarden recommends an Argon2 PHC hash, which you can generate with the binary itself:
docker exec -it vaultwarden /vaultwarden hash
This prompts for a password and prints an Argon2 hash string. Put that hash in your environment:
environment:
- DOMAIN=https://vault.yourdomain.com
- SIGNUPS_ALLOWED=false
- ADMIN_TOKEN=$argon2id$v=19$m=... # the hash from the command above
Recreate the container and visit https://vault.yourdomain.com/admin. You’ll be asked for the password you hashed. Because the stored value is a hash rather than the plaintext token, an attacker who reads your Compose file or environment can’t immediately use it.
If you don’t need the admin panel, leave ADMIN_TOKEN unset and the page stays disabled — one less thing exposed.
Step 6: Hardening the Deployment
A few settings worth applying once the basics work:
Restrict the admin page further. Even with a token, consider IP-allowlisting /admin at the reverse proxy, or only enabling the token when you actively need it. The admin panel can change server-wide settings.
Turn on push notifications (optional). Mobile clients can use Bitwarden’s push relay so changes sync instantly. This requires registering for an installation ID and key at the Bitwarden site and setting PUSH_ENABLED, PUSH_INSTALLATION_ID, and PUSH_INSTALLATION_KEY. It’s optional; without it, clients still sync on a poll.
Disable invitations and password hints you don’t want. Variables like INVITATIONS_ALLOWED and SHOW_PASSWORD_HINT control behaviors you may want off for a single-user instance.
Keep it off the public internet if you can. As with any high-value service, the most robust option is to reach Vaultwarden over a VPN (WireGuard or Tailscale) rather than publishing it. The clients still need HTTPS, but you can serve a valid certificate to a private hostname. If you do publish it, the strong master password and the closed-signups setting are doing the heavy lifting — make sure both are right.
Step 7: Back Up the Vault
Vaultwarden’s entire state is in the vw-data directory. A backup is a copy of that directory. The cleanest approach is to stop the container briefly, copy the data, and start it again so the SQLite database isn’t mid-write:
cd ~/services/vaultwarden
docker compose stop
tar czf vaultwarden-backup-$(date +%F).tar.gz vw-data
docker compose start
For a hands-off setup, the community vaultwarden/server ecosystem includes backup sidecar containers that snapshot the SQLite database safely while it’s running. Whatever you choose, follow a real backup discipline — see our notes on 3-2-1 backups ↗. Losing this database means losing every password it holds.
Step 8: Updating
docker compose pull
docker compose up -d
Vaultwarden releases frequently. Because it tracks the Bitwarden API, keeping it current also keeps it compatible with the latest official clients. The vw-data volume persists across updates, so this is a safe, routine operation — just make sure your backup ran first.
The Payoff
You now have a password manager that you control end to end, compatible with the polished official Bitwarden clients, with the premium features unlocked, running in a container small enough to share a Raspberry Pi with three other services. The most security-sensitive service in your homelab is also one of the simplest to run — provided you get HTTPS and the signup flag right, which you now have.
Sources
Related
Self-Host Immich (Photos) with Docker Compose
Replace Google Photos with Immich, a self-hosted photo and video backup server. The official Docker Compose stack, the .env file, mobile auto-backup, hardware acceleration, and reverse-proxy notes.
Self-Host Jellyfin with Docker Compose
Run your own media server with Jellyfin and Docker Compose. A working Compose file, hardware transcoding setup, library configuration, and reverse-proxy notes for streaming your media anywhere.
Best Docker Compose Apps for Your Homelab in 2026
The 20 best services to run in Docker on your home server, with ready-to-use Compose snippets and honest assessments of setup complexity and ongoing maintenance.