What is Vaultwarden?
Vaultwarden is an alternative server for the Bitwarden password manager, written in Rust and designed to run on very small machines. It is open source under the GPL-3.0 license and works with the official Bitwarden browser extensions, desktop apps and mobile apps. It is not affiliated with Bitwarden, Inc.
Requirements
- Any Linux server: 1 vCPU and 512 MB of RAM is plenty for a family or small team.
- Docker Engine and Docker Compose v2.
- A domain name and HTTPS. The web vault uses browser crypto APIs that only work in a secure context, so plain HTTP does not work except on
localhost.
Step 1: Prepare the server
This guide assumes Ubuntu 24.04 with Docker installed. If not, follow the Docker Engine install guide. Create a folder:
mkdir -p ~/vaultwarden && cd ~/vaultwarden
Before writing the Compose file, generate a hashed admin token. Vaultwarden supports Argon2 hashes for ADMIN_TOKEN, so the plain password is never stored on disk:
docker run --rm -it vaultwarden/server:latest /vaultwarden hash
Enter a strong admin password twice. The command prints a string starting with $argon2id$. Keep the password in your password manager. You will type it on the /admin page.
Step 2: Create the Docker Compose file
Save this as docker-compose.yml:
services:
vaultwarden:
image: vaultwarden/server:1.37.4
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: "https://vault.example.com"
SIGNUPS_ALLOWED: "true"
INVITATIONS_ALLOWED: "true"
SHOW_PASSWORD_HINT: "false"
ADMIN_TOKEN: "CHANGE_ME"
LOG_FILE: "/data/vaultwarden.log"
TZ: "Europe/London"
volumes:
- ./vw-data:/data
ports:
- "127.0.0.1:8080:80"
Replace CHANGE_ME with the Argon2 string from Step 1. Docker Compose treats $ as the start of a variable, so double every dollar sign in the hash ($argon2id$v=19$... becomes $$argon2id$$v=19$$...). If you prefer to keep it out of the Compose file, put ADMIN_TOKEN='...' in a .env file with single quotes and reference it as ${ADMIN_TOKEN}. DOMAIN must match the exact public URL, including https://, or attachments, WebAuthn and email links will break.
The port is bound to 127.0.0.1 on purpose: Vaultwarden should only be reached through the HTTPS proxy.
Step 3: Start and open the app
docker compose up -d
docker compose logs -f vaultwarden
Vaultwarden starts in a second or two. Complete Step 4, then open https://vault.example.com and click "Create account". This account is a normal user. The admin panel is separate, at https://vault.example.com/admin, and uses the admin password you hashed.
Once your own account and your family or team accounts exist, set SIGNUPS_ALLOWED: "false" and run docker compose up -d again. New users can then join only by invitation from an organization or the admin panel. Configure SMTP in the admin panel so invitations and two-step login emails work.
Step 4: Put it behind HTTPS
With Caddy on the host:
vault.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8080 {
header_up X-Real-IP {remote_host}
}
}
Caddy obtains the certificate automatically. Since version 1.29, Vaultwarden serves WebSocket notifications on the same port, so no extra route for port 3012 is needed. With Nginx Proxy Manager, point a proxy host at port 8080, request a Let's Encrypt certificate, and enable "Websockets Support".
Backups and upgrades
Everything lives in ./vw-data: the SQLite database db.sqlite3, attachments/, sends/, config.json (settings saved from the admin panel) and rsa_key* files. For a consistent database copy while the container runs, use the built-in backup command:
docker compose exec vaultwarden /vaultwarden backup
Then copy the whole vw-data folder off-site with restic, Borg or rclone, encrypted. Test a restore at least once.
Upgrade with:
docker compose pull && docker compose up -d
If you pinned a version, change the tag first after reading the release notes.
Troubleshooting
- Web vault shows a blank page or crypto error: you are on plain HTTP. Use your HTTPS domain.
- Admin page says the token is invalid: the
$signs in the Argon2 hash were not doubled in the Compose file, so Compose mangled the value. Check withdocker compose config. - Settings in
docker-compose.ymlare ignored: values saved in the admin panel go intoconfig.jsonand override environment variables. Change them in the panel or delete the key fromconfig.json. - Mobile app cannot log in: make sure the self-hosted server URL in the app exactly matches
DOMAIN.
Next steps
Enable two-step login for every account, set up an organization for shared passwords, add fail2ban rules against the Vaultwarden log, and schedule automatic encrypted backups.
Spotted something out of date? Tell us and we will update the guide.