Cloudersatz für Dropbox & Co.

Wer einen Ersatz für Dropbox und Co. sucht, der landet in der Regel zuerst bei Owncloud oder Nextcloud. Das es auch andere Lösungsansätze gibt, über die man unter Umständen nachdenken sollte, beschreibt dieser Artikel.

Die Synchronisation erfolgt mit Tools wie incrond, Unison sowie kleinen Hilfsshellskripten. Lokale Änderungen werden somit direkt durch das inotify System der Linux Kernels bekannt gegeben. Die Anleitung wird auf einem Archlinux durchgeführt, läuft jedoch praktisch auf jeder Distribution.

Was vorausgesetzt wird, ist ein funktionstüchtiger Server, welcher als Gegenstelle für die Synchronisation dient. Dies kann ein Samba Server mit einem SMB / Cifs Mounts sein oder aber ein entfernter SSH Server, welcher mit Authentifizierung per Zertifikat eingerichtet ist. Theoretisch ist auch ein lokales Ziel möglich. Kurz gesagt, alles was Unison kann, ist hier natürlich ebenfalls realisierbar.

In dieser Anleitung gehen wir davon aus, dass der Benutzer Tux seine lokalen Dokumente auf einen entfernen Server per SSH übertragen möchte. Die Authentifizierung mittels SSH-Zertifikaten ist bereits eingerichtet und funktionstüchtig.

Synchronisation einrichten

Die Synchronisation erfolgt mit Unison. Dieses Programm befindet sich bei allen gängigen Distributionen in den Paketverwaltungen und kann über diese komfotabel installiert werden. Bei Arch erfolgt die Installation wie folgt:

$ sudo pacman -S unison

Ist das Programm installiert, erfolgt die Konfiguration. Im Homeverzeichnis des Benutzers existiert ein verstecktes Verzeichnis .unison, in welchen für jede Konfigurationseinstellung eine entsprechende Einstellungsdatei abgelegt wird. Auch werden später dort die Differnezdateien gespeichert.

Eine Konfigurationsdatei bekommt den Namen, mit der später das Konfigurationsprofil aufgerufen wird und erhält die Endung .prf. Es kann hier also ein sprechender Name gewählt werden und trägt in unserem Beispiel den Namen Dokumente.prf. In der Datei folgen nun zwei Zeilen root, welche nach das Quell- und das Zielverzeichnis beinhalten. Unter sshargs können nun weitere Parameter für SSH angegeben werden. In diesem Fall soll noch die Kompression aktiviert werden. Arbeitet man beispielsweise auf lokalen Mounts, dann ist diese Zeile nicht notwendig.

root = /home/Tux/Documents
root = ssh://remote_user@remote_server//home/Tux/Documents
sshargs = -C

Weitere Parameter und Einstellungen können in der Manpage oder auf der Webseite von Unison nachgelesen werden.

Hat man die Konfiguration erstellt, startet man Unison das erste mal per Hand. Das ist wichtig um vorhandene Differenzen zu ermitteln und aufzulösen. Unison fordert den Benutzer hier auf, diese zu beheben. Auch wenn noch keine Dateien im Zielverzeichnis vorhanden sind, so ist dies ein Konflikt da Unison nicht weiß, ob das Verzeichnis leer sein soll oder aber, ob die Dateien synchronisert werden sollen. Für den späteren automatisierten Aufruf ist es jedoch wichtig, dass Unison hier einen Zustannd kennt.

Der Aufruf von Unison erfolgt mit dem Parameter des oben erstellten Profilnamens. Der Parameter -times sorgt dafür, dass das Änderungsdatum mit synchronisiert wird.

$ unison -times Dokumente

Am Ende der Dateianalyse löst man die Konflikte auf. Durch das drücken von ? erhält man eine Hilfe, welche beschreibt, welche Aktionen ausgeführt werden können. Aktionen können für jede Datei einzeln oder aber für alle auf einmal durchgeführt werden.

Synchronisationsskript

Als nächstes schreiben wir ein kleines Shellskript, welches Unison aufruft. Dieses Skript ist an sich nicht notwendig, erleichtert aber die Pflege an sich. Auch ermöglicht diese die Erweiterung um weitere Unisonsynchronisationen aufzurufen, wenn später weitere Verzeichnisse synchronisert werden sollen.

Was wir jetzt ebenfalls schon berücksichtigen ist, dass wir verhindern, Unison mehrmals gleichzeitig aufzurufen. Dies kann später passieren wenn mehrere Aktionen in den zu überwachenden Verzeichnissen zur gleichen Zeit ausgelöst werden. Zum Einsatz kommt hier flock[4], welches das parallele Ausführen von Programmen verhindert.

Unser kleines Shellskript legen wir im bin Verzeichnis unseres Benutzers Tux ab und geben diesen dann mit chmod 750 ~/bin/syncFiles.sh entsprechende Berechtigungen zum Ausführen.

#!/bin/bash

### kein Parameter uebergeben
if [ -z ${1} ]; then
echo "Kein Parameter fuer Verarbeitung uebergeben..."
echo
exit 1
### Dokumente Sync
elif [ ${1} == "Dokumente" ]; then
/usr/bin/flock -n /tmp/Dokumente /usr/bin/unison -batch -auto -times -silent Dokumente
### kein gueltiger Parameter
else
echo "Kein gueltiger Parameter angegeben..."
echo
exit 1
fi
exit 0

Wird unsere syncFiles.sh Datei nun mit dem Parameter Dokumente aufgerufen, so wird Unison gestartet und das Dokumentenverzeichnis synchronisiert. Der Parameter -batch sorgt dafür, das Unison im Batchmode läuft und mit -auto immer die Standardaktion akzeptiert. Für eine automatische Synchronisation also genau das was wir möchten. -silent unterdrückt noch alle Meldungen bis auf Fehler was für Ruhe im interaktiven Aufruf sorgt.

Mit einem ./bin/syncFiles.sh Dokumente testen wir nun das eben erzeugte Skript. Funktioniert dieses wie erwartet können wir fortfahren und eine Automatisierung einrichten.

Inotify Cron Daemon

Eine Synchronisation soll immer dann erfolgen, wenn sich eine Datei im zu überwachenden Verzeichnis ändert. Das Inotify Subsytem liefert und genau die Grundlage dafür, die wir hier benötigen. Inotify Cron Daemon läuft im Hintergrund und führt bei bestimmten Änderungen im Dateisystem Befehle aus. Das Ganze funktioniert ähnlich dem normalen crond nur das anstatt Zeitperionden inotify Aktionen der Auslöser sind.

incrond ist in allen gängingen Distributionen enthalten aber nicht standardmäßig installiert. Die Installation muss also über die entsprechende Paketverwaltungen nachgeholt werden.

$ sudo pacman -S incron

Auch der incrond hat eine Tabelle für die Cronjobs. Der Befehl zum Verwalten dieser lautet incrontab. Die Parameter sind hierbei analog des normalen crontab Befehls. Also -e für editieren und -l für anzeigen.

Der Aufbau der Einträge ist jedoch anderst. Der erste Parameter ist der Pfad, welcher überwacht werden soll. Danach folgen kommagetrennt die Parameter, auf welche der Eintrag reagieren soll. Zum Schluss wird noch der Befehl angegeben, welcher beim eintretenden Ereignis aufgerufen werden soll.

Mit incrontab -e editieren wir nun die Crontabelle unseres Benutzers und fügen hier einen neuen Eintrag hinzu:

/home/Tux/Documents IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_DONT_FOLLOW /home/Tux/bin/syncFiles.sh Dokumente

Überwacht wird hier das Dokumentenverzeichnis unseres Benutzers Tux. Es ist das gleiche Verzeichnis, welches wir auch in unserer Unison Konfiguration verwendet haben. Ausgeführt soll das Skript wenn eine Datei erzeugt, gelöscht oder geschrieben wird. Das IN_DONT_FOLLOW verhindert, dass symbolischen Links gefolgt wird. Natürlich können diese Parameter den persönlichen Bedürfnissen angepasset werden. Als letzer Parameter wird unser oben erzeugtes Skript mit unserem Parameter aufgerufen. In diesem Zusammenhang macht nun auch das flock Sinn, da beim einfügen oder ändern vieler Dateien natürlich sehr viele Ereignisse ausgelöst werden. Das würde dann zu unnötigen Fehlern bzw. Sperren bei Unison führen welche wir somit abfangen.

Je nach verwendeter Version von incrond werden Unterverzeichnisse mit überwacht oder nicht. In der Version 0.5.12 wurde diese Funktion hinzugefügt. Hat man diese Version nicht, so muss man für jedes Unterverzeichnis einen eigenen Eintrag in der icrontag anlegen oder alternativ eine eigene Version aus den Sourcen bauen.

Nun wird es Zeit, den incrond zu starten und zu prüfen, ob auch Änderungen synchronisiert werden.

$ sudo systemctl start incrond
$ journalctl -u incrond

Legen wir nun eine Datei in das Dokumentenverzeichnis, so sollte im Logjournal einen Transfer sehen sein. Auch sollte die Datei sich auf dem Zielsystem befinden. Beim Löschen das gleiche. Ist dies der Fall, so sollte man natürlich dafür Sorge tragen, dass der incrond immer mit dem System gestartet wird.

$ sudo systemctl enable incrond

Nacharbeiten und Einschränkungen

Ein paar Nacharbeiten gibt es noch. Diese sind notwendig, wenn man die Synchronisation auf mehreren Systemen laufen lässt. Da die Jobs nur gestartet werden, wenn eine lokale Änderung erfolgt, bekommt das Skript natürlich nicht mit, wenn auf einem anderen System etwas geändert wird. Es ist also sinnig, direkt nach dem Systemstart das Skript laufen zu lassen. Dies kann zum Beispiel durch ein systemd-Skript geschehen. Dies könnte zum Beispiel wie folgt aussehen:

[Unit]
Description=Startet die Synchronisation
Requires=network.target
After=network.target
Conflicts=umount.target
Before=umount.target shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
User=tobias
Group=tobias
RemainAfterExit=true
ExecStart=/home/tux/bin/syncJob.sh Dokumente
ExecStop=/home/tux/bin/syncJob.sh Dokumente

[Install]
WantedBy=multi-user.target

Problematisch wird das Ganze, wenn das Verzeichnis auf mehreren Systemen zur gleichen Zeit benutzt wird. Hier kommt diese Lösung an ihre Grenzen da eine Synchronisation nicht zuverlässig auf allen Systemen gestartet werden kann.

Ebenfalls ist diese Lösung nur auf Linux Systemen so umsetzbar. Inotify funktioniert unter Windows nicht weshalb man dort andere Lösungsansätze beschreiten muss.

Fazit

Einzelbenutzer, welche ihre eigenen Linuxsysteme ohne Dritte synchronisieren möchten, können über diesen Weg eine einfache und kostengünstige Lösung aufbauen. Auch liegt hier die Datenhoheit voll beim entsprechenden Anwender, der selbst entscheidet auf welche Systeme die Daten kopiert werden. Durch den Einsatz von verschiedenen Unison Profilen können auch die Verzeichnisse verteilt im System liegen. Es muss also kein zentraler Ordner wie bei der Dropbox verwendet werden.

Bekannte Probleme

Unter Arch Linux erzeugt der icrond Zombie Prozesse. Die Zahl dieser Prozesse steigt praktisch ins unendliche wenn man sehr viele Dateien synchronisiert. Ein schmutziger Workaround ist hier, als root einen Cron-Job einzurichten, der den incrond bei dem Erreichen eines Schwellenwertes von Zombieprozessen, diesen neu zu starten.

*/5 * * * * if [ `ps aufxw | grep "<defunct>" | wc -l` -gt 500 ]; then systemctl restart incrond; fi

Kommentare:

Was ist die Summe aus 9 und 1?