Nextcloud und Fileserver automatisch abgleichen
Eine gehostete Nextcloud ist bequem, solange das Internet funktioniert. Fällt die Verbindung aus, sind die Daten aber nicht erreichbar. Ein Fileserver im Heimnetz, der eine vollständige Kopie der Nextcloud hält, schließt diese Lücke und ist zugleich der ideale Ausgangspunkt für lokale Sicherungen. nc-bisync.sh hält diese Kopie mit rclone bisync automatisch auf dem aktuellen Stand. Es läuft unbeaufsichtigt per Cron und schlägt nur Alarm, wenn etwas auffällig ist.
Download: nc-bisync.sh
Die Ausgangslage
Die Nextcloud ist die zentrale Ablage, der Fileserver spiegelt sie ins Heimnetz:
Laptops, Handys ⇄ Nextcloud-Client ⇄ Nextcloud
⇅ rclone bisync (automatisch)
Fileserver → SMB-Freigaben im Heimnetz
│
└─ rsnapshot (täglich, versioniert) → externe Platte
Laptops und Handys synchronisieren sich wie gewohnt mit dem Nextcloud-Client. Der Fileserver gleicht sich regelmäßig mit der Nextcloud ab und ist über seine SMB-Freigaben im Heimnetz erreichbar. Fällt die Internetverbindung aus, liegt dort trotzdem eine vollständige Kopie aller Daten. Weil der Abgleich in beide Richtungen läuft, gelangen auch Dateien, die direkt auf dem Fileserver abgelegt werden, in die Nextcloud. Gesichert wird vom Fileserver aus, unabhängig vom Anbieter.
Für den Abgleich ist rclone bisync gut geeignet: rclone spricht WebDAV direkt an und braucht keinen davfs-Mount. Außerdem bringt es Schutzmechanismen mit, die sonst ein eigenes Wrapper-Skript erfordern würden.
Was das Skript macht
Ein Verzeichnispaar je Freigabe. Jede Freigabe auf dem Fileserver wird mit dem entsprechenden Ordner in der Nextcloud abgeglichen, unabhängig von den anderen. Paare lassen sich einzeln oder in Gruppen starten, auch mit unterschiedlicher Frequenz. Bei Bedarf wird ein einzelner Unterordner, etwa ein großes Projekt, zum eigenen Paar und im übergeordneten Paar automatisch ausgeschlossen.
Archiv nur auf Anforderung. Ein Unterordner archiv innerhalb eines Paares wird im normalen Lauf nie abgeglichen, sondern nur mit --archiv. Er ist intern ein eigenes Paar mit eigenem Zustand. Das ist stabiler als ein Ordner, der per Filter mal ein- und mal ausgeschlossen wird.
Schutz vor Massenschäden. Gegen größere Schäden sichern drei eingebaute Mechanismen ab:
--check-access: In jeder Wurzel liegt eine DateiRCLONE_TEST. Fehlt sie auf einer Seite, weil ein Pfad falsch ist oder ein Laufwerk nicht eingehängt ist, bricht der Lauf ab. Das schützt auch davor, dass ein leerer Bind-Mount als „alles gelöscht“ in die Nextcloud übertragen wird.--max-delete 10: Würden mehr als 10 % der Dateien gelöscht, passiert gar nichts.--backup-dir1: Überschriebene und gelöschte Dateien auf dem Fileserver landen in einem Tagesordner und werden nach 30 Tagen aufgeräumt.
Konflikte. Wurde eine Datei auf beiden Seiten geändert, gewinnt die neuere Version (--conflict-resolve newer). Die ältere bleibt umbenannt erhalten.
Robustheit. Mit --resilient und --recover übersteht bisync abgebrochene Läufe meist ohne manuellen --resync. Eine Sperrdatei verhindert überlappende Läufe.
Benachrichtigung. Bei Fehlern kommt eine Nachricht per Mail oder über ntfy. Das Skript unterscheidet dabei, ob ein Resync nötig ist, die Löschgrenze angeschlagen hat oder die Zugriffsprüfung fehlgeschlagen ist. Jeder Lauf wird mit seiner Dauer in summary.log protokolliert.
Filter. Temporärdateien von Office, macOS und Windows werden nie synchronisiert.
Voraussetzungen
Auf dem Fileserver:
- Linux mit
bashab Version 4 und den Standardwerkzeugenflock(aus util-linux),findundcmp. Auf Debian, Ubuntu und Raspberry Pi OS ist das alles vorinstalliert. - rclone 1.66 oder neuer, siehe Schritt 1.
- Ein Benutzer mit Schreibrechten auf die synchronisierten Verzeichnisse, unter dem das Skript läuft.
- Optional
curlfür Push-Nachrichten über ntfy und ein eingerichteter Mailversand für Mail-Benachrichtigungen, siehe Schritt 7.
In der Nextcloud:
- Ein Konto mit WebDAV-Zugriff und einem App-Passwort.
- Die Zielordner; fehlende legt
--initselbst an.
Setup
Das Skript läuft nicht als root, sondern als der Benutzer, dem die Dateien auf dem Fileserver gehören. Sonst gehörten neu aus der Nextcloud geholte Dateien root und wären für die anderen Benutzer der Freigabe nicht mehr beschreibbar. sudo ist nur für die Installation nötig.
1. rclone installieren
Das Skript braucht rclone 1.66 oder neuer. Die Pakete vieler Distributionen sind älter, deshalb besser das offizielle Installationsskript verwenden:
curl https://rclone.org/install.sh | sudo bash
rclone version
2. Nextcloud-Remote einrichten
Lege in der Nextcloud unter Einstellungen → Sicherheit ein App-Passwort an. Richte dann als der Benutzer, unter dem das Skript später läuft, den Remote ein (ohne sudo):
rclone config
# n) New remote
# name> nc
# Storage> webdav
# url> https://cloud.example.com/remote.php/dav/files/BENUTZERNAME/
# vendor> nextcloud
# user> BENUTZERNAME
# pass> (App-Passwort)
Zum Test:
rclone lsd nc:
3. Skript installieren und anpassen
sudo install -m 755 nc-bisync.sh /usr/local/bin/nc-bisync.sh
sudo install -d -o BENUTZER /var/lib/nc-bisync /var/log/nc-bisync
sudo install -d -o BENUTZER -m 700 /mnt/USB-Crucial/.bisync-backup
Der Modus 755 macht das Skript für alle Benutzer ausführbar, verändern kann es aber nur root. Die zweite Zeile legt das Status- und das Log-Verzeichnis an und übergibt sie dem Benutzer, unter dem das Skript läuft. Die dritte legt das Backup-Verzeichnis (BACKUP_ROOT) an; Modus 700, weil dort überschriebene Dateien aus allen Freigaben landen und nur der Benutzer des Skripts sie sehen soll.
Im Konfigurationsblock am Anfang trägst du die Paare ein, je Zeile Name, lokaler Pfad und Pfad in der Nextcloud:
PAIRS=(
"administration|/mnt/shares/administration|nc:Administration"
"bibliothek|/mnt/shares/bibliothek|nc:Bibliothek"
"dokumente|/mnt/shares/dokumente|nc:Dokumente"
"fotos|/mnt/shares/fotos|nc:Fotos"
"projekte|/mnt/shares/projekte|nc:Projekte"
"unternehmen|/mnt/shares/unternehmen|nc:Unternehmen"
)
Weitere Einstellungen:
| Variable | Bedeutung | Beispiel |
|---|---|---|
ARCHIVE_SUBDIR |
Unterordner, der nur mit --archiv läuft |
archiv |
BACKUP_ROOT |
Ablage für überschriebene Dateien | /mnt/USB-Crucial/.bisync-backup |
MAX_DELETE |
Löschgrenze in Prozent | 10 |
NOTIFY_MAIL |
Empfänger für Fehlermeldungen (optional) | admin@example.com |
NTFY_URL |
ntfy-Topic für Push-Nachrichten (optional) | https://ntfy.sh/mein-topic |
Achte darauf, dass BACKUP_ROOT außerhalb aller Paare liegt. Mit nc-bisync.sh --list prüfst du, welche Paare konfiguriert sind und welche einen Archiv-Unterordner haben.
4. Gruppenrechte auf dem Fileserver
Das Skript legt neue Dateien mit umask 002 an, damit sie für die Gruppe beschreibbar bleiben. Damit sie auch die richtige Gruppe bekommen und nicht die primäre Gruppe des Benutzers, sollten die synchronisierten Verzeichnisse das setgid-Bit haben. Das setgid-Bit an einem Verzeichnis bewirkt, dass darin neu angelegte Dateien und Unterordner automatisch dessen Gruppe erben, statt die primäre Gruppe ihres Erstellers zu bekommen.
Für die Paare aus dem Beispiel oben setzt du es so auf allen vorhandenen Verzeichnissen:
for d in administration bibliothek dokumente fotos projekte unternehmen; do
sudo find "/mnt/shares/$d" -type d -exec chmod g+s {} +
done
Ob es gesetzt ist, erkennst du an einem s in den Gruppenrechten:
$ ls -ld /mnt/shares/dokumente
drwxrws--- 10 stefan familie 4,0K 21. Jul 13:19 /mnt/shares/dokumente
5. Erstabgleich
Teste zuerst mit --dry-run, dann führe den Erstabgleich aus:
nc-bisync.sh --init --dry-run
nc-bisync.sh --init
--init legt die RCLONE_TEST-Dateien in jedem Paar und jedem vorhandenen Archiv-Unterordner an und gleicht alles mit --resync ab. Bei Unterschieden gewinnt die neuere Datei. Bei vielen Daten bietet es sich an, die Paare einzeln einzurichten, zum Beispiel nc-bisync.sh --init fotos.
Im Probelauf ändert das Skript nichts: Es legt auch keine RCLONE_TEST-Dateien an und überspringt deshalb die Zugriffsprüfung.
6. Zeitplan
Trage die Cronjobs mit crontab -e in die Crontab des Benutzers ein, unter dem das Skript läuft. Weil jedes Paar eine eigene Sperre hat, können häufig geänderte Freigaben öfter laufen als selten geänderte:
# häufig geändert: alle 2 Stunden
0 */2 * * * /usr/local/bin/nc-bisync.sh dokumente fotos projekte unternehmen administration
# selten geändert: nachts
30 2 * * * /usr/local/bin/nc-bisync.sh bibliothek
Bei vielen Dateien bremst nicht die Übertragung, sondern das Auflisten über WebDAV, und das passiert bei jedem Lauf vollständig. Starte deshalb mit zwei Stunden und lies nach ein paar Tagen die Laufzeiten ab:
tail /var/log/nc-bisync/summary.log
Als Faustregel sollte das Intervall etwa dreimal so lang sein wie ein Lauf. Allzu häufig solltest du nicht abgleichen, denn manche Anbieter drosseln viele WebDAV-Anfragen.
7. Benachrichtigungen einrichten (optional)
Bleiben NOTIFY_MAIL und NTFY_URL leer, schreibt das Skript Fehler nur in summary.log. Für einen unbeaufsichtigten Betrieb solltest du mindestens einen der beiden Wege einrichten; beide lassen sich auch kombinieren.
Mail (NOTIFY_MAIL). Das Skript verschickt die Nachricht mit dem Befehl mail. Dafür muss ein entsprechendes Paket installiert sein, etwa mailutils oder bsd-mailx, und der Server muss Mails nach außen zustellen können. Am einfachsten gelingt das mit msmtp-mta, das die Mails über das SMTP-Konto deines Mailanbieters verschickt. Ob es funktioniert, prüfst du als der Benutzer des Skripts:
echo "Test" | mail -s "Test von nc-bisync" admin@example.com
Fehlt der Befehl mail, überspringt das Skript den Mailversand ohne Fehlermeldung.
Push-Nachricht (NTFY_URL). Dafür braucht der Server curl. Installiere die ntfy-App auf dem Handy und abonniere dort ein Topic. Auf dem öffentlichen Server ntfy.sh ist kein Konto nötig, dafür kann jeder mitlesen, der den Namen des Topics kennt. Wähle deshalb einen langen, zufälligen Namen, zum Beispiel https://ntfy.sh/nc-bisync-7f3k9x2q. Zum Test:
curl -d "Test von nc-bisync" https://ntfy.sh/nc-bisync-7f3k9x2q
Ein eigener ntfy-Server funktioniert genauso. Topics, die eine Anmeldung oder ein Zugriffstoken verlangen, unterstützt das Skript in der jetzigen Form nicht.
Verwendung im Alltag
| Befehl | Wann |
|---|---|
nc-bisync.sh |
alle Paare abgleichen, ohne Archiv |
nc-bisync.sh fotos dokumente |
nur die genannten Paare abgleichen |
nc-bisync.sh --archiv projekte |
nachdem in projekte Dateien archiviert wurden |
nc-bisync.sh --dry-run fotos |
vorher anzeigen, was passieren würde |
nc-bisync.sh --archiv --force projekte |
wenn beim Archivieren die Löschgrenze angeschlagen hat |
nc-bisync.sh --list |
konfigurierte Paare anzeigen |
rclone-Optionen mit Wert gibst du immer in der Form --option=wert an, sonst hält das Skript den Wert für den Namen eines Paares.
Dateien archivieren
Verschiebe die Dateien innerhalb der Freigabe in den Unterordner archiv und starte dann den Abgleich für diese Freigabe:
nc-bisync.sh --archiv projekte
Das Skript gleicht zuerst das Archiv ab und erst danach den Rest der Freigabe. So liegen die Dateien schon im Archiv der Nextcloud, bevor sie dort aus dem Rest der Freigabe verschwinden. Schlägt der Archiv-Lauf fehl, wird der Rest der Freigabe gar nicht angefasst.
Verschiebst du sehr viele Dateien auf einmal, kann die Löschgrenze greifen. Prüfe dann kurz das Log und starte mit --force.
Ein Archiv richtest du nachträglich ein, indem du lokal den Ordner archiv anlegst und einmal nc-bisync.sh --init NAME ausführst.
Einzelne Unterordner als eigenes Paar
Wird eine Freigabe zu groß für häufige Läufe, kann ein Unterordner ein eigenes Paar bekommen:
"tango|/mnt/shares/projekte/Tango|nc:Projekte/Tango"
Das Skript schließt Tango dann im Paar projekte automatisch aus. Weil sich dadurch dessen Filter ändert, ist einmal nc-bisync.sh --init projekte tango nötig. Der Unterordner muss in der Nextcloud an der entsprechenden Stelle liegen, sonst bricht das Skript mit einer Meldung ab.
Wenn eine Benachrichtigung kommt
- Resync nötig: Lies die Ursache im genannten Log nach. Danach behebt meist
nc-bisync.sh --init NAMEden Zustand, vorher am besten mit--dry-run. - Zu viele Löschungen: Prüfe, ob die Löschungen gewollt sind. Wenn ja, starte mit
--force. - Zugriffsprüfung fehlgeschlagen: Eine
RCLONE_TEST-Datei fehlt. Prüfe, ob der Pfad stimmt, die Nextcloud erreichbar ist und das Laufwerk gemountet ist.
Fehlerbehebung
Verbindungsabbrüche bei großen Übertragungen
Symptome. Vor allem beim Erstabgleich großer Datenmengen tauchen im Log bei einzelnen Dateien Fehler wie dieser auf:
ERROR : 2014/…/IMG_0929.PNG: Failed to copy: unchunked simple update failed: Put "https://…":
http2: Transport: cannot retry err [http2: Transport received Server's graceful shutdown GOAWAY]
after Request.Body was written; define Request.GetBody to avoid this error
Der Lauf bricht dabei nicht ab, sondern überträgt die übrigen Dateien weiter. Am Ende eines Erstabgleichs meldet bisync trotzdem Bisync aborted. Must run --resync to recover., denn beim --resync genügt schon eine einzige fehlgeschlagene Datei. In der Zusammenfassung stehen dann zum Beispiel 100 % übertragen, aber mehrere Fehler.
Was bei HTTP/2 nicht klappt. HTTP/2 schickt viele Anfragen gleichzeitig über eine einzige Verbindung. Der Server oder ein vorgeschalteter Proxy beendet diese Verbindung irgendwann geordnet mit einem GOAWAY, etwa nach einer festen Zahl von Anfragen oder bei einem Neustart. Anfragen, die noch nicht begonnen haben, kann der Client problemlos über eine neue Verbindung schicken. Bei Uploads, deren Daten schon unterwegs waren, gelingt das nicht: Der Dateiinhalt ist bereits abgeschickt und kann an dieser Stelle nicht ein zweites Mal gesendet werden. Die Datei schlägt fehl.
Was bei HTTP/1.1 anders ist. Hier läuft jede Anfrage über eine eigene Verbindung. Schließt der Server eine davon, betrifft das nur diese eine Übertragung, und rclone wiederholt sie mit seinen normalen Wiederholungsversuchen über eine neue Verbindung. Weil rclone ohnehin mehrere Dateien parallel überträgt, ist HTTP/1.1 in der Praxis kaum langsamer.
Workaround für einen einzelnen Lauf. Meist reicht es schon, den Lauf einfach zu wiederholen: Die Abbrüche treten nur sporadisch auf, und beim nächsten Versuch werden die fehlgeschlagenen Dateien in der Regel doch noch übertragen. Bereits übertragene Dateien werden dabei nur verglichen, nicht erneut hochgeladen. Andernfalls bleibt das Ausweichen auf HTTP/1.1. Alle Optionen, die das Skript nicht selbst kennt, reicht es an rclone weiter. So wiederholst du einen gescheiterten Erstabgleich mit HTTP/1.1:
nc-bisync.sh --init fotos --disable-http2
Dauerhaft abschalten. Jede rclone-Option lässt sich auch als Umgebungsvariable RCLONE_<OPTION> setzen. Trag dazu im Konfigurationsblock des Skripts diese Zeile ein:
export RCLONE_DISABLE_HTTP2=true
Damit nutzen alle rclone-Aufrufe des Skripts HTTP/1.1, auch die im Cronjob.
Grenzen
rclone bisync ist kein Backup. Der Abgleich überträgt auch versehentliche Änderungen, nur Massenlöschungen werden abgefangen. Verschlüsselt etwa Ransomware Dateien auf einem Laptop, landen sie über den Nextcloud-Client in der Nextcloud und per bisync auch auf dem Fileserver, denn dabei wird überschrieben, nicht gelöscht. Die überschriebenen Fassungen liegen dann zwar noch 30 Tage im Backup-Verzeichnis, den eigentlichen Schutz bilden aber die versionierten rsnapshot-Sicherungen und die Dateiversionen der Nextcloud. Die Aufbewahrungszeit sollte länger sein als die Zeit, bis man einen Schaden bemerkt.