Skip to main content

Overview

Vaultwarden is a lightweight, self-hosted password manager server (AGPL-3.0) that is compatible with all official Bitwarden clients: browser extensions, desktop apps, and mobile apps. This template deploys one stateful Vaultwarden workload with its SQLite database on a persistent volume, serving the web vault, the client APIs, and live sync over HTTPS on the canonical *.cpln.app endpoint. Vault contents are end-to-end encrypted with each user’s master password, so the server never holds readable passwords. Registration is open on a fresh install so you can create your first accounts immediately; turn it off once your users are on board.
This template does not create a GVC. It deploys into an existing GVC that you already have.

What Gets Created

There is no external database: Vaultwarden talks only to its own volume and, when configured, your mail server.

Prerequisites

None for a default install. The two secrets below are optional, each enables one feature, and each must exist before you set its values key. Secrets are org-level, so no GVC flag is involved.
1

Optional - admin panel token

The /admin panel stays disabled unless you provide an opaque secret holding the argon2 hash of an admin token you choose. Generate the hash with the Vaultwarden binary itself; it prompts for the token twice and prints a string starting with $argon2:
Store the full output as-is. Do not double the $ signs; that escaping is for docker-compose files only and breaks the login here. The single quotes below keep the shell from expanding them:
Keep the plaintext token somewhere safe: it is what you type into the admin panel, and the hash cannot be reversed. Set admin.tokenSecretName to this name.
2

Optional - SMTP authentication

Only needed when you configure smtp.host and your mail server requires a login. Create a dictionary secret with exactly two keys, username and password:
Set smtp.authSecretName to this name.
A secret named in values but missing wedges the deployment silently. cpln helm install still succeeds and the workload never becomes ready. cpln logs returns nothing at all, because the container never ran. The only place the reason appears is status.versions[].message, which names the missing secret:
Note this is get-deployments; plain cpln workload get has no versions key. Create the missing secret and the deployment recovers on its own, or force a redeployment to skip the wait:
Backups are scheduled volume set snapshots managed by the platform and need no bucket or cloud account. See Backing Up.

Installation

A default install needs no values at all:
Or follow the instructions for your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Vaultwarden Instance

The resources block exposes both a reservation and a limit, so the limit is named maxCpu / maxMemory. A values file that still carries the bare cpu or memory keys is refused at render with a message telling you to rename them (see Upgrading from 1.0.0). Size volumeset.capacity for your attachments and sends as well as the database.

Backup

Scheduled, crash-consistent snapshots of the data volume, managed by the platform. backup.enabled: false removes the schedule only; backup.retention still applies, and a final snapshot is taken when the release is uninstalled either way. See Backing Up.

Sign-ups and Invitations

With signups.allowed: true, anyone who can reach the public endpoint can create an account. After your first accounts exist, set signups.allowed: false, or keep self-service registration for your own company with signups.domainsWhitelist. signups.verify: true is refused at render unless smtp.host is set.

Admin Panel

Set admin.tokenSecretName to the opaque secret from Prerequisites to enable /admin. Empty (the default) leaves the panel disabled. Settings saved in the panel take precedence over Helm values from then on; see Important Notes.

SMTP

Email powers invitations, registration verification, and email-based two-step login. The chart refuses to render when smtp.host is set without smtp.from, or when smtp.authSecretName is set without smtp.host.

Privacy

Domain

When empty, the start script sets Vaultwarden’s DOMAIN to the workload’s canonical endpoint at boot, so attachment links, email links, and passkeys bind to the right URL with no configuration. Set customDomain only when you serve the vault on your own domain, and decide before users register passkeys; see Important Notes.

Access

Bitwarden clients require HTTPS, which the canonical endpoint provides, so keep publicAccess.enabled: true unless you front the vault another way. With it disabled, external requests are refused at the edge. Access changes are not instantaneous; re-test after a pause rather than concluding a knob did not work.

Connecting

The web vault, the client APIs, and the admin panel are all served on the Vaultwarden workload’s canonical endpoint, which is public by default (publicAccess.enabled: true). Read it from status.canonicalEndpoint:
Verify the server is up before you open the vault:
A 200 means Vaultwarden is serving. With publicAccess.enabled: false, Bitwarden clients cannot reach the server, because they need an HTTPS URL. You can still check the server from your machine through a port-forward:
Then run curl -s http://localhost:8080/alive in a second terminal.

First Run

There is no setup wizard; the first user simply registers.
1

Create your account

Open https://CANONICAL_ENDPOINT, choose Create account, and set a strong master password. The master password encrypts your vault and cannot be reset by anyone; without SMTP configured, password-hint emails are off too.
2

Connect your Bitwarden clients

In each Bitwarden app or browser extension, select the self-hosted option on the login screen and enter https://CANONICAL_ENDPOINT as the server URL, then sign in with the account you just created.
3

Lock down registration

Once your users have accounts, upgrade the release with signups.allowed set to false, or restrict registration with signups.domainsWhitelist. While registration is open, anyone who can reach the public endpoint can create an account. See the CLI guide for upgrading a release.

Operations

Backing Up

On the cron schedule in backup.schedule (default daily at 03:00 UTC), the platform takes a crash-consistent snapshot of RELEASE_NAME-vaultwarden-data; SQLite recovers cleanly from one through its write-ahead log. Snapshots are pruned after backup.retention (default 7 days), and a final snapshot is always taken when the release is uninstalled. A snapshot covers everything on the volume: the database, attachments, sends, and the session-signing key.
Snapshots live in the platform storage layer alongside the volume, not off-site. They protect against corruption and accidental changes, but they are not an off-platform copy; for that, users can export their own vaults from the web vault or a Bitwarden client.

Restoring a Backup

Restore is in place on the release’s own volume set: the platform provisions a fresh volume from the chosen snapshot and swaps it in, and the single replica restarts to remount it. An in-place snapshot restore recovered an intact vault when this template was tested; the command flags below are taken from the CLI help and have not been exercised against a live install since. Rehearse on a throwaway release before you depend on it.
Restoring reverts the volume to the snapshot: every vault change made after it is lost, and the vault is unavailable while the only replica restarts.
1

Find the snapshot

List the snapshots and note the name and location of the one you want:
2

Restore it in place

The volume set has one volume per replica and this workload has exactly one, so the volume index is 0:
3

Verify

Once the workload is ready again, sign in to the web vault and confirm your items are present and decrypt correctly.

Rotating the Admin Token

The admin token is read from your opaque secret when the replica starts. To change it, generate a new hash as in Prerequisites, apply the whole secret with the new value, then force a redeployment:
Skipping the redeployment produces no error: the old token simply keeps working until the replica restarts. The same apply-then-redeploy sequence rotates the SMTP credentials in SMTP_AUTH_SECRET_NAME.

Upgrading from 1.0.0

Version 1.1.0 renames the resource limit keys: resources.cpu is now resources.maxCpu and resources.memory is now resources.maxMemory, so it is no longer ambiguous which number is the limit. Rename those two keys in your values before upgrading. An upgrade that still carries the old names is refused at render, before any resource is touched. Nothing else changed, and the volume and its data are unaffected.

Scaling and Availability

Vaultwarden runs as exactly one replica on SQLite, and there is deliberately no replicas knob. Upstream does not support running multiple instances: replicas cannot share the data volume or notify each other of changes, and on this platform each stateful replica would get its own volume, so a second replica would serve a different, empty vault. Scale vertically by raising resources.maxCpu and resources.maxMemory, keeping maxCpu within 4:1 of minCpu. Any restart, from an upgrade that changes the container, a forced redeployment, or a replica being rescheduled, is a short full outage while the new replica starts and the volume reattaches. Data is not at risk, because the same volume reattaches. Bitwarden apps keep a local copy of the vault, so users can still read their items during the outage.

Troubleshooting

Symptom: cpln helm install reported success, cpln logs returns nothing, and cpln workload get-deployments RELEASE_NAME-vaultwarden --gvc GVC_NAME -o yaml shows The secret ADMIN_TOKEN_SECRET_NAME no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. (or the same for your SMTP secret) under status.versions[].message.Cause: admin.tokenSecretName or smtp.authSecretName names a secret that does not exist.Fix: Create it (see Prerequisites), or clear the value and upgrade the release. The deployment recovers on its own once the secret exists; cpln workload force-redeployment RELEASE_NAME-vaultwarden --gvc GVC_NAME skips the wait.
Symptom: vaultwarden: resources.cpu was RENAMED to resources.maxCpu. (or the same for resources.memory).Cause: Your values use the 1.0.0 key names.Fix: Rename them to resources.maxCpu and resources.maxMemory (see Upgrading from 1.0.0).
Symptom: vaultwarden: smtp.from is required when smtp.host is set — the sender address for outgoing mail, or vaultwarden: signups.verify requires smtp.host, or vaultwarden: smtp.authSecretName is set but smtp.host is empty.Cause: The SMTP settings are incomplete.Fix: Set smtp.host and smtp.from together; set signups.verify and smtp.authSecretName only when smtp.host is set.
Symptom: /admin says the token is invalid.Cause: Either the hash was stored with doubled $ signs (docker-compose escaping), or you typed the hash instead of the plaintext token.Fix: Sign in with the plaintext token you chose when generating the hash. If that still fails, re-apply the secret with the raw $argon2... string and force a redeployment (see Rotating the Admin Token).
Symptom: You upgraded the release with a new setting (for example signups.allowed: false) and Vaultwarden still behaves the old way.Cause: Saving settings in the admin panel writes /data/config.json, which takes precedence over the environment the chart sets from values.Fix: Change the setting in the admin panel instead, or remove the file and restart to return control to values:
Symptom: Passkey or security-key sign-in stops working after you set or changed customDomain.Cause: WebAuthn credentials are bound to the exact URL they were registered on.Fix: Users re-register their passkeys on the new URL. Choose the final domain before users register passkeys.

Important Notes

  • Turn off open registration after onboarding. Sign-ups are open by default; set signups.allowed: false or use signups.domainsWhitelist.
  • Master passwords are unrecoverable. Vault contents are end-to-end encrypted; a forgotten master password means a lost vault.
  • Admin panel settings override Helm values. Saving in /admin writes /data/config.json, which wins over values from then on.
  • Store the admin token hash raw. No doubled $ signs, and sign in with the plaintext token, not the hash.
  • Do not change the domain casually. Passkeys are bound to the exact URL and break until re-registered.
  • Rotating a secret needs a forced redeployment. The old admin token or SMTP password keeps working until the replica restarts.
  • Single instance only. Every restart is a short outage; see Scaling and Availability.
  • Snapshots are not an off-platform copy. Uninstalling deletes the volume set after a final snapshot; your own secrets survive.

External References

Vaultwarden on GitHub

Upstream source repository

Enabling the Admin Page

How to configure and secure the /admin panel

SMTP Configuration

Configure outbound email for invites and verification

Hardening Guide

Upstream recommendations for locking down an instance

Vaultwarden Template

View the source files, default values, and chart definition