Zugriffsrechte auf geteilte Dateien und Ordner mit AFP und NAS4Free

FreeNAS 7 wird seit einiger Zeit nicht mehr unter diesem Namen weiterentwickelt. Das Projekt NAS4Free hat sich dem Sourcecode angenommen. Ich hatte zwar zwischenzeitlich einen Sprung auf FreeNAS 8 gewagt. Jedoch war ich von der Administrationsoberfläche und der Stabilität (zumindest auf meiner Hardware) nicht überzeugt.

Daher erfolgte am letzten Wochenende der Sprung zurück auf das ehemals FreeNAS 7 getaufte Projekt. Das Erkennen meines ZFS Pools machte keinerlei Schwierigkeiten. Mittels des Befehls zpool import 1 können spezifische Pools importiert werden. Vorteilhaft ist zuvor das Exportieren des Pools mit zpool export. Das hatte ich vergessen. Hat aber trotzdem funktioniert.

Das eigentliche Problem war im Anschluss das Bereitstellen und Teilen meiner ZFS Datasets über AFP zwischen verschiedenen Benutzern. Legt ein Benutzer A einen Ordner oder eine Datei an, der für das Teilen vorgesehen ist, kann ein zweiter Benutzer B nicht schreibend auf den Ordner zugreifen. Die voreingestellten Zugriffsrechte, die AFP nutzt, sehen dies nicht vor.

Die Dokumentation von netatalk beschreibt, wie man mit Hilfe der Parameter perm, dperm und fperm die Standardzugriffsrechte für neue Dateien und Ordner anpassen kann. Das geschieht in der Datei AppleVolumes.default, die unter NAS4Free unter /var/etc liegt. Leider bietet NAS4Free in der GUI keinerlei Einsellungsmöglichkeiten für die Zugriffsrechte. Ein manuelles Ändern der Zugriffsrechte in der Datei AppleVolumes.default ist möglich. Jedoch werden die Änderungen nach einem Neustart des AFP-Dienstes überschrieben.

Einen Workaround habe ich beim Probieren gefunden. In den Einstellungen eines AFP-Shares können am Ende des Eingabefeldes „Read/Write Access“ die benötigten Parameter angehangen werden. Diese werden in die AFP-Konfiguration übernommen. Wenn also Benutzer A, der einen Ordner oder eine Datei erstellt, und Benutzer B Zugriff auf den Ordner oder die Datei haben sollen, kann dies beispielsweise mit

Read/Write Access: userA,userB perm:0770

erreicht werden. Eine nicht besonders elegante Lösung. Sie funktioniert jedoch.

Homeserver: Einfach runterfahren

Wenn der Server läuft, bin ich zufrieden. Trotzdem möchte ich ihn ab und an wieder abschalten. Um den Server, auf dem FreeNAS läuft, herunterzufahren, kann man das Webinterface aufrufen und mit einigen Klicks den Server ausschalten. Dafür muss ich aber einen Browser offen haben, die URL zum Webinterface eingeben, meinen Benutzer und Passwort eintragen und dann erst komme ich über das Menü zum Herunterfahren. Nicht sehr bequem.

Ähnlich umständlich ist es sich über die Konsole mit SSH auf dem Server einzuloggen und per shutdown den Server schlafen zu legen. Das ist aber ein guter Ansatz. Ich habe mir ein Shellscript geschrieben, dass einen Rechner mit shutdown herunterfährt. Dazu logge ich mich über SSH mit einem auf dem Server authorisierten Benutzer ein (siehe vorheriger Beitrag) und rufe das Shutdown-Kommando auf. Im Folgenden ein Auschnitt aus dem Shellscript:

# SSH command string
SSH_CMD="shutdown -p now"

# Pruefe ob Host anpingbar, ansonsten breche ab
ping -c 2 $SSH_HOST > /dev/null
if [ $? -gt 0 ] ; then
	echo "Host with IP $SSH_HOST is not reachable."
	exit
else
	# ### SSH-Aufruf
	# Ruft auf entferntem Server ein Kommando auf
	ssh $SSH_USER@$SSH_HOST "$SSH_CMD"
fi

Das klappt ja wunderbar! Aber ich müsste trotzdem auf dem Mac jedes Mal das Terminal öffnen und das Script aufrufen. Ich nutze daher den Umweg über ein Applescript. In Mac OS X den Skripteditor öffnen und die folgende Zeile in ein neues Skript einfügen:

do shell script "~/Scripts/host-shutdown.sh user ip"

Ersetzt werden muss natürlich user und ip mit dem Benutzer und der IP-Adresse/URL, welche dem Shellscript übergeben werden sollen. Anschließend kann das Applescript als Programm abgespeichert werden und ist nun wie jede andere Anwendung per Doppelklick ausführbar.

Ich habe mir noch ein Icon erstellt für mein Applescript-Programm und habe es nun im Dock liegen. :)

Skript: host-shutdown.sh

Einloggen auf dem Server mit SSH ohne Passwort

Im letzten Artikel habe ich versprochen aufzuklären darüber, wie man sich auf einem Server mit SSH über das Netzwerk einloggt; ohne ein Passwort. In meinem Fall ist das besonders nötig, da ich auf dem Server ein Shellscript aufrufe. Das möchte ich natürlich nicht jedes Mal manuell machen und dabei ein Passwort eingeben müssen. Außerdem wir das noch nützlich sein, wenn ich den Server herunterfahren möchte.

Was muss also getan werden damit ich ohne ein Passwort einzugeben mich mit SSH einloggen kann? Zunächst benutzen wir das Kommandozeilenprogramm ssh-keygen auf der lokalen Maschine um ein Schlüsselpaar zu generieren:

ssh-keygen -t rsa

Dabei sollten die vorgegebenen Werte für aufkommende Fragen übernommen werden und kein Passwort eingegeben werden.

Von der lokalen Maschine aus erstellen wir nun auf dem Server mit dem Benutzer über SSH das Verzeichnis ~/.ssh, mit dem anschließend ohne Passwort das Einloggen auf dem Server möglich sein soll:

ssh user@server mkdir -p ~/.ssh

Der letzte Schritt ist den generierten Schlüssel der lokalen Maschine auf dem Server zu authorisieren. Dazu muss der lokale Schlüssel an die Datei ~/.ssh/authorized_keys auf dem Server angehängt werden. Also wird von der lokalen Maschine aus Folgendes ausgeführt:

cat ~/.ssh/id_rsa.pub | ssh user@server 'cat >> ~/.ssh/authorized_keys'

Jetzt ist das Einloggen von der lokalen Maschine aus auf dem Server ohne Passwort möglich.

Credits: http://linuxproblem.org/art_9.html

Homeserver: Backupstrategie #2

Im vorigen Beitrag habe ich meine Idee für ein Backup meiner Daten vorgestellt. Im Folgenden möchte ich die Shell-Skripte vorstellen, die die eigentliche Arbeit machen.

Insgesamt nutze ich vier Shell-Skripte:

  1. backup-rsync.sh
  2. backup-rotate-server.sh
  3. backup-rotate-client.sh
  4. backup-now.sh

Skript 1 wird mit der IP-Adresse meines Servers, dem über FreeNAS auf dem Server angelegtem RSync-Modul sowie dem Pfad auf meinem Macbook, der gesichert werden soll, aufgerufen. Die wichtigsten Zeilen in diesem Skript beziehen sich auf den Aufruf von RSync. Ich nutze RSync von den MacPorts. Diese Version ist neuer und soll mehr Features besitzen als die von Apple gelieferte.

$RSYNC -az --numeric-ids --delete --delete-excluded
      	     --exclude-from="$EXCLUDES" $EXTRAOPT	        
      	     $BACKUP_PATH $SERVER::$MODULE

RSync wird mit den obigen Zeilen mit den Optionen az (archive, compress) aufgerufen. Mit diesen Optionen wird RSync angewiesen möglichst alle Dateiattribute, wie Benutzer und Gruppe, sowie Links zu konservieren. Weiterhin soll der zu sichernde Ordner rekursiv verarbeitet und die Daten während der Übertragung komprimiert werden. Außerdem sollen irrelevante Dateien sowie auszuschließende Dateien (delete, delete-excluded) gelöscht werden. Mittels der Option exclude-from kann eine Datei angegeben werden, die eine Liste von Mustern auszuschließender Dateien und Ordnern enthält. So kann beispielsweise die allseits beliebte .DS_STORE Datei umgangen werden, die Mac OS X so gerne anlegt. Schließlich wird mit der Variable BACKUP_PATH das zu sichernde Verzeichnis und mit SERVER:MODULE der RSync-Server sowie das dort angelegte Modul übergeben.

Für meine Uni-Daten habe ich auf meinem Server mit ZFS ein File System angelegt. Das vereinfacht das sichern der Daten mit ZFS Bordmitteln (Stichwort: Snapshots). Skript 2 wird auf dem Server ausgeführt. Zunächst wird geprüft ob der höchste Snapshot existiert. Dazu nutze ich den Befehl zfs list -t snapshot. Falls er vorhanden ist, wird er gelöscht, denn ich möchte nur eine gewisse Anzahl von Backups halten. Das Löschen wird mit dem Befehl zfs destroy eingeleitet.

SNAP_REG="#$FILE_SYSTEM@weekly.3#!d"
CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

if [ "$CHECK_SNAP" ] ; then
  zfs destroy $FILE_SYSTEM@weekly.3
fi

Anschließend werden alle anderen Snapshots um eine Nummer „nach oben geschoben“. Dazu werden sie mit dem Befehl zfs rename umbenannt.

for OLD in 2 1 0 ; do
  SNAP_REG="#$FILE_SYSTEM@weekly.$OLD#!d"
  CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

  if [ "$CHECK_SNAP" ] ; then
    NEW=$[ $OLD + 1 ]
    zfs rename $FILE_SYSTEM@weekly.$OLD @weekly.$NEW
  fi
done

Schließlich wird ein aktueller Snapshot angelegt:

SNAP_REG="#$FILE_SYSTEM@weekly.0#!d"
CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

if [ -z "$CHECK_SNAP" ] ; then
  zfs snapshot $FILE_SYSTEM@weekly.0
fi

Skript 3 dient dazu Skript 2 auf dem Server über SSH aufzurufen. Dazu werden dem Skript der Benutzer zum Einloggen sowie die IP-Adresse des Servers und das zu sichernde ZFS File System übergeben. Der Rest funktioniert wie auf der Konsole:

SSH_CMD="~/script/backup/backup-rotate-server.sh $ZFS_FILE_SYSTEM"

ssh $SSH_USER@$SSH_HOST "$SSH_CMD"

Den Kennern ist sicherlich aufgefallen, dass ich kein Passwort benötige um den Befehl auf dem Server auszuführen. Darauf gehe ich in einem weiteren Artikel ein.

Skript 4 schließlich ist der Einstiegspunkt für das Backup. In diesem Skript wird zunächst mit dem Befehl ping geprüft ob der Server erreichbar ist. Falls nicht wird sofort abgebrochen. Ansonsten werden nacheinander Skript 3 und Skript 1 aufgerufen.

Sicherlich gibt es an einigen Stellen (wie immer) Verbesserungsbedarf. Trotzdem bin ich mit der jetzigen Lösung zufrieden, lasse mich aber gerne belehren. :)
Für diejenigen, die Interesse haben, sind im Anschluss die Skripte verlinkt.

Homeserver: Backupstrategie #1

In den folgenden Artikeln möchte ich auf die Backuplösung eingehen, die ich mit Hilfe meines Servers umgesetzt habe. Für das Systembackup meines Macbooks nutze ich Timemachine. Mit der aktuellen FreeNAS Version lässt sich ein AFP-Share für Timemachine verfügbar machen. Das klappt bis jetzt wunderbar. Jedoch möchte ich mich gerade bei wirklich wichtigen Daten, wie meinen Daten fürs Studium, nicht auf eine nicht von Apple abgesegnete Lösung verlassen.

Deshalb wollte ich RSync nutzen. FreeNAS bieten einen RSync-Server an, mit dem ein definierbarer Bereich auf der Platte als sogenanntes Module freigegeben werden kann. So muss beim Aufruf von RSync nicht mit Verzeichnissen hantiert werden. Die Angabe des Modules reicht, die Daten landen im richtigen Verzeichnis.

Ein weiterer wichtiger Punkt war die Haltung von mehreren Versionen meiner Daten. Ich wollte jede Woche ein Backup meiner Daten anlegen, einen Monat lang. Danach sollten die vorhandenen Backups rotieren: das Älteste kommt weg, die anderen werden weiter nach hinten geschoben. Natürlich sollte nicht nur einfach kopiert werden, sondern mittels Hardlinks auf Daten verwiesen werden um Plattenplatz zu sparen. Für diesen Einsatz gibt es rsnapshot. Leider kann mit rsnapshot nicht auf einen entfernten (wenn bei mir auch zwei Meter hinter mir stehenden) Server gebackupped werden. Also fiel die Möglichkeit schonmal aus.

Das Rotieren musste nun also „von Hand“ geschehen. Dabei habe ich mich etwas inspirieren lassen. Diese Shell-Skripte backuppen entfernte Server auf einen lokalen Rechner. Dabei werden die Backups rotiert und eine gewisse Anzahl Backups vorgehalten. Also fast, was ich gesucht habe. Die Skripte habe ich großzügig an meine Bedürfnisse angepasst.

Timemachine macht Backups automatisch, wenn das Backup-Volume verfügbar ist. So ungefähr sollte das auch beim Backup meiner Uni-Daten passieren. Unter Linux würde man wohl einen Cronjob anlegen, unter Mac OS X gibt es launchd. Dieser Daemon wird beim Systemstart als zweiter Prozess gestartet (siehe Aktivitätsanzeige) und soll verschiedene bekannte Starter (init, crond, etc.) ablösen und deren Aufgaben vereinheitlichen. Als weiteres Schmankerl wird launchd mit XML-Dateien konfiguriert. Wem das zu unübersichtlich ist, kann sich mit Lingon behelfen. Einen kleinen Einstiegsartikel zu Lingon findet man auf Apfeltalk.

Meine erste Idee war, einen AFP-Share zu nutzen und für jede Version meiner Daten einen Ordner (wie weekly.0, weekly.1 etc.) anzulegen. Beim Rotieren dieser Versionen wollte ich mit cp und Hardlinks arbeiten. Leider funktionierte das auch mit der GNU-Version von cp (über Macports bezogen) nicht. Woran genau es lag, kann ich nicht sagen. Vielleicht war AFP Schuld, vielleicht auch ZFS. Aber Moment… ZFS! Mit ZFS kann man von einem File System ohne großen Aufwand einen Snapshot (also quasi ein zeitliches Abbild eines File Systems) anlegen. Das wollte ich letztendlich tun.

Die Umsetzung dieser Idee und die Probleme, auf die ich gestoßen bin, kommen im nächsten Artikel. Bis dahin schöne Feiertage und so. ;)