Eine schlecht konfigurierte cron-Rotation, die Archive überschreibt, statt sie zu inkrementieren, ist eine der klassischen Arten, wochenlange Serverprotokolle zu verlieren, ohne es zu merken. Linux-Backups mit cron und rsync richtig zu automatisieren vermeidet genau diese Fehlerklasse. Dieser Leitfaden dokumentiert ein praxiserprobtes cron- + rsync-Setup für 2026, häufige Fallstricke inklusive.
Die Prämisse ist einfach: Automatisierung ist bei Backups nicht optional. Menschen vergessen. Cron nicht. Ein gutes automatisiertes System läuft jede Nacht um 02:00 Uhr, ohne dass jemand daran denkt – und genau dann zahlt es sich aus, an dem Tag, an dem eine Datenbank beschädigt wird oder jemand versehentlich ein großes Archivverzeichnis löscht.
Warum Backups automatisieren
Die kurze Antwort: weil das menschliche Gedächtnis ein schlechter Scheduler für kritische wiederkehrende Aufgaben ist.
Menschen vergessen, Skripte nicht. Backblazes jährliche Umfrage 2024 zu Backup-Gewohnheiten zeigt, dass 67 % der Nutzer, die behaupten, „regelmäßig zu sichern“, dies tatsächlich unregelmäßig tun – mit Lücken von 2 bis 6 Wochen zwischen den Backups. Die wahrgenommene Regelmäßigkeit ist systematisch höher als die tatsächliche. Ein täglicher cron-Auftrag um 02:00 Uhr läuft ausnahmslos: im Urlaub, am Wochenende, in Nächten mit Stromschwankungen (wenn der Server eine USV hat).
Inkrementelles Backup macht Automatisierung praktikabel. Ohne rsync und seine Delta-Übertragungen wäre es untragbar, 500 GB Daten jede Nacht zu sichern (50 bis 100 GB Netzwerkübertragung für ein Standard-Fotoverzeichnis). Mit rsync werden nur die seit dem letzten Backup geänderten Bytes übertragen. Bei einem typischen nächtlichen Backup auf ein LAN-NAS kann die anfängliche Vollkopie einige Stunden dauern, aber jeder folgende Lauf ist meist in Minuten abgeschlossen, weil nur geänderte Blöcke über die Leitung gehen.
Skalierung auf mehrere Maschinen. Der Schritt von einem zu mehreren Servern macht das manuelle Backup zu einer langwierigen Prozedur, die nie korrekt erledigt wird. Ein zentralisiertes cron-Skript, das Backups von allen Maschinen an ein einziges Ziel zieht, kostet null menschliche Zeit.
Automatische Überwachung erkennt Ausfälle. Ein Backup, das seit 3 Wochen stillschweigend fehlschlägt, ist gefährlicher als ein nie konfiguriertes Backup – zumindest wissen Sie dann, dass es nicht existiert. Mit einem Healthchecks.io-Ping am Ende des Skripts erhalten Sie in dem Moment eine E-Mail, in dem ein Backup fehlschlägt oder nicht planmäßig läuft.
rsync 2026: Syntax und wesentliche Optionen
rsync ist ein inkrementelles Dateisynchronisations-Tool, 1996 von Andrew Tridgell entwickelt. Sein Delta-Übertragungsalgorithmus überträgt nur die geänderten Blöcke einer Datei statt der vollständigen Datei – das ist die Grundlage seiner Effizienz für tägliche Backups.
Grundsyntax:
rsync -avz --delete SOURCE DESTINATION
Optionen erklärt:
-a(archive): bewahrt Berechtigungen, Zeitstempel, Symlinks, Eigentümer, Gruppe. Entspricht-rlptgoD.-v(verbose): zeigt übertragene Dateien an.-z(compress): aktiviert Kompression während der Übertragung. Nützlich im WAN, nutzlos im Gigabit-LAN.--delete: entfernt Dateien am Ziel, die an der Quelle nicht mehr existieren.
Lokales Backup auf NAS:
rsync -av --delete /home/eric/ /mnt/nas/backup/eric-home/
Backup auf entfernten Server über SSH:
rsync -avz --delete -e "ssh -i /home/eric/.ssh/backup_key -p 22" \
/var/www/ \
backup@192.168.1.100:/data/backups/www/
Erweiterte Optionen 2026:
# --mkpath: create destination directories if absent (recent flag, rsync 3.2.3+)
rsync -av --mkpath /source/ user@host:/path/that/does/not/exist/
# --exclude: skip specific patterns
rsync -av --exclude='*.log' --exclude='tmp/' --exclude='.git/' /source/ /dest/
# --bwlimit: cap bandwidth (in KB/s)
rsync -av --bwlimit=20000 /source/ user@host:/dest/
# --checksum: force hash-based verification (slower but more reliable)
rsync -avc --checksum /source/ /dest/
# Dry run: simulate without changing anything
rsync -avn --delete /source/ /dest/
Vollständiges Beispiel: VPS-Backup auf eine Hetzner Storage Box:
rsync -avz --delete \
--exclude='*.sock' \
--exclude='/proc' \
--exclude='/sys' \
--exclude='/dev' \
--exclude='/run' \
--bwlimit=30000 \
-e "ssh -i /root/.ssh/hetzner_backup -p 23" \
/etc/ /home/ /var/www/ /var/backups/ \
u123456@u123456.your-storagebox.de:/backups/vps-main/
Ein solches Skript, nächtlich geplant, überträgt typischerweise nur die geänderten Daten an ein entferntes Ziel wie eine Hetzner Storage Box (Preis 2026: 3,81 €/Monat für 100 GB).
Cron: vollständige Syntax und praktische Beispiele
Cron ist der Standard-Unix-Aufgabenplaner, auf jeder Linux-Distribution vorhanden. Der Befehl crontab -e bearbeitet die cron-Tabelle des aktuellen Nutzers.
Die Fünf-Felder-Syntax:
# ┌───── minute (0 - 59)
# │ ┌───── hour (0 - 23)
# │ │ ┌───── day of month (1 - 31)
# │ │ │ ┌───── month (1 - 12)
# │ │ │ │ ┌───── day of week (0 - 7, 0 and 7 = Sunday)
# │ │ │ │ │
# * * * * * command
Gängige Zeitplan-Beispiele:
# Every minute (testing / monitoring)
* * * * * /usr/local/bin/monitor.sh
# Every hour at H:00
0 * * * * /usr/local/bin/hourly-backup.sh
# Every day at 02:00
0 2 * * * /usr/local/bin/daily-backup.sh
# Every Sunday at 03:00
0 3 * * 0 /usr/local/bin/weekly-backup.sh
# 1st of every month at 04:00
0 4 1 * * /usr/local/bin/monthly-backup.sh
# Every 6 hours
0 */6 * * * /usr/local/bin/incremental.sh
# Weekdays (Mon-Fri) at 08:30
30 8 * * 1-5 /usr/local/bin/workday-sync.sh
Wichtige Umgebungsvariablen in crontab:
# cron does not inherit user PATH — always define it explicitly
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=admin@mydomain.com
# Explicit timezone (avoids scheduling surprises)
CRON_TZ=America/New_York
0 2 * * * /usr/local/bin/daily-backup.sh >> /var/log/backup.log 2>&1
systemd-Timer: die moderne Alternative
Auf Systemen mit systemd (Ubuntu 16.04+, Debian 9+, CentOS 7+) bieten systemd-Timer bessere Nachvollziehbarkeit:
# /etc/systemd/system/backup-daily.timer
[Unit]
Description=Daily rsync backup
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true # Catches up missed jobs if server was off
Unit=backup-daily.service
[Install]
WantedBy=timers.target
# /etc/systemd/system/backup-daily.service
[Unit]
Description=Daily rsync backup
After=network.target
[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/daily-backup.sh
Nice=19
IOSchedulingClass=idle
# Activation
systemctl enable backup-daily.timer
systemctl start backup-daily.timer
systemctl list-timers # Check status
journalctl -u backup-daily.service # View logs
Der entscheidende Vorteil von Persistent=true: War der Server um 02:00 Uhr aus, läuft der Auftrag beim nächsten Start. Standard-cron verpasst Aufträge, wenn die Maschine offline ist.
Vollständiges Backup-Skript: Logging, Fehlerbehandlung, Benachrichtigungen
Hier ist ein produktionsreifes Referenzskript, das Sie anpassen können. Es deckt strukturiertes Logging, Fehlerbehandlung und Benachrichtigungen ab.
#!/bin/bash
# /usr/local/bin/daily-backup.sh
# Daily rsync backup with logging and alerts
set -euo pipefail
# ── Configuration ──────────────────────────────────────────────────────────────
BACKUP_SOURCE="/home /etc /var/www /var/backups"
BACKUP_DEST="/mnt/nas/backups/vps-main"
LOG_FILE="/var/log/backup-daily.log"
MAX_LOG_SIZE_MB=50
LOCK_FILE="/tmp/backup-daily.lock"
HEALTHCHECK_URL="https://hc-ping.com/YOUR-UUID-HERE" # Healthchecks.io
NOTIFY_EMAIL="admin@mydomain.com"
RSYNC_OPTIONS="-avz --delete --delete-after --exclude='*.sock' --exclude='*.pid'"
SSH_KEY="/root/.ssh/backup_key"
REMOTE_HOST="backup@192.168.1.100"
REMOTE_PATH="/data/backups"
BWLIMIT=30000 # KB/s — 30 MB/s cap
# ── Functions ──────────────────────────────────────────────────────────────────
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
send_alert() {
local subject="$1"
local body="$2"
echo "$body" | mail -s "$subject" "$NOTIFY_EMAIL" 2>/dev/null || true
# Healthchecks.io: ping /fail to signal failure
curl -fsS --retry 3 --max-time 10 "${HEALTHCHECK_URL}/fail" \
--data-raw "$body" > /dev/null 2>&1 || true
}
rotate_log() {
local size_mb
size_mb=$(du -sm "$LOG_FILE" 2>/dev/null | cut -f1 || echo 0)
if [ "$size_mb" -gt "$MAX_LOG_SIZE_MB" ]; then
mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d)"
gzip "${LOG_FILE}.$(date +%Y%m%d)" 2>/dev/null || true
log "Log rotated (size threshold exceeded)"
fi
}
cleanup() {
rm -f "$LOCK_FILE"
}
# ── Preliminary checks ─────────────────────────────────────────────────────────
# Lock: prevent parallel executions
if [ -f "$LOCK_FILE" ]; then
log "ERROR: backup already running (lockfile present). Aborting."
send_alert "[BACKUP] Lock conflict on $(hostname)" \
"Backup was already running. Check PID in $LOCK_FILE."
exit 1
fi
trap cleanup EXIT
echo $$ > "$LOCK_FILE"
rotate_log
log "═══ Starting daily backup ═══"
# Check destination connectivity
if ! ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes \
"$REMOTE_HOST" "echo OK" > /dev/null 2>&1; then
log "ERROR: cannot reach $REMOTE_HOST"
send_alert "[BACKUP] Destination unreachable on $(hostname)" \
"SSH to $REMOTE_HOST failed. Check network/key."
exit 2
fi
# ── rsync execution ────────────────────────────────────────────────────────────
ERRORS=0
START_TIME=$(date +%s)
for SOURCE_DIR in $BACKUP_SOURCE; do
if [ ! -d "$SOURCE_DIR" ]; then
log "WARNING: source directory absent: $SOURCE_DIR"
continue
fi
DEST_DIR="${REMOTE_PATH}/$(basename "$SOURCE_DIR")"
log "Syncing: $SOURCE_DIR → $REMOTE_HOST:$DEST_DIR"
if rsync $RSYNC_OPTIONS \
--bwlimit="$BWLIMIT" \
-e "ssh -i $SSH_KEY -o BatchMode=yes" \
"$SOURCE_DIR/" \
"$REMOTE_HOST:$DEST_DIR/" \
>> "$LOG_FILE" 2>&1; then
log "OK: $SOURCE_DIR synced"
else
log "ERROR: rsync failed for $SOURCE_DIR (exit code: $?)"
ERRORS=$((ERRORS + 1))
fi
done
# ── Final result ───────────────────────────────────────────────────────────────
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
DURATION_MIN=$((DURATION / 60))
if [ "$ERRORS" -eq 0 ]; then
log "Backup completed successfully in ${DURATION_MIN} min"
# Healthchecks.io success ping
curl -fsS --retry 3 --max-time 10 "$HEALTHCHECK_URL" > /dev/null 2>&1 || true
else
log "Backup completed with $ERRORS error(s) in ${DURATION_MIN} min"
send_alert "[BACKUP] $ERRORS error(s) on $(hostname)" \
"Backup finished with $ERRORS error(s). Duration: ${DURATION_MIN} min. See $LOG_FILE."
fi
log "═══ Backup complete ═══"
Zur crontab hinzufügen:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 2 * * * /usr/local/bin/daily-backup.sh
Da rsync nur das Geänderte überträgt, dauert ein inkrementelles Backup von einigen Hundert GB typischerweise nur wenige Minuten pro Nacht, sobald die erste Synchronisation erledigt ist.
rsnapshot: automatische Snapshot-Rotation
rsnapshot ist ein rsync-Wrapper, der die Snapshot-Rotation mit Hardlinks automatisch umsetzt – jeder Snapshot sieht aus wie eine vollständige Kopie, speichert aber nur tatsächlich neue oder geänderte Dateien.
Installation:
apt install rsnapshot # Debian/Ubuntu
yum install rsnapshot # CentOS/RHEL
Konfiguration /etc/rsnapshot.conf (Auszug):
# IMPORTANT: tabs required between fields (not spaces)
config_version 1.2
# Snapshot root directory
snapshot_root /mnt/nas/rsnapshot/
# rsync command
cmd_rsync /usr/bin/rsync
# Rotation intervals
retain hourly 6 # 6 hourly snapshots
retain daily 7 # 7 days
retain weekly 4 # 4 weeks
retain monthly 12 # 12 months
# Global rsync options
rsync_short_args -az
rsync_long_args --delete --delete-excluded --numeric-ids
# Sources to back up
backup /home/eric/ localhost/
backup /etc/ localhost/
backup /var/www/ localhost/
backup root@192.168.1.10:/home/ web-server/
backup root@192.168.1.10:/etc/ web-server/
# Exclusions
exclude *.log
exclude tmp/
exclude .cache/
rsnapshot-crontab:
# Hourly snapshots (6am - 10pm)
0 6-22 * * * /usr/bin/rsnapshot hourly
# Daily at 02:30
30 2 * * * /usr/bin/rsnapshot daily
# Weekly on Monday at 03:00
0 3 * * 1 /usr/bin/rsnapshot weekly
# Monthly on 1st at 04:00
0 4 1 * * /usr/bin/rsnapshot monthly
Resultierende Verzeichnisstruktur:
/mnt/nas/rsnapshot/
├── daily.0/ ← yesterday
│ ├── localhost/
│ │ ├── home/eric/
│ │ ├── etc/
│ │ └── var/www/
│ └── web-server/
├── daily.1/ ← two days ago
├── daily.2/
...
├── weekly.0/ ← last week
├── monthly.0/ ← last month
Die Wiederherstellung ist trivial: cp -a /mnt/nas/rsnapshot/daily.2/localhost/home/eric/file.txt /home/eric/. Kein spezielles Tool, nur eine Kopie aus einem Snapshot-Verzeichnis.
Speicherplatz: bei 180 GB Quelldaten und einer Rotation von 7 täglich + 4 wöchentlich + 12 monatlich = 23 Snapshots verwende ich etwa 320 GB auf dem NAS (160 GB „duplizierter“ Daten, weil unveränderte Dateien Hardlinks zwischen Snapshots teilen).
BorgBackup: Deduplizierung und Verschlüsselung für sensible Backups
rsync glänzt bei der Dateisynchronisation. BorgBackup ist überlegen, wenn Sie Block-Deduplizierung, native Verschlüsselung und variable Kompression benötigen. Es ist mein Tool für externe Backups auf eine Hetzner Storage Box und für Backups mit personenbezogenen Daten.
Vergleich rsync vs. BorgBackup:
| Kriterium | rsync | BorgBackup |
|---|---|---|
| Deduplizierung | Nein (Hardlinks über rsnapshot) | Ja (variable Blöcke ~512 KB) |
| Verschlüsselung im Ruhezustand | Nein | AES-256 nativ |
| Kompression | Während der Übertragung (-z) | LZ4/ZSTD/ZLIB integriert |
| Einzeldatei-Wiederherstellung | Einfach (cp aus Snapshot) | borg extract |
| Speicherplatz | Höher (keine echte Dedup) | 40-60 % geringer bei gemischten Daten |
| Einrichtungskomplexität | Gering | Mäßig |
Installation und Initialisierung:
apt install borgbackup # Ubuntu 22.04: version 1.2.x
# Initialize an encrypted repository (recommended mode)
borg init --encryption=repokey-blake2 user@nas:/data/borg-repo/
# Store the passphrase in a password manager
# AND in a secure file outside the machine being backed up
Borg-Backup-Skript mit Prune-Richtlinie:
#!/bin/bash
export BORG_PASSPHRASE="YOUR_LONG_AND_COMPLEX_PASSPHRASE"
export BORG_REPO="user@nas:/data/borg-repo"
# Create snapshot with timestamp
borg create \
--verbose \
--compression lz4 \
--exclude-caches \
--exclude '/home/*/.cache' \
--exclude '/home/*/.local/share/Trash' \
"${BORG_REPO}::$(hostname)-$(date +%Y%m%d-%H%M%S)" \
/home /etc /var/www
# Retention policy: 7 daily + 4 weekly + 12 monthly
borg prune \
--verbose \
--list \
--keep-daily=7 \
--keep-weekly=4 \
--keep-monthly=12 \
"${BORG_REPO}"
# Integrity verification (recommended weekly)
# borg check "${BORG_REPO}"
Wiederherstellung:
# List archives
borg list "${BORG_REPO}"
# Restore a specific file
borg extract "${BORG_REPO}::server-20260608-020000" home/eric/documents/important.pdf
# Full restoration
borg extract "${BORG_REPO}::server-20260608-020000"
Wann Borg gegenüber rsync zu bevorzugen ist:
- Sensible Daten (persönliche Dokumente, Datenbanken mit personenbezogenen Daten)
- Backups auf Cloud-Speicher oder nicht vertrauenswürdige Hosts
- Datenmengen mit hoher Redundanz (Fotos, Quellcode mit Git-Historie)
- Bedarf an einer komprimierten Snapshot-Historie auf begrenztem Speicher
Auf einem entfernten 100-GB-Ziel wie einer Hetzner Storage Box kann Borg mehrere Monate deduplizierter, komprimierter Snapshots in einem Bruchteil des Speichers behalten, den einfache rsync-Kopien für dieselbe Verlaufstiefe benötigen würden – typischerweise ein Kompressionsverhältnis deutlich unter 1, je nachdem, wie redundant die Quelldaten sind.
Überwachung und Benachrichtigung: nie annehmen, dass das Backup läuft
Ein Backup, das seit 3 Wochen stillschweigend fehlschlägt, ist eine Katastrophe mit Ansage. Überwachung ist nicht optional.
Healthchecks.io: der einfachste Ansatz
Healthchecks.io ist ein cron-Überwachungsdienst auf Ping-Basis. Erstellen Sie eine Prüfung mit dem erwarteten Intervall (täglich 24 Std. + 1 Std. Karenz), fügen Sie den Ping am Ende Ihres Skripts hinzu. Kommt der Ping nicht an, erhalten Sie eine E-Mail.
# At the end of the backup script, on success:
curl -fsS --retry 3 --max-time 10 \
"https://hc-ping.com/YOUR-UUID" > /dev/null 2>&1 || true
# On failure, ping the /fail endpoint:
curl -fsS --retry 3 --max-time 10 \
"https://hc-ping.com/YOUR-UUID/fail" > /dev/null 2>&1 || true
Kostenloser Plan: 20 Prüfungen. Ausreichend für 4 Server mit täglicher + wöchentlicher Überwachung. Business-Plan für 20 $/Jahr für Teams.
Log-Überwachung mit einfachem grep:
# Crontab: check backup logs for errors every hour
0 * * * * grep -i "error\|fail" /var/log/backup-daily.log \
| tail -5 \
| mail -s "[$(hostname)] Backup errors" admin@mydomain.com 2>/dev/null || true
Skript zur Prüfung der Backup-Aktualität:
#!/bin/bash
# Verify that the most recent backup is less than 26 hours old
BACKUP_DIR="/mnt/nas/backups"
MAX_AGE_HOURS=26
find "$BACKUP_DIR" -name "*.log" -newer \
<(date -d "$MAX_AGE_HOURS hours ago") > /tmp/recent_backups 2>/dev/null
if [ ! -s /tmp/recent_backups ]; then
echo "ALERT: No recent backup on $(hostname)" \
| mail -s "[BACKUP] Backup too old!" admin@mydomain.com
fi
Prometheus + Grafana für fortgeschrittene Homelabs:
Für Umgebungen mit mehreren Servern stellt der Prometheus node_exporter Dateisystem-Metriken bereit. Eine Alertmanager-Regel kann eine Slack-Benachrichtigung auslösen, wenn der Zeitstempel des letzten Backups einen Schwellenwert überschreitet:
# prometheus/rules/backup.yml
groups:
- name: backup_freshness
rules:
- alert: BackupStaleness
expr: |
(time() - node_filesystem_file_content_mtime_seconds{
mountpoint="/mnt/nas",
path="/data/backups/vps-main"
}) > 90000
for: 1h
labels:
severity: warning
annotations:
summary: "Stale backup on {{ $labels.instance }}"
description: "Last backup {{ $value | humanizeDuration }} ago"
Ein solches Dashboard kann auf Hardware so bescheiden wie einem Raspberry Pi laufen und liefert Ihnen zentrale Überwachung für mehrere Server zu nahezu null Infrastrukturkosten (Prometheus und Grafana sind beide quelloffen).
Die cron- + rsync-Automatisierung ist die technische Ebene, die die 3-2-1-Backup-Strategie im großen Maßstab praktikabel macht. Um zu verstehen, wie sich das in eine vollständige Backup-Architektur einfügt, siehe den Leitfaden zur 3-2-1-Backup-Strategie. Für Windows- und Mac-Nutzer, die neben Desktop-Maschinen auch Linux-Server verwalten, behandelt der Leitfaden für automatisches Backup unter Windows und Mac die GUI-Entsprechungen.
Wenn Prävention versagt und die Datenrettung notwendig wird, behandelt der Leitfaden zur Festplatten-Datenrettung 2026 DIY- und professionelle Optionen, und der Vergleich der besten Rettungssoftware 2026 misst die verfügbaren Tools. Für Schätzungen der professionellen Wiederherstellungskosten siehe unseren Leitfaden zu den Datenrettungskosten 2026.
Automatisiertes GUI-Backup für Windows und Mac
Wenn Sie neben Ihren Linux-Servern auch Windows-/Mac-Maschinen verwalten – EaseUS Todo Backup automatisiert Backups ohne jede Kommandozeile · Kostenlose Version verfügbar
Recover your deleted files → EaseUS
Free scan · deleted, formatted & lost files · Windows & Mac
