rsync

Siehe auch

rsync dient der Synchronisation von Dateien und Verzeichnissen, auch über Rechnergrenzen hinweg. Mit rsync ist sowohl das Netzwerkprotokoll als auch die gleichnamige Programm-Implementierung gemeint.

Bei rsync läuft die Synchronisation immer unidirektional von einem Quellverzeichnis oder einer Datei (in den Beispielen src) zu einem Zielverzeichnis oder einer Datei ab (dest). Per Parameter lässt sich unter anderem steuern, ob Dateien im Zielverzeichnis auch gelöscht werden sollen, wenn sie im Quellverzeichnis nicht mehr existieren. Während der Synchronisation werden nur die geänderten Teile der Dateien übertragen (Delta-Kodierung), was Zeit spart. Abgebrochene Transfers werden ab der Stelle wieder aufgenommen, an denen wirklich abgebrochen wurde.

Endet eine Verzeichnisangabe mit einem /, wechselt rsync in das Verzeichnis, ignoriert den Verzeichnisnamen und verarbeitet alle Dateien innerhalb des Verzeichnisses; fehlt der abschliessende Slash, wird der Verzeichnisname berücksichtigt und dieser ebenfalls gesynct.

Installation:

yum -y install rsync

Kurz- vs. Lang-Parameter:

  • -A: --acls

  • -D: --devices --specials

  • -g: --group

  • -H: --hard-links

  • -l: --links

  • -o: --owner

  • -p: --perms

  • -r: --recursive

  • -t: --times

  • -X: --xattrs

Nützliche Parameter:

  • --archive:
    Ist die Kurzform für -rlptgoD. Meist wird er durch --human-readable und --progress ergänzt.
  • --checksum
    rsync soll nicht anhand von Modifikationsdatum, sondern anhand on Checksummen arbeiten.
  • --delete:
    Löscht Dateien im Zielverzeichnis, die im Quellverzeichnis nicht mehr existieren.
  • --dry-run
    Test-Modus.
  • --exlude:
    Dateien und/oder Verzeichnisse von der Synchronisation ausnehmen. Der Parameter kann mit Wildcards arbeiten und mehrfach verwendet werden.
  • --one-file-system:
    Lokal bleiben, Dateien auf Netzwerk-Mounts ignorieren.
  • --password-file /path/to/secrets.rsync:
    Datei, die das Passwort für den Zugriff auf einen per rsync-Daemon exportiertes Verzeichnis enthält. Muss per chmod 0400 geschützt werden.
  • --times:
    Zeitstempel beim Kopieren behalten.
  • --update:
    Ist die Datei im Zielverzeichnis neuer, wird sie nicht kopiert.

Verwendung von rsync

Der einfachste Aufruf: alle Dateien der obersten Verzeichnisebene synchronisieren:

rsync src dest

Eine Datei von lokal auf einen entfernten Server kopieren (ohne weitere Angaben wird das per SSH erledigt):

rsync --archive --human-readable --progress --verbose src user@host:dest

Gewünschte Art der Remoteverbindung spezifizieren und für SSH zum Beispiel den Port ändern:

rsync --archive --human-readable --progress --verbose --rsh "ssh -p 2222" user@host:src dest

Eine Datei von lokal auf einen entfernten Server kopieren, hier per rsync:

rsync --archive --human-readable --progress --verbose src rsync://user@host:dest

Sync mit Ausnahmen von einem per rsync:// erreichbarem, entfernten Verzeichnis auf ein lokales Verzeichnis. Passwort wird nicht in einer Datei definiert, sondern als Umgebungsvariable gesetzt:

export RSYNC_PASSWORD=myrsyncpwd
rsync --archive --human-readable --progress --verbose --exclude=cache --exclude=files/*.pdf --delete rsync://user@host:src dest

Gegen einen rsync-Daemon authentifizieren; Passwort wird in einer Datei definiert:

secrets.rsync
mypassword
chmod 0600 secrets.rsync

rsync --human-readable --verbose --recursive --times --update --delete --password-file secrets.rsync src rsync://user@host:dest

Sync auf Basis einer Datei-Liste - nur ausgewählte Dateien auf einen Remote-Host kopieren. Hier wird ausgehend vom aktuellen Verzeichnis die relativ organisierte Datei-Liste abgearbeitet:

rsync --archive --human-readable --progress --files-from=myfilelist . host:dest

Rsync nice und bandbreitenschonend laufen lassen, in Units per Second (hier KByte/sec):

/usr/bin/nice --adjustment 19 /usr/bin/rsync --bwlimit 1.5K --archive --human-readable --progress --verbose src dest

Daemon-Mode

Für den Daemon-Modus muss ein Username/Passwort und eine Liste der zu exporierenden Verzeichnisse konfiguriert werden.

/etc/rsyncd.secrets
myuser1:mypassword1
myuser2:mypassword2
chmod 0600 /etc/rsyncd.secrets

Im Beispiel wird /etc als etc und /var/www/html als var-www-html exportiert. Der anzugebene Benutzername gilt nur innerhalb von rsync, muss also nicht auf dem System existieren:

/etc/rsyncd.conf
 1# global parameters go here
 2auth users = myuser1,myuser2
 3gid = root
 4lock file = /var/lock/subsys/rsync.lock
 5log file = /var/log/rsyncd.log
 6pid file = /var/run/rsyncd.pid
 7read only = yes
 8secrets file = /etc/rsyncd.secrets
 9uid = root
10
11[etc]
12path = /etc
13
14[var-www-html]
15path = /var/www/html

In SELinux erlauben, dass diese (eigentlich alle) Verzeichnisse read-only exportiert werden dürfen:

setsebool -P rsync_export_all_ro on

# and, if more needed (for /var/spool/postfix for example)
setsebool -P rsync_full_access on

Start des Daemons:

systemctl enable --now rsyncd

Firewall einrichten und Port 873 (tcp und udp) freigeben, zum Beispiel per

firewall-cmd --permanent --add-service=rsyncd
firewall-cmd --reload

rsync-Logdateien über Logrotate aufräumen, im Beispiel nach 14 Tagen:

cat >/etc/logrotate.d/rsync <<EOF
/var/log/rsyncd.log {
    compress
    daily
    dateext
    missingok
    rotate 14
    size 1
}
EOF

Der Client synct dann beispielshalber per:

export RSYNC_PASSWORD=mypassword1
rsync --archive rsync://myuser1@host:/var-www-html .

Robustes Backup-Skript mit Deduplizierung

Das nachfolgende Backup-Skript arbeitet mit Backup-Ordnern beginnend bei „00“ zum Beispiel bis „99“, wobei „00“ das aktuellste und „99“ das älteste Backup enthält. Die Backups werden bei jedem Aufruf rotiert - das älteste Backup „99“ wird entfernt, aus „98“ wird „99“ usw., bis aus „00“ das Verzeichnis „01“ wird. Mit Hilfe von rsync wird synchronisiert, mit Hilfe von Hard-Links wird dedupliziert und nur das gesichert, was sich geändert hat. Jedes Verzeichnis enthält durch die durchgehende Verwendung von Hard-Links die gesamte Quell-Verzeichnisstruktur, so dass sich ein Restore sehr einfach durchführen lässt. Die zu sichernden Rechner und deren Verzeichnisse werden in einer CSV-Datei gepflegt.

mycoolbackup.sh
 1#!/usr/bin/env bash
 2
 3# call with parameter: "backup daily.conf|weekly.conf|... myhostlist.csv"
 4
 5LOCK_FILE=/var/lock/subsys/backup-$(basename $1 | cut -d. -f1)
 6
 7if [ -f $LOCK_FILE ]; then
 8    logger "$0 - Backup is already running, exiting..."
 9    exit 1
10fi
11touch $LOCK_FILE
12
13# include configuration file given via first parameter
14BACKUP_TYPE=$1
15BACKUP_LIST=$2
16source "$BACKUP_TYPE"
17
18# create structure for backups if it does not exist
19mkdir -p $BACKUP_DIR
20for (( i = 0; i <= $BACKUP_MAX ; i++ ))
21do
22    if [ ${#i} == 1 ]; then
23        mkdir -p $BACKUP_DIR/0$i
24    else
25        mkdir -p $BACKUP_DIR/$i
26    fi
27done
28
29# rotate backup folders
30\mv $BACKUP_DIR/$BACKUP_MAX $BACKUP_DIR/tmp
31for (( i = $BACKUP_MAX ; i > 0 ; i-- ))
32do
33    j=$(($i - 1))
34    if [ ${#j} == 1 ]; then
35        j="0$j"
36    fi
37    if [ ${#i} == 1 ]; then
38        \mv $BACKUP_DIR/$j $BACKUP_DIR/0$i
39    else
40        \mv $BACKUP_DIR/$j $BACKUP_DIR/$i
41    fi
42done
43\mv $BACKUP_DIR/tmp $BACKUP_DIR/00
44
45# now let's do the backup
46cd $BACKUP_DIR
47
48# the backup takes place here, based on CSV files
49while IFS=\; read -r SERVER SRC OPTIONS
50do
51    if [ "$SERVER" != "" ]; then
52        if [ "${SERVER:0:1}" != "#" ]; then
53
54            TS=$(date +"%Y-%m-%d %H:%M:%S")
55            mkdir -p 00/$SERVER
56
57            echo "-------------------------------------------------------------------------------"
58            echo "Job:"
59            echo "* Current Dir:     $(pwd)"
60            echo "* Source Dir:      $SERVER:$SRC"
61            echo "* Destination Dir: 00/$SERVER$SRC/"
62            echo "* Options:         $OPTIONS"
63            echo -n "* Start:           "; echo $TS
64            logger "$0 - $TS - $SERVER:$SRC - Start"
65
66            rsync --rsh="ssh" --recursive --links --perms --group --owner --devices --specials \
67                  --human-readable --compress --compress-level=9 --checksum --delete \
68                  $OPTIONS --link-dest=../../01/$SERVER $SERVER:$SRC 00/$SERVER
69
70            TS=$(date +"%Y-%m-%d %H:%M:%S")
71            echo "* Stop:            $TS\n";
72
73            logger "$0 - $TS - $SERVER:$SRC - Stop"
74        fi
75    fi
76done < $BACKUP_LIST
77
78echo "-------------------------------------------------------------------------------"
79echo "Finished."
80
81logger "$0 - finished"
82rm -f $LOCK_FILE

Eine passende Konfigurationsdatei dazu:

daily.conf
1#!/usr/bin/env bash
2
3# where to store the backups
4BACKUP_DIR=/backup/daily
5
6# number of backups: 01, 30, 99, whatever (don't forget the leading zero)
7BACKUP_MAX=99

Eine passende Serverliste, die angibt, welche Dateien und Verzeichnisse mit welchen Optionen zu sichern sind:

daily.csv
1# expecting "SERVER;SRC[; RSYNC-OPTIONS]" - don't forget an empty last line
2
3server1;/etc;--exclude-from=exclude-filelist.server.txt
4
5server2;/boot
6server2;/etc
7server2;/root

Aufruf mit:

mycoolbackup.sh daily.conf daily.csv

Troubleshooting

rsync: opendir „/.“ (in dest) failed: Permission denied (13)

Neustart des rsync-Daemons, oder der rsyncd wird durch SELinux daran gehindert, die konfigurierten Verzeichnisse zu exportieren (setsebool -P rsync_export_all_ro on ausführen).

rsync: rsync_xal_set: lremovexattr(„/backup“,“security.selinux“) failed: Permission denied (13)

Taucht bei Verwendung von --acls --xattrs mit Quelle:xfs und Ziel:ZFS auf.

rsync --archive erzeugt trotz bzw. zusammen mit --checksum und --link-dest keine Hard-Links, wenn sich der Timestamp einer Datei, aber nicht deren Inhalt geändert hat.

Hier hilft nur, --archive wegzulassen und selbst anzugeben, sowie die Option --time dabei zu entfernen (--archive = -rlptgoD no -H,-A,-X; daraus macht man --recursive, --links, --perms, --group, --owner, --acls, --xattrs, --devices --specials).

Built on 2022-06-03