Skip to content
Deploying / Vaultwarden

Vaultwarden

Installing the Vaultwarden template -- a password manager every Bitwarden client can use -- and inviting the first user.

Vaultwarden is a lightweight server for the Bitwarden protocol, so the official Bitwarden apps, browser extensions and CLI all work against it. The template runs it on SQLite, with everything in one volume.

Image vaultwarden/server:1.37.2-alpine
Port 80 inside the container, behind kamal-proxy
Health check /alive
Volumes data
Singleton yes

Before you start

  • A server that is registered, and a ready runner
  • A hostname for it. Bitwarden clients will not talk to a server without HTTPS, and Vaultwarden derives WebAuthn, email links and attachment URLs from its domain, so the environment is blocked until it has one. Leave the domain blank and install gives it a generated sslip.io hostname when the server has an IP – but passkeys and attachment links will be tied to that name, so enter your own domain up front if you mean to keep one.

Installing

Templates → Vaultwarden → Install. Give it a name, a runner, an environment, the server and the domain, e.g. vault.example.com. Vaultwarden asks for nothing else.

Install creates the app and does not deploy it. Point an A record for the domain at the server, then press Deploy.

What the install sets

Variable Value
DOMAIN https:// plus the environment’s first domain filled in at each deploy
SIGNUPS_ALLOWED false nobody can create an account on their own
INVITATIONS_ALLOWED true an admin invites people instead
IP_HEADER X-Forwarded-For without it, every login shares one rate-limit bucket
ADMIN_TOKEN 64 random letters and digits secret, generated once at install

Because DOMAIN is derived at deploy time, changing the domain means deploying again. Attachment links and passkeys registered under the old hostname will not follow it.

Inviting the first user

  1. Open Environment → Variables and read ADMIN_TOKEN. Secret values are shown to admins only.
  2. Go to https://<your domain>/admin and paste the token.
  3. Under Users, invite yourself by email.
  4. Open https://<your domain> and create an account with the invited address.

Invitations are normally sent by email. Without SMTP configured, Vaultwarden still records the invitation, and the invited address can register directly on the sign-up page. Nobody else can.

Sending email

For invitation emails, password hints and new-device alerts, add Vaultwarden’s SMTP settings as variables on the environment and deploy:

Variable Example
SMTP_HOST smtp.example.com plain
SMTP_FROM vault@example.com plain
SMTP_PORT 587 plain
SMTP_SECURITY starttls plain; force_tls for port 465
SMTP_USERNAME plain
SMTP_PASSWORD secret

Use a relay or your mail provider’s submission port. Sending straight out on port 25 is blocked on new Hetzner, DigitalOcean and AWS accounts.

Connecting clients

In any Bitwarden app, choose self-hosted on the sign-in screen and enter https://<your domain> as the server URL.

Bitwarden clients from 2026.8.0 onwards need Vaultwarden 1.37.2 or newer. If the image on the app is ever pinned lower, it shows up as clients that will not sync, not as an error anywhere in KamalCloud.

Hardening the admin page

The generated token works as it is, and Vaultwarden logs a warning that it is stored in plain text. To replace it with an Argon2 hash, open Environment → Shell and run:

docker exec -it $(docker ps -q --filter label=service=<app name> | head -1) /vaultwarden hash

Paste the $argon2id$... string it prints into ADMIN_TOKEN and deploy. KamalCloud writes $ into the secrets file escaped, so the hash arrives in the container unchanged. From then on, you sign in to /admin with the password you typed into hash, not with the string.

Settings saved from the /admin page go to config.json in the data volume and take precedence over variables. If a variable seems to be ignored, check whether it was saved there.

Data and backups

Everything – the SQLite database, attachments, sends, icons and the RSA keys that sign sessions – lives in the data volume, <app name>-data on the host. It is registered for backup at install and marked to stop containers, so Vaultwarden stands down for each backup and each restore. Both are consistent, and both are a short outage.

Set a schedule and a bucket on the volume. A password manager with no off-machine backup is one disk failure from losing every vault on it.

Upgrading

Change the image tag on the app and deploy. Read Vaultwarden’s release notes first: it upgrades the database on start, and it does not go back down.

Troubleshooting

  • Blocked: “Vaultwarden reads its own address” – the environment has no domain. Add one and deploy.
  • Clients sign in but will not sync – check the image is at least 1.37.2.
  • Every user is rate-limited at once – IP_HEADER has been removed or changed.
  • The admin token is rejected – after switching to a hash, sign in with the password, not with the hash.