· · 12 min leestijd Intermediate

Backup-strategie voor je homelab: de 3-2-1-regel in de praktijk

Implementeer een solide backup strategie voor je homelab met de 3-2-1 regel. Praktische gids met Restic, Velero, en offsite backup opties.

Drie kopieën van één tape, in haar hand, in een brandkast, aan een ballon, terwijl het huis achter haar brandt

TL;DR Drie kopieën, twee soorten media, één ervan buiten de deur. Restic voor bestanden, Velero voor het cluster, een bucket bij Backblaze als offsite kopie, en een restore-test op een vast moment. Bij mij kost dat zo’n 5 euro per maand, en die restore-test is het onderdeel waar ik mezelf nog steeds toe moet zetten.

Stel dat de disk in je homelab vannacht sterft. Niet corrupt raken, niet eerst een week SMART-waarschuwingen geven, gewoon weg. De git-server met elke repo waar je om geeft, de password vault, vijftien jaar familiefoto’s, de home automation die het huis aanstuurt. Allemaal op een drive die heeft besloten dat het mooi geweest is.

Kun je zeggen wat er daarna gebeurt zonder dat je maag samentrekt? Zo niet, dan heb je geen backups. Dan heb je hoop, en op hoop heb ik zelf langer gedraaid dan me lief is.

Het goede nieuws is dat je niks slims nodig hebt. De 3-2-1-regel bestaat al tientallen jaren en is bijna saai simpel. Deze post brengt je van “volgens mij heb ik wel iets” naar een setup die je getest hebt. Ik begin met de versie die je vandaag kunt draaien en stapel de rest daar bovenop.

De 3-2-1-regel

Drie kopieën, twee verschillende media, één offsite. Meer is de regel niet. De rest van deze post is die drie getallen invullen met echte tools.

3-2-1 Backup Regel

1 Offsite

2 Media Types

3 Kopieën

Cloud/Remote

Originele Data

Kopie 1
(Origineel)

Kopie 2
(Lokale Backup)

Kopie 3
(Offsite)

NVMe/SSD

HDD/NAS

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 je data die zit te wachten tot hij kapotgaat. Twee kopieën voelen veiliger, precies tot één gebeurtenis ze allebei meeneemt. Brand doet dat. Een ransomware-payload die elke mount afloopt die hij kan bereiken ook. Drie kopieën met echte afstand ertussen, dáár zou ik het pas resilience durven noemen.

Waarom twee soorten media

Verschillende hardware gaat op verschillende manieren kapot, en je wilt je kopieën over die faalwijzen verdeeld hebben, zodat één slechte dag er niet bij allemaal kan.

  • SSDs kunnen stilletjes falen via bit rot, waarbij data ongemerkt slecht wordt voordat je het doorhebt
  • HDDs sterven mechanisch, vaak met genoeg waarschuwing om te reageren als je oplet
  • RAID is geen backup. Het beschermt tegen een drive die wegvalt, en doet niets tegen corruptie, verwijdering, of een slechte write die netjes gespiegeld wordt over elke disk

Zet je kopieën op een SSD, een draaiende schijf en een bucket op afstand, en wat de ene sloopt, sloopt zelden de andere.

Waarom één offsite

Je huis kan afbranden. Een stroompiek kan alles koken wat aan hetzelfde circuit hangt. Lokale kopieën zijn snel en handig en waardeloos tegen alles wat het hele gebouw raakt. De offsite kopie is gewoon de kopie die in een ander gebouw staat.

Wat je back-upt

Voordat je iets back-upt, sorteer je je data in drie bakken. De meeste mensen back-uppen veel te veel, of ze slaan stilletjes het ene ding over dat ze niet kunnen herbouwen. Een paar minuten sorteren lost allebei op.

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, geen backup

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

Kun je het terughalen met een commando of een download, laat het dan weg. Backupruimte kost geld en backuptijd kost tijd, en die aan een basis-OS besteden is zonde.

Backup-tools

Goed, dat was de theorie. Nu wordt het praktisch. Ik begin met de simpelste tool die je een echte tweede kopie geeft en bouw daarna op naar het Kubernetes-spul.

Restic voor file-backups

Doe je na het lezen maar één ding, zet dan Restic op. Dat gebruik ik zelf voor file-backups. Snel, versleutelt standaard, dedupliceert zodat herhaalde backups klein blijven, en praat met een lokale schijf of een S3-bucket zonder dat je iets aan je workflow verandert. Dit is de minimaal werkende backup, en hij draait binnen vijf minuten.

# 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

Restic automatisch

Een backup die je zelf moet onthouden is er een die je vergeet. Zet de commando’s in een script, wijs het naar je offsite bucket en laat het zelf prunen, zodat de repo niet eindeloos groeit.

#!/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

Die restic check aan het eind doet er meer toe dan het lijkt. Hij leest de repository terug en controleert hem. Zonder die check heb je een map vol bytes en geen idee of ze nog leesbaar zijn.

Cronjob:

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

Velero voor Kubernetes

Zodra je een cluster draait, zijn file-backups niet meer genoeg. Je wilt ook de staat van het cluster zelf, de Deployments en ConfigMaps en PersistentVolumeClaims. Velero back-upt Kubernetes-resources en hun persistent volumes samen, dus één restore brengt de workloads én hun data terug.

# 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

Draai je Longhorn als storage, dan zit er al een backup-engine onder je volumes, en die praat rechtstreeks met 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"

Terugkerende backups inplannen:

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

De “1” in 3-2-1 is het deel dat mensen overslaan, meestal omdat het klinkt als het dure, ingewikkelde deel. Valt mee. Je hebt drie eerlijke opties, ze ruilen kosten tegen controle, en hoe ver je dat lijstje afzakt zegt best wat over hoeveel sovereignty je wilt.

Cloudopslag

De goedkoopste manier om offsite te komen. Kies een provider, wijs Restic of Velero ernaartoe, klaar.

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

Wil je de offsite kopie binnen de EU? Dan is de Hetzner Storage Box op prijs lastig te verslaan. Backblaze is de makkelijke default als je het gewoon werkend wilt hebben. Die van mij staat bij Backblaze, in de VS, dus over die EU-optie mag ik niet al te hard roepen.

Tweede locatie

Heb je een vriend of familielid die ook een homelab draait? Back-up elkaar. Zij bewaren een versleutelde kopie van jouw data, jij één van die van hen, en geen van beiden kan lezen wat er staat.

Hun Huis

Jouw Huis

Versleuteld

Versleuteld

Jouw Data

Hun Backup
(versleuteld)

Hun Data

Jouw Backup
(versleuteld)

Dit kost je wat schijf en wat uploadbandbreedte, en je offsite kopie komt nooit bij een cloudprovider terecht.

Eigen cloud

De volle sovereignty-versie. Draai je eigen S3-compatible storage op een tweede fysieke locatie en back-up daarheen.

# 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

Bereik het via Tailscale, dan hoeft de storage nooit aan het publieke internet te hangen.

Database-backups

Databases vragen hun eigen aanpak. Kopieer je de bestanden onder een draaiende database vandaan, dan krijg je een snapshot die midden in een write kan zitten, en zo’n snapshot restoret misschien niet. Dump ze netjes.

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

Vault is degene waar ik wakker van lig, want Vault kwijt betekent de toegang tot al het andere kwijt. Maak een raft -snapshot, versleutel hem voordat hij de machine verlaat en stuur hem dan pas weg.

# 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

Dit is het deel waar iedereen bij knikt en bijna niemand doet. Ik heb ook geknikt. Een backup die je niet getest hebt is een gok. De eerste restore moet niet de restore zijn die je echt nodig hebt, met productie plat, en dan blijkt dat de dumps al drie maanden leeg zijn.

Maandelijkse restore-test

Dus test op een vast moment. Restore naar een wegwerp-namespace, kijk of het ding opkomt, breek het weer af.

#!/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

Herstelprocedures opschrijven

Als er echt iets in brand staat, wil je je eigen restore-procedure niet uit je hoofd zitten reconstrueren. Schrijf per kritiek systeem het runbook op, met hoe lang het duurde en wanneer je voor het laatst hebt bewezen dat het werkt.

# 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

Die regel “Laatst Getest” houdt de test eerlijk. Staat er een datum van een jaar geleden, dan weet niemand of de procedure nog werkt, jij ook niet.

Backups monitoren

Een backup-job die twee weken geleden stilletjes gestopt is, is erger dan geen backup, want je denkt dat je gedekt bent. Hang de jobs aan je monitoring, zodat een failure tegen je schreeuwt.

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

Bijhouden in Grafana:

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

Mijn backup-setup

Zo past het bij mij in elkaar, en dat is gewoon de lagen hierboven op elkaar gestapeld. Lokale kopieën voor snelle restores, een offsite bucket voor het rampscenario, en Git voor alles wat al tekst is.

Offsite (Backblaze B2)

Lokale Backup (NAS)

Homelab (K3s)

Persistent Volumes

Databases

Configs (Git)

Longhorn Snapshots

Restic Repository

Velero Backups

Restic Offsite

Forgejo (self-hosted)

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

Vijf euro per maand, en de NAS stond er al. De foto’s zijn de reden dat ik het betaal.

Veelgemaakte fouten

De meeste hiervan heb ik zelf gemaakt, of bij vrienden zien gebeuren. Ze klinken allemaal redelijk, tot de dag dat ze je wat kosten.

“RAID is mijn backup”

RAID beschermt tegen een schijf die uitvalt. Het doet niks tegen:

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

Een rm -rf in de verkeerde directory staat meteen op elke schijf in de array. RAID houdt de array in de lucht als er een schijf sterft. Niks op dat lijstje is een schijf die sterft.

“Ik restore wel als het nodig is”

Heb je nog nooit gerestored, dan weet je niet of je backups werken, en de dag dat je ze nodig hebt is de dag dat je erachter komt. Minstens elk kwartaal testen.

“Ik back-up alles”

10TB aan films back-uppen die je opnieuw kunt downloaden, kost geld en tijd die je aan de data kunt besteden die je niet kunt vervangen. Eerst sorteren, dan het onvervangbare spul.

“Mijn backup staat in dezelfde kamer”

Eén brand neemt de server én de backup-schijf ernaast mee. Offsite is het deel dat de rest van de regel de moeite waard maakt.

Waarom dit ertoe doet

Dataverlies is geen misschien. Schijven hebben een jaarlijkse failure rate van 3-5%, mensen draaien het verkeerde commando, software maakt databases kapot op manieren die elke health check doorstaan, en huizen vatten af en toe vlam. Draai een homelab lang genoeg en je komt er minstens één van tegen.

Wat de uitkomst bepaalt is of je het saaie werk van tevoren gedaan hebt. Het is hetzelfde waar ik op deze blog steeds op uitkom, het verschil tussen een systeem dat je begrijpt en in de hand hebt en een systeem waarvan je hoopt dat het blijft staan. Met een geteste backup kost een kapotte schijf je een middag. Zonder kost hij je de foto’s.

Dus geef die vijf euro en die middag uit. En zet de restore-test in je agenda, want dat is de stap waar ik mezelf nog steeds toe moet zetten.