SSH Login mit Public-Key-Authentifizierung einrichten
Grundlegender rsync mit ssh Befehl
rsync -avz -e ssh /lokaler/pfad/ benutzer@server:/ziel/pfad/
rsync -avzP --delete --progress -e "ssh -p 2222" /quelle/ user@server:/ziel/
rsync -avz --rsh="ssh -p 2222" /lokaler/pfad/ benutzer@server:/ziel/pfad/
| Optionen+ |
Bedeutung |
-a |
Archiv-Modus (Behält Berechtigungen, Zeitstempel, Symlinks, etc.) |
-v |
Verbose (zeigt Details) |
-z |
Komprimiert während der Übertragung |
--progress |
Zeigt Fortschritt pro Datei |
-P |
--progress + --partial (ermöglicht Wiederaufnahme) |
-e ssh |
Explizit SSH als Transport nutzen |
-p 2222 |
Anderer SSH-Port (Standard: 22) |
--delete |
Löscht Dateien auf dem Ziel, die lokal nicht mehr existieren |
--dry-run |
Testlauf ohne Änderungen |
--exclude="*.tmp" |
Bestimmte Dateien ausschließen |
--include="*.txt" |
Bestimmte Dateien einschließen |
--bwlimit=1000 |
Bandbreite auf 1000 KB/s begrenzen |
Verzeichnisse und Dateien beim rsync ausschließen
Die Option --exclude funktioniert für Dateien und Verzeichnisse auf die gleiche Weise. Du kannst sowohl einzelne Dateien als auch ganze Ordner mit derselben Syntax ausschließen.
Die allgemeine Syntax lautet:
rsync [OPTIONEN] QUELLE/ ZIEL/ --exclude=MUSTER
Dabei kann MUSTER sowohl ein Dateiname als auch ein Verzeichnisname sein.
Beispiel mit einem konkreten Verzeichnis und einer konkreten Datei
Lokaler Client Server
─────────────────────────────────────────────────────────────────────────────
~/Projekte/website/ /meinserver/verzeichnis/
│
├── index.php ├── index.php
├── about.php ├── about.php
├── contact.php ├── contact.php
├── config.local.php ──── ausgeschlossen ────✗ (nicht übertragen)
├── _archive/ ──── ausgeschlossen ────✗ (nicht übertragen)
│ ├── altes-design.css
│ └── backup-vom-januar/
├── cache/
│ └── temp/
├── css/
│ └── style.css
└── .rsync-exclude.txt
Angenommen, du möchtest von deinem lokalen Verzeichnis ~/Projekte/website auf den Server /meinserver/verzeichnis/ synchronisieren und dabei das Verzeichnis _archive sowie die Datei config.local.php ausschließen.
Mit und ohne /Schrägstrich/ am Ende
… ohne Schrägstrich kopiert rsync das gesamte Verzeichnis website inklusive seines Namens auf den Server.
----------
VARIANTE 1
----------
👇
rsync -a --info=progress2 ~/Projekte/website meinserver:/verzeichnis/ --exclude=/website/_archive/ --exclude=/website/config.local.php
… mit Schrägstrich kopiert rsync nur den Inhalt von website direkt nach /verzeichnis/ auf dem Server.
----------
VARIANTE 2
----------
👇
rsync -a --info=progress2 ~/Projekte/website/ meinserver:/verzeichnis/ --exclude=/_archive/ --exclude=/config.local.php
Vorsicht: Kein Schrägstrich beim Verzeichnis (Datei)
Bei der Schreibweise --exclude='_archive' oder --exclude='config.local.php' schließt rsync alle Dateien und Verzeichnisse die so heissen komplett aus.
Was ist für rsync root /
Der Pfad nach --exclude= muss immer relativ zur Wurzel der Übertragung sein.
- Bei der ersten Variante ist
~/Projekte die Wurzel
- bei der zweiten Variante ist
~/Projekte/website/ die Wurzel.
Mehrere Dateien und Verzeichnisse ausschließen
Du kannst den --exclude-Parameter beliebig oft wiederholen, um eine Mischung aus Dateien und Ordnern auszuschließen:
rsync -a ~/Projekte/website/ meinserver:/verzeichnis/ --exclude=/_archive/ --exclude=/config.local.php --exclude='*.tmp' --exclude=/cache/
Exclude-Liste aus einer Datei verwenden
Falls du viele Ausnahmen definieren möchtest, ist es übersichtlicher, diese in eine Datei zu schreiben und mit --exclude-from= zu verwenden:
rsync -a ~/Projekte/website/ meinserver:/verzeichnis/ --exclude-from=/pfad/zur/ausschlussliste.txt
Die Ausschlussliste könnte beispielsweise so aussehen:
/_archive/
/config.local.php
/*.tmp
/cache/
/logs/
Wenn die Datei z.B. (versteckt) .rsync-exclude.txt mit den Excludes im selben Pfad liegt, muss sie selbst natürlich auch excluded werden.
rsync -a ~/Projekte/website/ meinserver:/verzeichnis/ --exclude-from=/.rsync-exclude.txt --exclude=/.rsync-exclude.txt
Die Datei kann natürlich auch außerhalb des Verzeichnisses platziert werden.
Testlauf durchführen
Bevor du den Befehl ausführst, kannst du mit --dry-run oder -n prüfen, ob die richtigen Dateien und Verzeichnisse ausgeschlossen werden:
rsync -a --dry-run ~/Projekte/website/ meinserver:/verzeichnis/ --exclude=/_archive/ --exclude=/config.local.php
Exclude-Übersicht: Schreibweisen für Dateien & Verzeichnisse
| Option |
Verhalten |
Beispiel für Verzeichnis |
Beispiel für Datei |
--exclude=/pfad/zum/element/ |
Schließt nur den exakten Pfad in der Übertragungswurzel aus. |
--exclude=/_archive/ |
--exclude=/config.local.php |
--exclude=name |
Schließt jedes Element dieses Namens aus, wo auch immer es sich befindet. |
--exclude=_archive |
--exclude=config.local.php |
--exclude=*/name/ |
Schließt jeden Ordner name aus, der ein direktes Unterverzeichnis eines beliebigen Ordners ist. |
--exclude=*/_archive/ |
nicht anwendbar |
--exclude=*.endung |
Schließt alle Dateien mit einer bestimmten Endung aus. |
nicht anwendbar |
--exclude=*.log |
Performance-Tuning
| Optimierung |
Befehl |
| Schnellere Verbindung |
-e "ssh -c arcfour" (weniger sicher, aber schneller) |
| Größere Blockgröße |
-B 8192 (für große Dateien) |
| Keine Komprimierung |
--no-compress (bei schnellen Netzwerken) |
| Weniger I/O |
--inplace (Dateien direkt überschreiben) |
Parallelisieren für viele kleine Dateien
Hierzu muss das Tool parallel installiert sein.
## Mit GNU parallel
find /daten -type f | parallel -j 4 rsync -avz {} server:/backup/{}
Restriktive Berechtigungen auf dem Server
## ~/.ssh/authorized_keys mit Einschränkungen
command="rsync --server -vlogDtprze.iLsf . /backup/",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAA... backup-user
Komplettes Backup mit Löschung (Spiegelung)
# -avzP : Komplettes Backup
# P : Fortschrittsanzeige
# --delete : mit Löschung (Spiegelung)
# -e "ssh -p 2222" : anderer SSH Port
# --exclude="*.mp4" --exclude=".cache/" : Ausschluss von Dateien oder Ordnern
# --bwlimit=5000 : Limitierte Bandbreite hier 5Mbit
# --dry-run : Testlauf ... nichts passiert
# --no-compress : keine Komprimierung
rsync -avzP --delete -e "ssh -p 2222" /home/benutzer/ benutzer@server:/backup/home/
Highperformance Sync
Hier ist ein hochperformantes Beispiel für das parallele Synchronisieren vieler Dateien mit rsync:
find /daten -type f | parallel -j 8 rsync -avzP --delete -e "ssh -p 2222 -c aes128-gcm@openssh.com -o Compression=no" {} benutzer@server:/backup/{} --no-compress --bwlimit=10000
Erklärung der Parameter
find /daten -type f listet alle Dateien im Quellverzeichnis auf und übergibt sie an parallel
-j 8 bestimmt die Anzahl der parallelen Prozesse (Faustregel: 4 bis 8)
-c aes128-gcm@openssh.com verwendet einen schnellen Verschlüsselungsalgorithmus
-o Compression=no deaktiviert die SSH-Komprimierung (rsync hat bereits --no-compress)
--bwlimit=10000 begrenzt die Bandbreite auf 10 MB/s (Wert in KB/s)
Performance-Tipps für viele kleine Dateien
Bei sehr vielen kleinen Dateien (z.B. tausende 1-KB-Dateien) ist die Latenz der SSH-Verbindung der limitierende Faktor. In diesem Fall sind weniger parallele Prozesse sinnvoll, um den SSH-Handshake-Overhead zu reduzieren. Ich empfehle dann -j 4 oder sogar nur -j 2.
Ein weiterer Performance-Gewinn lässt sich erzielen, indem große Dateien aus der Parallelisierung ausgeschlossen werden und sie separat synchronisiert werden.
## Kleine Dateien parallel synchronisieren
find /daten -type f -size -10M | parallel -j 8 rsync -av --no-compress {} benutzer@server:/backup/{}
## Große Dateien einzeln mit Komprimierung übertragen
find /daten -type f -size +10M | parallel -j 1 rsync -avzP {} benutzer@server:/backup/{}
Komfortables rsync-ssh Script
- Die Exclude-Datei wird automatisch von der Übertragung ausgeschlossen, damit sie nicht auf den Server kopiert wird.
- Das Script speicherst du als
rsync-parallel-backup.sh und machst es ausführbar:
chmod +x rsync-parallel-backup.sh
Vor der Ausführung passt du die Werte im Bereich “Benutzerkonfiguration” an:
| Variable |
Bedeutung |
REMOTE_USER |
Benutzername auf dem Server |
REMOTE_HOST |
Server-Adresse oder Domain |
SSH_PORT |
SSH-Port (Standard: 22) |
LOCAL_SOURCE |
Lokales Quellverzeichnis |
REMOTE_TARGET |
Zielverzeichnis auf dem Server |
EXCLUDE_FILE |
Pfad zur Exclude-Datei (wird selbst ausgeschlossen) |
COMPRESSION |
yes oder no - bei schnellen Netzwerken no |
BANDWIDTH_LIMIT |
Bandbreitenlimit in KB/s, 0 für unbegrenzt |
RSYNC_EXTRA_OPTIONS |
Zusätzliche rsync-Optionen (z.B. --chmod=755) |
DRY_RUN |
"true" Testen - es werden keine Dateien übertragen oder gelöscht / "false" Echter Sync - Dateien werden übertragen und gelöscht |
Bei DRY_RUN="true" wird die rsync-Option --dry-run hinzugefügt. Das Script zeigt dann in der Ausgabe einen deutlichen Hinweis an, dass der Testmodus aktiv ist, und gibt nach Abschluss eine entsprechende Meldung aus.
#!/bin/bash
# ============================================================
# rsync-parallel-backup.sh - Hochperformantes paralleles Backup
# ============================================================
# Author: hoergen
# Date: 20260901
# URL: https://hyperblog.de/hoergen/
# -------------------- Benutzerkonfiguration --------------------
# SSH-Verbindungsdaten
REMOTE_USER="benutzer"
REMOTE_HOST="server.domain.de"
SSH_PORT="2222"
# Verzeichnisse
LOCAL_SOURCE="/daten"
REMOTE_TARGET="/backup/"
# Exclude-Datei (Pfad zur Datei mit Ausschlusslisten)
EXCLUDE_FILE="/pfad/zur/ausschlussliste.txt"
# Performance-Einstellungen
COMPRESSION="no" # "yes" oder "no" - bei schnellen Netzwerken "no"
BANDWIDTH_LIMIT="10000" # KB/s, 0 = unbegrenzt
# Testmodus
DRY_RUN="false" # "true" = Testlauf (--dry-run), "false" = echter Sync
# Zusätzliche rsync-Optionen (leer lassen wenn nicht benötigt)
RSYNC_EXTRA_OPTIONS=""
# -------------------- Ende Benutzerkonfiguration --------------------
error_exit() {
echo "FEHLER: $1" >&2
exit 1
}
# Prüfen, ob die lokale Quelle existiert
if [ ! -d "$LOCAL_SOURCE" ]; then
error_exit "Lokales Quellverzeichnis '$LOCAL_SOURCE' existiert nicht."
fi
# Exclude-Optionen zusammenbauen
EXCLUDE_OPTION=""
if [ -n "$EXCLUDE_FILE" ]; then
if [ -f "$EXCLUDE_FILE" ]; then
EXCLUDE_OPTION="--exclude-from=$EXCLUDE_FILE --exclude=$EXCLUDE_FILE"
echo "Verwende Exclude-Datei: $EXCLUDE_FILE"
else
echo "WARNUNG: Exclude-Datei '$EXCLUDE_FILE' existiert nicht. Fahre ohne Ausschlüsse fort."
fi
fi
# SSH-Optionen
SSH_OPTIONS="-p $SSH_PORT -c aes128-gcm@openssh.com -o Compression=no -o ServerAliveInterval=60"
# rsync-Optionen zusammenbauen
RSYNC_OPTIONS="-avP --delete $RSYNC_EXTRA_OPTIONS"
if [ "$COMPRESSION" = "no" ]; then
RSYNC_OPTIONS="$RSYNC_OPTIONS --no-compress"
fi
if [ "$BANDWIDTH_LIMIT" -gt 0 ]; then
RSYNC_OPTIONS="$RSYNC_OPTIONS --bwlimit=$BANDWIDTH_LIMIT"
fi
if [ "$DRY_RUN" = "true" ]; then
RSYNC_OPTIONS="$RSYNC_OPTIONS --dry-run"
fi
# Ausgabe der Konfiguration
echo "============================================================"
echo "rsync-backup.sh - Starte Backup"
echo "============================================================"
echo "Quelle: $LOCAL_SOURCE"
echo "Ziel: $REMOTE_USER@$REMOTE_HOST:$REMOTE_TARGET"
echo "SSH-Port: $SSH_PORT"
echo "Komprimierung: $COMPRESSION"
echo "Bandbreitenlimit: $BANDWIDTH_LIMIT KB/s"
echo "Exclude-Datei: ${EXCLUDE_FILE:-keine}"
echo "Testmodus (dry-run): $DRY_RUN"
echo "============================================================"
if [ "$DRY_RUN" = "true" ]; then
echo "ACHTUNG: Testmodus aktiv! Es werden keine Dateien übertragen oder gelöscht."
echo "============================================================"
fi
# Bestätigung abfragen
read -p "Mit diesen Einstellungen fortfahren? (j/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Jj]$ ]]; then
echo "Abgebrochen."
exit 0
fi
# Startzeit messen
START_TIME=$(date +%s)
echo "Starte Synchronisation um $(date)"
# Rsync-Befehl ausführen
rsync $RSYNC_OPTIONS -e "ssh $SSH_OPTIONS" $EXCLUDE_OPTION "$LOCAL_SOURCE/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_TARGET"
# Prüfen, ob der Befehl erfolgreich war
if [ $? -eq 0 ]; then
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "============================================================"
if [ "$DRY_RUN" = "true" ]; then
echo "Testlauf erfolgreich abgeschlossen!"
echo "Es wurden keine Dateien übertragen oder gelöscht."
echo "Zum Ausführen des echten Backups setze DRY_RUN='false'."
else
echo "Backup erfolgreich abgeschlossen!"
fi
echo "Dauer: $((DURATION / 60)) Minuten und $((DURATION % 60)) Sekunden"
echo "============================================================"
else
echo "FEHLER: Backup fehlgeschlagen!" >&2
exit 1
fi
exit 0