Longhorn provides the longhorn StorageClass used by Vault,
Authentik, Nextcloud, Immich, and PostgreSQL. Every PVC backed by Longhorn
has recurring snapshot and backup jobs enabled via annotation — backups
land on the NAS over NFS.
01 Configuration
The key deviation from Longhorn defaults is replica count 1. With a single node there is no second node to place a replica on — leaving the default at 3 would cause volumes to stay in a degraded state. Everything else is standard.
| Property | Value |
|---|---|
| Namespace | longhorn-system |
| Default replica count | 1 — single-node cluster; replication has no benefit |
| Backup target | NFS — nfs://172.20.20.2:/var/nfs/shared/backups |
| Backup poll interval | 300 seconds |
| StorageClass | longhorn (default for stateful apps) |
| UI | longhorn.in.alybadawy.com (LAN and VPN only) |
02 Backup annotations
Longhorn's recurring backup jobs are opt-in per PVC via an annotation. Any
PVC with
recurring-job-group.longhorn.io/default: enabled participates
in the default backup schedule. All stateful app PVCs in this cluster
carry this annotation.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vault-data-lh
namespace: security
labels:
app.kubernetes.io/name: vault
annotations:
recurring-job-group.longhorn.io/default: enabled # ← joins default backup schedule
spec:
accessModes: [ReadWriteOnce]
storageClassName: longhorn
resources:
requests:
storage: 5Gi
recurring-job-group.longhorn.io/default: enabled,
its volume will not be backed up. Check the Longhorn UI under Volumes to
verify a new volume shows the recurring job attached.
03 Restoring volumes on a rebuild
When rebuilding from scratch, Longhorn PVCs are restored manually via the Longhorn UI before ArgoCD deploys stateful apps. This is Step 8 of the provisioning sequence:
-
provision/restore-volumesinstalls Longhorn and opens the UI via port-forward onlocalhost:9000. - In the UI: Backup → select each volume → Restore → create PV/PVC with the same name.
- The script waits for confirmation, then exits.
-
When
activate-gitops.shdeploys stateful apps, they bind to the pre-created PVCs instead of triggering dynamic provisioning.
spec.volumeName pointing at the specific Longhorn volume.
When ArgoCD syncs the app, the Deployment finds the PVC already bound —
no data loss, no re-initialisation.
04 Access
# UI via ingress (once ingress-nginx and cert-manager are live)
# → https://longhorn.in.alybadawy.com
# UI via port-forward (bootstrap / before ingress is live)
$ kubectl port-forward -n longhorn-system svc/longhorn-frontend 9000:80
# open http://localhost:9000
# check volume status from CLI
$ kubectl get pvc -A
$ kubectl get volumes.longhorn.io -n longhorn-system