Deploy Vaultwarden on Thalassa Cloud Kubernetes

Vaultwarden is a lightweight, self-hosted alternative to Bitwarden that provides secure password management with end-to-end encryption. By deploying Vaultwarden on Thalassa Cloud Kubernetes, a European cloud platform, you can run a production-ready password manager with full data sovereignty, ensuring your sensitive credentials remain under your control, hosted within the European Union, and comply with EU privacy regulations like GDPR.

This guide walks you through deploying Vaultwarden using Kubernetes manifests, configuring persistent storage, and setting up ingress with TLS certificates.

Prerequisites

Before deploying Vaultwarden, ensure you have a few things in place. First, you need a running Kubernetes cluster in Thalassa Cloud. If you’re new to Thalassa Cloud Kubernetes, see the Getting Started guide for cluster creation and basic setup.

  1. You’ll also need cluster access configured using kubectl. Use tcloud kubernetes connect to configure access, or set up kubeconfig manually. You’ll need cluster administrator permissions to create namespaces and deploy resources.
  2. For TLS certificates, you’ll need Cert Manager installed with Let’s Encrypt configured. See the Cert Manager and Let’s Encrypt guide for installation and configuration instructions.
  3. Finally, ensure your cluster has sufficient resources. Vaultwarden is lightweight but requires persistent storage for the database. Plan for at least one node with adequate resources. For information about storage options, see the Storage documentation and Persistent Volumes documentation.

Understanding Vaultwarden on Kubernetes

Vaultwarden is a Rust implementation of the Bitwarden server API that is compatible with all Bitwarden clients (desktop, mobile, browser extensions). It uses SQLite by default, making it simple to deploy without requiring a separate database. On Kubernetes, Vaultwarden benefits from persistent storage, automatic restarts, and easy scaling.

Vaultwarden stores all data encrypted at rest and in transit. The encryption keys are managed by the Bitwarden clients, ensuring that even if the server is compromised, your passwords remain encrypted. This makes it ideal for organisations requiring data sovereignty and compliance with privacy regulations.

Deploying Vaultwarden

Step 1: Create Namespace

Create a namespace for Vaultwarden resources with pod security labels:

apiVersion: v1
kind: Namespace
metadata:
  name: vaultwarden
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/warn: restricted

Apply the namespace:

kubectl apply -f namespace.yaml

Step 2: Create PersistentVolumeClaim

Vaultwarden requires persistent storage for its SQLite database. Create a PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: vaultwarden-data
  namespace: vaultwarden
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: tc-block

Apply the PersistentVolumeClaim:

kubectl apply -f pvc.yaml

Step 3: Create Configuration Secret

Create a Kubernetes Secret for Vaultwarden configuration. Generate a strong admin token:

openssl rand -base64 32

Create the secret:

apiVersion: v1
kind: Secret
metadata:
  name: vaultwarden-config
  namespace: vaultwarden
type: Opaque
stringData:
  ADMIN_TOKEN: "your-generated-admin-token-here"
  SIGNUPS_ALLOWED: "true"
  DOMAIN: "https://vaultwarden.yourdomain.com"

Security Configuration

  • Use a strong, randomly generated admin token
  • Set SIGNUPS_ALLOWED to false in production after creating your account
  • Configure DOMAIN with your actual domain for proper client configuration

Apply the secret:

kubectl apply -f secret.yaml

Step 4: Deploy Vaultwarden

Create a Deployment for Vaultwarden:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vaultwarden
  namespace: vaultwarden
  labels:
    app: vaultwarden
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vaultwarden
  template:
    metadata:
      labels:
        app: vaultwarden
    spec:
      containers:
      - name: vaultwarden
        image: vaultwarden/server:latest
        ports:
        - containerPort: 80
          name: http
        env:
        - name: ADMIN_TOKEN
          valueFrom:
            secretKeyRef:
              name: vaultwarden-config
              key: ADMIN_TOKEN
        - name: SIGNUPS_ALLOWED
          valueFrom:
            secretKeyRef:
              name: vaultwarden-config
              key: SIGNUPS_ALLOWED
        - name: DOMAIN
          valueFrom:
            secretKeyRef:
              name: vaultwarden-config
              key: DOMAIN
        - name: ROCKET_PORT
          value: "80"
        - name: DATA_FOLDER
          value: "/data"
        volumeMounts:
        - name: data
          mountPath: /data
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: vaultwarden-data

Apply the Deployment:

kubectl apply -f deployment.yaml

Step 5: Create Service

Create a Service to expose Vaultwarden:

apiVersion: v1
kind: Service
metadata:
  name: vaultwarden
  namespace: vaultwarden
spec:
  selector:
    app: vaultwarden
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  type: ClusterIP

Apply the Service:

kubectl apply -f service.yaml

Step 6: Configure Ingress with TLS

Create an Ingress resource with TLS configuration. This assumes Cert Manager is installed and configured:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: vaultwarden
  namespace: vaultwarden
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-body-size: "128m"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - vaultwarden.yourdomain.com
    secretName: vaultwarden-tls
  rules:
  - host: vaultwarden.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: vaultwarden
            port:
              number: 80

Ingress Controller

This example uses NGINX ingress controller. Adjust the ingressClassName and annotations based on your ingress controller configuration.

Apply the Ingress:

kubectl apply -f ingress.yaml

Accessing Vaultwarden

After deployment, access Vaultwarden through your configured domain. The admin panel is available at /admin using the admin token you configured.

Initial Setup

  1. Access Vaultwarden at https://vaultwarden.yourdomain.com
  2. Create your first account (if SIGNUPS_ALLOWED is true)
  3. After creating your account, set SIGNUPS_ALLOWED to false in the secret and restart the deployment
  4. Access the admin panel at https://vaultwarden.yourdomain.com/admin using your admin token

Client Configuration

Vaultwarden is compatible with all Bitwarden clients. Configure clients to use your self-hosted instance:

  1. Desktop/Mobile Apps: In settings, change the server URL to https://vaultwarden.yourdomain.com
  2. Browser Extensions: In extension settings, set the server URL to your domain

Backup and Recovery

Vaultwarden stores all data in a SQLite database. To back up:

# Create a backup
kubectl exec -n vaultwarden deployment/vaultwarden -- \
  sqlite3 /data/db.sqlite3 ".backup /data/backup-$(date +%Y%m%d).db"

# Copy backup from pod
kubectl cp vaultwarden/vaultwarden-<pod-name>:/data/backup-20240115.db ./backup.db

For automated backups, consider using a CronJob or integrating with Thalassa Cloud’s snapshot capabilities for the persistent volume.

References