Je homelab draait je GitLab, je wachtwoorden, je foto’s, je home automation. Wat gebeurt er als de disk faalt?

Als je die vraag niet met vertrouwen kunt beantwoorden, heb je geen backups. Je hebt hoop.

De 3-2-1 regel bestaat al decennia omdat hij werkt. Drie kopieën, twee verschillende media, één offsite. Hier is hoe je het daadwerkelijk implementeert.

De 3-2-1 Regel Uitgelegd

flowchart TD
    subgraph rule["3-2-1 Backup Regel"]
        Data["Originele Data"]

        subgraph three["3 Kopieën"]
            C1["Kopie 1<br/>(Origineel)"]
            C2["Kopie 2<br/>(Lokale Backup)"]
            C3["Kopie 3<br/>(Offsite)"]
        end

        subgraph two["2 Media Types"]
            M1["NVMe/SSD"]
            M2["HDD/NAS"]
        end

        subgraph one["1 Offsite"]
            Off["Cloud/Remote"]
        end
    end

    Data --> C1
    Data --> C2
    Data --> C3
    C1 --> M1
    C2 --> M2
    C3 --> Off

Waarom Drie Kopieën?

  • Kopie 1: Je live data (origineel)
  • Kopie 2: Lokale backup (snelle restore)
  • Kopie 3: Offsite backup (disaster recovery)

Eén kopie is geen backup. Twee kopieën kunnen allebei falen in dezelfde ramp (brand, overstroming, ransomware). Drie kopieën met separatie geeft je echte resilience.

Waarom Twee Media Types?

Verschillende failure modes:

  • SSDs kunnen stilletjes falen (bit rot)
  • HDDs hebben mechanische failures
  • RAID is geen backup (beschermt tegen drive failure, niet data corruptie)

Verschillende media betekent dat verschillende failure scenarios niet alle kopieën uitschakelen.

Waarom Eén Offsite?

Je huis kan afbranden. Je buurt kan overstromen. Je hele stad kan stroom verliezen. Offsite betekent overleven zelfs wanneer alles lokaal weg is.

Wat Back-uppen

Kritiek (Dagelijkse Backup)

DataWaaromTool
DatabasesKan niet herstellenpg_dump, Velero
Secrets/credentialsSecurity kritiekVault export, External Secrets
ConfiguratieSysteem staatGit (al offsite)
Persoonlijke bestandenOnvervangbaarRestic

Belangrijk (Wekelijkse Backup)

DataWaaromTool
Container imagesRebuild kost tijdRegistry backup
Persistent volumesStateful workloadsLonghorn/Velero
Logs (gecomprimeerd)ForensicsLoki snapshots

Herbouwbaar (Niet Back-uppen)

  • Basis OS (herinstalleer van ISO)
  • Gedownloade packages (opnieuw downloaden)
  • Gecachete data (regenereert)
  • Tijdelijke bestanden

Verspil geen backup ruimte aan data die je kunt herstellen.

Backup Tools

Restic: File-Level Backups

Restic is mijn go-to voor file backups. Het is snel, versleuteld, dedupliceert, en ondersteunt meerdere backends.

# Initialiseer repository
restic init --repo /mnt/backup/restic

# Of met S3 backend
restic init --repo s3:s3.amazonaws.com/my-bucket

# Backup een directory
restic backup /home/user/documents

# Backup met exclusies
restic backup /data \
  --exclude="*.tmp" \
  --exclude=".cache" \
  --exclude="node_modules"

# Lijst snapshots
restic snapshots

# Restore
restic restore latest --target /restore/location

Geautomatiseerde Restic Backups

#!/bin/bash
# /usr/local/bin/backup.sh

export RESTIC_REPOSITORY="s3:s3.eu-west-1.amazonaws.com/homelab-backups"
export RESTIC_PASSWORD_FILE="/etc/restic/password"
export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"

# Backup
restic backup /data/important \
  --exclude-caches \
  --tag homelab \
  --tag daily

# Prune oude snapshots (bewaar 7 dagelijks, 4 wekelijks, 12 maandelijks)
restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 12 \
  --prune

# Check repository integriteit
restic check

Cron job:

# /etc/cron.d/restic-backup
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/restic-backup.log 2>&1

Velero: Kubernetes Backups

Velero back-upt Kubernetes resources en persistent volumes.

# Installeer Velero met S3 backend
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.8.0 \
  --bucket velero-backups \
  --backup-location-config region=eu-west-1 \
  --secret-file ./credentials-velero \
  --use-volume-snapshots=true \
  --snapshot-location-config region=eu-west-1

Geplande Backups

apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-backup
  namespace: velero
spec:
  schedule: "0 3 * * *"
  template:
    includedNamespaces:
      - production
      - gitlab
      - monitoring
    excludedResources:
      - events
      - pods
    ttl: 720h  # Bewaar 30 dagen
    storageLocation: default
    volumeSnapshotLocations:
      - default

Restore vanuit Velero

# Lijst backups
velero backup get

# Beschrijf een backup
velero backup describe daily-backup-20260518030000

# Restore gehele backup
velero restore create --from-backup daily-backup-20260518030000

# Restore specifieke namespace
velero restore create --from-backup daily-backup-20260518030000 \
  --include-namespaces gitlab

Longhorn Backups

Longhorn heeft ingebouwde backup naar S3:

# Configureer backup target
apiVersion: longhorn.io/v1beta1
kind: Setting
metadata:
  name: backup-target
  namespace: longhorn-system
value: "s3://longhorn-backups@eu-west-1/"
---
apiVersion: longhorn.io/v1beta1
kind: Setting
metadata:
  name: backup-target-credential-secret
  namespace: longhorn-system
value: "longhorn-s3-secret"

Plan terugkerende backups:

apiVersion: longhorn.io/v1beta1
kind: RecurringJob
metadata:
  name: daily-backup
  namespace: longhorn-system
spec:
  cron: "0 3 * * *"
  task: backup
  groups:
    - default
  retain: 7
  concurrency: 2

Offsite Opties

Cloud Storage

ProviderKostenVoordelenNadelen
Backblaze B2$0.005/GBGoedkoop, S3-compatibleUS-gebaseerd
Wasabi$0.0059/GBGeen egress kosten90-dagen minimum
AWS S3 Glacier$0.004/GBZeer goedkoopTrage retrieval
Hetzner Storage Box€3.81/1TBEU-gebaseerd, goedkoopAlleen SFTP/WebDAV

Tweede Locatie

Als je een vriend/familielid hebt met een homelab:

flowchart LR
    subgraph your["Jouw Huis"]
        YourData["Jouw Data"]
        YourBackup["Hun Backup<br/>(versleuteld)"]
    end

    subgraph their["Hun Huis"]
        TheirData["Hun Data"]
        TheirBackup["Jouw Backup<br/>(versleuteld)"]
    end

    YourData -->|Versleuteld| TheirBackup
    TheirData -->|Versleuteld| YourBackup

Wederzijdse offsite backup. Beide versleuteld zodat geen van beiden elkaars data kan lezen.

Self-Hosted Cloud

Draai je eigen S3-compatible storage op een tweede locatie:

# MinIO op remote locatie
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minio
spec:
  template:
    spec:
      containers:
        - name: minio
          image: minio/minio
          args:
            - server
            - /data
          env:
            - name: MINIO_ROOT_USER
              valueFrom:
                secretKeyRef:
                  name: minio-credentials
                  key: user
            - name: MINIO_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: minio-credentials
                  key: password

Toegang via Tailscale voor security.

Database Backups

PostgreSQL

#!/bin/bash
# Kubernetes PostgreSQL backup

NAMESPACE="gitlab"
POD=$(kubectl get pod -n $NAMESPACE -l app=postgresql -o jsonpath='{.items[0].metadata.name}')
DATE=$(date +%Y%m%d_%H%M%S)

# Dump alle databases
kubectl exec -n $NAMESPACE $POD -- \
  pg_dumpall -U postgres | \
  gzip > /backup/postgres_${DATE}.sql.gz

# Upload naar S3
restic backup /backup/postgres_${DATE}.sql.gz --tag postgres --tag daily

Vault Backup

# Export Vault data (vereist root token)
vault operator raft snapshot save /backup/vault_$(date +%Y%m%d).snap

# Versleutel en upload
gpg --encrypt --recipient backup@example.com /backup/vault_$(date +%Y%m%d).snap
restic backup /backup/vault_$(date +%Y%m%d).snap.gpg --tag vault

Restores Testen

Een backup die je niet getest hebt is geen backup.

Maandelijkse Restore Test

#!/bin/bash
# test-restore.sh

# Maak test namespace
kubectl create namespace restore-test

# Restore vanuit Velero
velero restore create test-restore \
  --from-backup $(velero backup get -o json | jq -r '.items[0].metadata.name') \
  --include-namespaces gitlab \
  --namespace-mappings gitlab:restore-test

# Wacht op restore
velero restore wait test-restore

# Verifieer pods draaien
kubectl get pods -n restore-test

# Test applicatie (voorbeeld: GitLab)
kubectl port-forward -n restore-test svc/gitlab 8080:80 &
curl -s http://localhost:8080/health | grep "ok"

# Cleanup
kubectl delete namespace restore-test

Documenteer Recovery Procedures

Voor elk kritiek systeem:

# GitLab Recovery Procedure

## Vereisten
- Toegang tot Velero backups
- Toegang tot PostgreSQL backups
- GitLab Helm values

## Stappen
1. Restore PostgreSQL vanuit backup
2. Restore GitLab PVCs met Velero
3. Deploy GitLab met zelfde Helm values
4. Verifieer user login werkt
5. Verifieer repositories bereikbaar zijn

## Geschatte Tijd: 45 minuten
## Laatst Getest: 2026-05-01

Backups Monitoren

Prometheus Alerts

groups:
  - name: backup-alerts
    rules:
      - alert: BackupFailed
        expr: restic_backup_last_successful_timestamp < (time() - 86400)
        for: 1h
        labels:
          severity: critical
        annotations:
          summary: "Backup niet geslaagd in 24 uur"

      - alert: BackupStorageLow
        expr: restic_repository_size_bytes / restic_repository_max_bytes > 0.9
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "Backup storage boven 90% vol"

Backup Dashboard

Track in Grafana:

  • Laatste succesvolle backup tijd
  • Backup duur trend
  • Storage gebruik
  • Restore test resultaten

Mijn Backup Setup

flowchart TD
    subgraph homelab["Homelab (K3s)"]
        PV["Persistent Volumes"]
        DB["Databases"]
        Config["Configs (Git)"]
    end

    subgraph local["Lokale Backup (NAS)"]
        Longhorn["Longhorn Snapshots"]
        Restic1["Restic Repository"]
    end

    subgraph offsite["Offsite (Backblaze B2)"]
        Velero["Velero Backups"]
        Restic2["Restic Offsite"]
    end

    PV --> Longhorn
    PV --> Velero
    DB --> Restic1
    Restic1 --> Restic2
    Config --> Git["GitLab (self-hosted)"]
    Git --> GitMirror["GitHub Mirror"]

Schema

WatFrequentieRetentieLocatie
Longhorn snapshotsPer uur24 uurLokale NVMe
Longhorn backupsDagelijks7 dagenNAS
Velero volledige backupDagelijks30 dagenBackblaze B2
Database dumpsDagelijks30 dagenBackblaze B2
Git reposPushAltijdGitHub mirror

Kosten

  • Backblaze B2: ~€5/maand voor 200GB
  • NAS storage: Al in bezit
  • Totaal: ~€5/maand voor gemoedsrust

Veelgemaakte Fouten

“RAID is mijn backup”

RAID beschermt tegen drive failure. Het beschermt niet tegen:

  • Per ongeluk verwijderen
  • Ransomware
  • Software bugs die data corrumperen
  • Brand/overstroming/diefstal

“Ik restore wel als ik het nodig heb”

Als je nooit gerestored hebt, weet je niet of je backups werken. Test minimaal per kwartaal.

“Ik backup alles”

10TB aan films back-uppen die je opnieuw kunt downloaden verspilt geld en tijd. Prioriteer onvervangbare data.

“Mijn backup is in dezelfde kamer”

Een brand haalt je server EN je backup drive uit. Offsite is niet onderhandelbaar.

Waarom Dit Ertoe Doet

Dataverlies is geen kwestie van of, maar wanneer:

  • Drives falen (3-5% jaarlijks failure rate)
  • Mensen maken fouten (rm -rf verkeerde directory)
  • Software heeft bugs (database corruptie)
  • Slechte dingen gebeuren (brand, overstroming, diefstal)

Het verschil tussen “klein ongemak” en “catastrofaal verlies” is een geteste backup strategie.

Je homelab slaat dingen op die ertoe doen. Bescherm ze dienovereenkomstig.


De beste tijd om backups in te stellen was voordat je ze nodig had. De op een na beste tijd is nu.