Setting up Vaultwarden#
*Vaultwarden is a lightweight, self-hosted implementation of the Bitwarden server API.
It lets you run your own password manager backend (instead of using Bitwarden’s cloud service), while still using official Bitwarden clients. It is written in Rust and designed to be resource-efficient, making it suitable for small servers or homelab setups.*
I wanted to show a few services, but for the most part after K3s is up and online the services are self explanitory through code. Each service is likely to vary in its own way, but I wanted to present a few.
hostPath v Local#
One of the biggest differences between this service and the others is the use of hostPath within the PersistentVolume.
Below is one of the better explanations I have seen with a table explaining the differences:
hostPath is a simple, node-specific mount that bypasses scheduler awareness, so Kubernetes does not enforce where Pods land relative to the data.
In contrast, a local PersistentVolume is modeled as a node-bound resource, requiring node affinity so the scheduler can place Pods on the correct node.
This makes local suitable for multi-node clusters, while hostPath is primarily a single-node or development convenience.
| Aspect | hostPath | local PersistentVolume |
|---|---|---|
| Scheduler awareness | No | Yes |
| Node affinity required | No | Yes |
| Multi-node safety | No | Yes (with constraints) |
| Typical usage | Dev / single-node / debugging | Production local storage |
| Data locality handling | Manual | Enforced by scheduler |
Based on the above information I will likely swap the other PersistentVolumes to this configuration as this setup will only be running on one host.
To Note and To Fix#
One of the things I want to fix is environment settings for the domain name. I need to be able to pass in the variables for the domain.
This will be something to fix in the near future.
apiVersion: v1
kind: PersistentVolume
metadata:
name: vaultwarden-pv
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: vaultwarden-local
local:
path: /var/lib/nik3sx/vaultwarden
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- l-nodet
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vaultwarden-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: vaultwarden-local
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vaultwarden
spec:
replicas: 1
selector:
matchLabels:
app: vaultwarden
template:
metadata:
labels:
app: vaultwarden
spec:
securityContext:
fsGroup: 1000
containers:
- name: vaultwarden
image: vaultwarden/server:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: WEBSOCKET_ENABLED
value: "true"
- name: SIGNUPS_ALLOWED
value: "false"
- name: DOMAIN
value: "https://test-vw.jmoore53.dev"
volumeMounts:
- name: vaultwarden-data
mountPath: /data
securityContext:
runAsUser: 1000
runAsGroup: 1000
volumes:
- name: vaultwarden-data
persistentVolumeClaim:
claimName: vaultwarden-pvc
---
apiVersion: v1
kind: Service
metadata:
name: vaultwarden
spec:
type: ClusterIP
selector:
app: vaultwarden
ports:
- port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vaultwarden
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
tls:
- hosts:
- test-vw.jmoore53.dev
secretName: boot-unlock-tls
rules:
- host: test-vw.jmoore53.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: vaultwarden
port:
number: 80