Skip to main content

Vaultwarden

A lightweight self-hosted Bitwarden-compatible password manager server.

Vaultwarden is an unofficial Bitwarden server API implementation written in Rust that is compatible with all official Bitwarden clients. It runs with a fraction of the resources required by the official server. Self-hosting ensures your encrypted password vault never leaves your own infrastructure.

Alternatives considered

Cloud Hosted

ToolOpen SourceFree TierMonthly Cost
BitwardenYesLimitedFrom $10/mo (teams)
1PasswordNoNoFrom $3/user/mo
LastPassNoLimitedFrom $3/user/mo

Self Hosted

ToolOpen SourceFull FeaturesNotes
PassboltYesLimitedTeam-focused; CE is open source

Installation

Architecture

  • Deployment: Single vaultwarden deployment in the vaultwarden namespace
  • Image: ghcr.io/dani-garcia/vaultwarden:1.35.4-alpine (digest-pinned)
  • Database: CNPG PostgreSQL cluster with Longhorn-encrypted PVCs
  • Storage: Longhorn PVC (data, k8up.io/backup: "true") for attachments and config
  • Networking: ClusterIP service on port 80, HTTPRoute via public gateway

Security

  • Runs as runAsUser: 1000, runAsNonRoot: true, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities dropped
  • SIGNUPS_ALLOWED controls open registration; admin token controls admin panel access
  • Longhorn PVC and CNPG PVCs encrypted at rest

Updates

Managed by Renovate. Image is digest-pinned.

Data Management

  • Database: CNPG PostgreSQL cluster (Longhorn-encrypted PVCs) for vault data
  • PVC: data (Longhorn-encrypted, k8up.io/backup: "true") for attachments
  • Backups: k8up Schedule (schedule-hetzner) backs up Longhorn PVC to Hetzner S3 (workload-talos-vaultwarden-c27b0810) at @daily-random. CNPG annotated with k8up.io/backupcommand: pg_dump for consistent dumps.

User Management

No OIDC (Vaultwarden SSO requires Bitwarden-compatible paid client). Invitations and registration controlled by SIGNUPS_ALLOWED and SMTP-based invite emails.

Configuration Management

  • Admin token, registration settings, SMTP credentials, and domain from SOPS-encrypted secret
  • Database URL injected from CNPG-generated secret

Administration

Usage

Access the admin panel at /admin with the admin token to manage users and invitations. Install the Bitwarden browser extension or mobile app, point it and log in to access your vault. All vault data is end-to-end encrypted before leaving the client.

Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/talos/vaultwarden/README.md.

Cluster Deployment

Vaultwarden — Talos cluster

Cluster-specific notes only. General product info, "why we use it", and alternatives live in docusaurus/docs/apps/vaultwarden.mdx.

Deviations from defaults

Defaults live in docusaurus/docs/apps/vaultwarden.mdx — document anything this cluster does differently here, with a one-line reason.

Kubernetes Metadata
  • Image: ghcr.io/dani-garcia/vaultwarden:1.36.0-alpine@sha256:d3531610b486905943706b235e97159331801c6856e1367a93a5905e2b40f204
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app: vaultwarden
name: vaultwarden
namespace: vaultwarden
spec:
replicas: 1
selector:
matchLabels:
app: vaultwarden
ingress: public
strategy:
type: Recreate
template:
metadata:
labels:
app: vaultwarden
ingress: public
spec:
containers:
- env:
- name: ADMIN_TOKEN
valueFrom:
secretKeyRef:
key: vaultwardenAdminSecret
name: vaultwarden
- name: SIGNUPS_ALLOWED
value: 'false'
- name: LOG_LEVEL
value: debug
- name: DOMAIN
value: https://vaultwarden.web.kueber.eu
- name: SMTP_HOST
valueFrom:
secretKeyRef:
key: host
name: allinkl-smtp-credentials
- name: SMTP_FROM
valueFrom:
secretKeyRef:
key: from
name: allinkl-smtp-credentials
- name: SMTP_PORT
valueFrom:
secretKeyRef:
key: port
name: allinkl-smtp-credentials
- name: SMTP_SECURITY
value: force_tls
- name: SMTP_USERNAME
valueFrom:
secretKeyRef:
key: username
name: allinkl-smtp-credentials
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: allinkl-smtp-credentials
- name: DATABASE_URL
valueFrom:
secretKeyRef:
key: uri
name: cnpg-app
image: >-
ghcr.io/dani-garcia/vaultwarden:1.36.0-alpine@sha256:d3531610b486905943706b235e97159331801c6856e1367a93a5905e2b40f204
livenessProbe:
failureThreshold: 10
httpGet:
path: /alive
port: 80
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: vaultwarden
ports:
- containerPort: 80
name: web
protocol: TCP
readinessProbe:
failureThreshold: 10
httpGet:
path: /alive
port: 80
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
memory: 100Mi
requests:
cpu: 10m
memory: 100Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
startupProbe:
failureThreshold: 10
httpGet:
path: /alive
port: 80
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
volumeMounts:
- mountPath: /data
name: data
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
supplementalGroups:
- 1000
volumes:
- name: data
persistentVolumeClaim:
claimName: data