Vaultwarden is a Bitwarden-compatible server that uses the official Bitwarden apps and browser extensions but keeps the vault on hardware you control. It is small enough to run on almost anything.

The compose file is four lines of nothing. The admin token has two traps that catch nearly everyone.

The token is a hash, not a password

ADMIN_TOKEN is the credential for the /admin panel. You do not invent a password for it; you generate an Argon2 hash and use that. You generate one by running the image's own hashing command and typing a password when prompted; the hash it prints is what goes in the configuration, and the password you typed is what you will type at the login page.

Write the password down somewhere safe first. It is not recoverable from the hash, which is the entire point of a hash.

And then the hash breaks your env file

An Argon2 hash is full of $ characters. Docker Compose reads $ as the start of a variable, so a hash pasted into a .env file gets silently mangled into something that will never match.

Every $ in the hash must be escaped as $$. Miss one and Compose silently corrupts the value, so the token never works and nothing tells you why. It is the most common reason a correctly generated token refuses to log in.

Turn the admin panel off when you are done

The /admin page is for one-time configuration such as SMTP and user invitations, not for daily use.

Once you have finished with it, DISABLE_ADMIN_TOKEN removes the panel rather than merely guarding it. An attack surface that does not exist does not need a strong password, and for a service holding every credential you own that trade is worth making. You can switch it back on for a few minutes when you next need it.

HTTPS is not optional, and DOMAIN is not cosmetic

Run this behind a reverse proxy with a real certificate. Password managers over plain HTTP are not a thing.

Set the DOMAIN variable to the full public address, including the https://. The server uses it to verify its own certificate, and a mismatch produces errors that look like client-side bugs.

One thing has become simpler: since version 1.29.0, WebSocket traffic shares the ordinary HTTP port. A large number of guides still tell you to add a separate proxy rule for /notifications/hub. On current versions that rule is unnecessary, and copying it from an older tutorial is a good way to spend an evening debugging a proxy that was already correct.

What the compose file actually needs

Four things, and nothing else is required to get a working server.

The image itself. A single named volume or bind mount for the data directory, which is where the database, the attachments and the keys live. A port published to localhost rather than to the world, because the reverse proxy in front is what should be reachable. And the environment: the admin token, the domain, and whether signups are open.

Pay attention to SIGNUPS_ALLOWED. By default anyone who can reach the page can create an account, which is not what you want on a server exposed to the internet. Turn it off and invite people instead, or turn it off after you have created your own account, which is the usual sequence for a household.

Two-factor, and where it actually lives

Vaultwarden supports the second factor methods the Bitwarden clients expect, and turning one on is done from the client rather than from the server. That surprises people who go looking for the setting in the admin panel.

The one worth thinking carefully about is where your second factor is stored. A time-based code kept in the same vault it protects is not a second factor, it is a longer password with extra steps. Put it somewhere else — a separate authenticator, a hardware key — or accept honestly that you have chosen convenience.

Updating without surprises

Pin a version rather than tracking the latest tag. An unattended pull that lands a major release on a password manager at three in the morning is a bad way to discover a breaking change.

Read the release notes before moving between major versions, and take a backup first. Vaultwarden's upgrades are usually uneventful, which is what lulls people into skipping the backup, right up until the one time they are not.

What to back up

The data directory holds the SQLite database, the attachments and the keys. That directory is the whole service. Copy it somewhere that is not the same machine, on a schedule, and encrypt the copy — it contains everything, and a backup of a password vault is as sensitive as the vault.

Then test the restore. Not "check the file exists": stand the service up from the backup, on a spare machine or a throwaway container, and log in. A backup that has never been restored is a hypothesis.

A password manager you cannot restore is a password manager you have not really got. This is the one service where the backup is more important than the uptime.

Where this comes from

Composed from the project's own documentation and configuration reference together with several independent published setup guides, cross-checked against each other on 31 August 2026. Version-specific details, the WebSocket change in particular, are the kind of thing that ages fastest — check the current documentation before copying any configuration, including this one.

Self-hosting a password manager is a real commitment. If the machine dies and the backup was never tested, the vault is gone. Anyone unwilling to own that should use a hosted service, and there is no shame in the choice.