Selbstbau-NAS mit FreeBSD

Wie in Ausgabe 2 von skrupuloes zu hören war, hatte ich Probleme mit dem Speicherplatz auf meinem NAS. Die Synology Diskstation 211J hat nur Platz für zwei Platten, die ich aus Redundanzgründen gespiegelt habe. Ich hatte also effektiv 2 TB Platz. Da die Diskstation auch meine Boxee-Box, Raspberry Pi mit XBMC und diverse iDevices mit Mediendateien versorgt hat, war der Platz relativ schnell voll, wenn man die Time Machine-Backups für zwei MacBooks dazu rechnet. Es musste also etwas neues her.

Die fertigen Lösungen, die es auf dem Markt gibt waren mir alle zu unflexibel und mit Platz für mind. vier Festplatten auch relativ schnell relativ teuer. Ich entschied mich also, etwas selbst zu bauen.

Nach ein wenig Recherche entschied ich mich für folgende Komponenten:

  • Mainboard: ASUS C60M1-I
  • Gehäuse: Fractal Design Array R2
  • RAM: Corsair XMS3 PC-133 8GB (CL9)
  • Festplatten: Western Digital WD20EZRX Green 2TB
  • 320 GB Hitachi 2,5″ HDD aus MacBook Pro

Das Mainboard ist passivgekühlt, kommt mit einem AMD Fusion Dualcore mit 1GHz, Gigabit-LAN und 6 SATA-Ports. Dazu habe ich 8 GB RAM verbaut (man weiß ja nie…). Gespeichert wird auf vier 2 TB-Platten und einer 320 GB-Platte, die ich noch aus meinem MacBook rumliegen hatte. Das Gehäuse ist extra für den Einsatz als NAS entwickelt worden. Es kommt komplett mit einem großen Gehäuse-Lüfter, 300 W-Netzteil und bietet sowohl einen herausnehmbaren Festplattenkäfig für bis zu sechs Platten und die Möglichkeit, zusätzlich eine 2,5″-Platte zu verbauen.

Da ich aus Gründen der Datensicherheit gerne ZFS nutzen wollte, bin ich nun gezwungen, nicht mehr Linux zu benutzen. Da mir fertige NAS-Distributionen zu unflexibel sind, entschied ich mich, mal etwas neues zu wagen und jetzt läuft hier ein schickes FreeBSD.

Als Linux-Umsteiger war FreeBSD kurzzeitig ungewohnt, aber mittlerweile bin ich recht gut drin und lerne die diversen Vorzüge bezüglich Software-Verwaltung mit Ports, Konfigurationsdatein etc. zu schätzen.

Die vier großen Platten laufen als RAIDZ1 (vergleichbar mit RAID5) und bieten mir somit knapp 6 TB Speicherplatz und eine mögliche Wiederherstellung, falls eine Platte ausfällt. Wenn der Speicherplatz knapp wird, kann ich noch zwei weitere Platten verbauen und das RAID einfach erweitern. Die 2,5″-Platte nutze ich als Systemplatte und habe hierauf das BSD installiert.

Alles in allem habe ich jetzt für vergleichsweise wenig Geld ein kleines, Leistungsstarkes, stromsparendes und flexibel einsetzbares System, das auch noch Spaß beim Herumexperimentieren mit einem echten UNIX gibt 😉

Time Machine Backups verschlüsselt über das Internet erstellen

An Tagen wie diesen (z.B. Weihnachten) stellt sich immer wieder ein Problem. Das NAS steht zu Hause, man selbst ist zum Beispiel bei seinen Eltern und das über Tage hinweg. Der paranoide Nerd hat dann immer wieder das gleiche Problem: Was ist mit den Backups. Was soll ich nur machen, wenn die Festplatte des MacBooks nach zwei Tagen abraucht?

Genau diesem (meinem) Problem habe ich mich über Weihnachten mal angenommen. Zu Hause steht meine Synology Disk Station. Sie ist im Netzwerk u.A. per AFP (Apple Filing Protocol) als Time Machine-Volume ansprechbar. SSH läuft, die Authentifizierung läuft schon seit Längerem über Keys und der SSH-Port ist über den Router freigegeben, welcher wiederum per DDNS erreichbar ist.

Ich habe also ein Script gebastelt, welches all diese Faktoren kombiniert und es mir ermöglicht, auf meine Disk Station per AFP zuzugreifen und Backups zu machen.

Das Script stellt eine Verbindung zum SSH-Server im NAS her, und Tunnelt den dortigen AFP-Port per SSH auf einen Port meines Rechners. Über diesen Port kann ich dann über eine verschlüsselte Verbindung auf mein NAS zugreifen. Der Tunnel bzw. der durch den Tunnel angebotene Service wird dem Betriebssystem per dns-sd bekannt gemacht, was dazu führt, dass es ihn „entdeckt“ und im Finder aufführt, als wäre ich im heimischen Netzwerk.

Wird das Script noch mal aufgerufen, prüft es, ob schon ein Tunnel besteht. Wenn dies nicht der Fall ist, versucht es einen zu erstellen. Dadurch bietet es sich an, das Script per cron regelmäßig ausführen zu lassen um den Tunnel dauerhaft aufrecht zu erhalten.

Alles in allem ist das bisher eine sehr coole Sache 🙂 Gigabyteweise Time Machine Backups mit 128kb Upstream machen jedoch keinen Spaß.

Ich habe das Projekt wie immer auf github gehostet und Pflege es auch dort. Über Anregungen und Commits würde ich mich freuen.

Anbei zusätzlich auch noch mal das aktuelle Listing des Codes.

#!/bin/sh

## CONFIG

REMOTEUSER="user" # The ssh user name on remote server
REMOTEHOST="remote.host.name" # The ssh user password on remote server
LABEL="DiskStation" # The label for the service, that's registered with dns-sd

## NO NEED TO EDIT BELOW THIS LINE

VERSION="2011-12-27"

VERBOSE=false

REMOTELOGIN="$REMOTEUSER@$REMOTEHOST"

createTunnel() {
    # Create tunnel to port 548 on remote host and make it avaliable at port 12345 at localhost
    # Also tunnel ssh for connection testing purposes
    ssh -gNf 
    -L 12345:127.0.0.1:548 
    -L 19922:127.0.0.1:22 
    -C $REMOTELOGIN &

    if [[ $? -eq 0 ]]; then
        # Register AFP as service via dns-sd
        dns-sd -R $LABEL _afpovertcp._tcp . 12345 > /dev/null &

        if [ $VERBOSE = "true" ]; then echo Tunnel to $REMOTEHOST created successfully; fi
        exit 0
    else
        if [ $VERBOSE = "true" ]; then echo An error occurred creating a tunnel to $REMOTEHOST RC was $?; fi
        exit 1
    fi
}

killTunnel() {
    MYPID=`ps aux | egrep -w "$REMOTEHOST|dns-sd -R $LABEL" | grep -v egrep | awk '{print $2}'`
    for i in $MYPID; do kill $i; done
    echo All processes killed
}

help() {
    echo "ssh-ds  version $VERSION

ssh-ds is a small shell script that tunnels the AFP port of your disk station
(and propably every other NAS with AFP and SSH services running) over ssh to your client computer.

Put your settings in the config section in the script itself!

Options
 -v, --verbose               increase verbosity
 -k, --kill                  kill all ssh-ds processes
 -h, --help                  show this screen
"
exit 0
}

# Yippieeh, commandline parameters

while [ $# -gt 0 ]; do    # Until you run out of parameters . . .
    case "$1" in
        -k|--kill)
            killTunnel
            exit 0
        ;;
        -v|--verbose)
            VERBOSE=true
        ;;
        -h|--help)
            help
        ;;
        *)

        ;;
    esac
    shift       # Check next set of parameters.
done

## Run the 'ls' command remotely.  If it returns non-zero, create a new connection
ssh -q -p 19922 $REMOTEUSER@localhost ls > /dev/null
if [[ $? -ne 0 ]]; then
    createTunnel
else
    if [ $VERBOSE = "true" ]; then echo Tunnel to $REMOTEHOST is active; fi
fi

Aus Backup-Script mit rsync und growl wird fabula-backup

In meinem Artikel „Mac: Inkrementelle Backups mit rsync und growl“ habe ich letztens mein Backup-Script für den Mac veröffentlicht, welches mit rsync und growl bei mir Time Machine ersetzt und wesentlich mehr Möglichkeiten bietet.

Da ich jetzt noch ein Bisschen daran rumgeschraubt habe und auch für die Zukunft noch ein paar Dinge geplant sind, habe ich mich entschlossen, das Teil zu GitHub zu schieben.

Hier gibt’s jetzt immer die aktuellste Version mit der Möglichkeit des Downloads und der Mitarbeit. Wenn es großartige Änderungen gibt, werde ich über neue Versionen auch hier berichten.

Aktuell sind wir bei Version 0.7.1 und es hat sich Folgendes getan:

  • Anstatt alles in einer log-Datei pro Ausführung zu dokumentieren, nutzt das Script jetzt den Syslog und schreibt ein Error-log nur, wenn Fehler aufgetreten sind. Es ist jetzt also näher an den Standardmethoden von OS X dran und müllt die Festplatte nicht mit Logfiles zu 😉
  • Die growl-Notifications sind jetzt nur sticky, wenn Fehler aufgetreten sind. Ansonsten verschwinden alle Benachrichtigungen, nach der von Euch eingestellten Zeit.

Für die Zukunft geplant ist noch eine stärkere Linux-Kompatibilität und evt. eine Setup-Prozedur o. Ä.

Mac: Inkrementelle Backups mit rsync und growl

Ich bin seit ca. einem halben Jahr Mac-User und wirklich zufrieden mit OS X. Das Einzige, was mich stört, ist Time Machine.

Ich habe meinen Home-Folder verschlüsselt in einem FileVault und meine restlichen Daten auf einer separaten, mit Truecrypt verschlüsselten, Partition liegen. Time Machine ist relativ beschränkt, wenn es darum geht, die Backups anzupassen. Um mein Verschlüsseltes Home-Verzeichnis zu sichern, muss ich mich ausloggen, MacOS komprimiert den FileVault und schmeißt ihn dann auf das Backup-Medium. Die Sicherung des Truecrypt-Volumes ist gar nicht möglich.

Da dies für eine Backup-Strategie, welche automatisch im Hintergrund läuft, denkbar unpraktisch ist, musste eine andere Lösung her.

Ich habe also ein Bisschen gegoogelt und mir aus verschiedenen Backup-Scripts Anregungen geholt. Heraus kam ein Backup-Script, welches die Backups ähnlich anlegt, wie Time Machine.

Ich konfiguriere die Quell-Ordner, gebe das Ziel-Medium an und der Rest geschieht im Hintergrund. Da rsync in meiner Configuration nur neue und geänderte Dateien übertragen muss und nicht veränderte Dateien einfach verlinkt werden, geht das Backup relativ schnell und verbraucht sehr wenig Platz. Bei jedem Durchlauf wird ein neuer Ordner angelegt, welcher immer ein Vollbackup enthält. Wenn sich keine Dateien verändert haben, wird aber kein zusätzlicher Platz verbraucht.

Am Ende jedes Durchlaufs werde ich per growl benachrichtigt, dass das Backup gemacht wurde und ob es Fehler gab.

Alles in allem funktioniert jetzt alles so, wie ich es will. Das Script läuft stündlich per cron im Hintergrund und ich brauche mich um nichts zu kümmern. Trotzdem habe ich Gewissheit, dass alle meine Daten gesichert sind, falls etwas passiert.

Folgenden Code einfach in eine Textdatei packen, mit root-Rechten ausführen und glücklich sein 🙂

P.S.: Der Code funktioniert auf jedem System, af dem rsync läuft (Linux, Unix, Windows mit Cygwin). Hier muss dann aber unter Umständen auf die Benachrichtigungen verzichtet werden, wenn Ihr das Script nicht an des Benachrichtigungssystem Eures Betriebssystem anpassen wollt (z.B. notify-bin in Ubuntu).


#!/bin/bash

# --- Set backup parameters ---
 
# What local files/folders are we backing up (without trailin "/")?

SOURCES='/bin /private/etc /sbin /etc /usr /opt /Volumes/Macintosh/Library /Volumes/Macintosh/System /Volumes/Macintosh/Users/chris /Volumes/Macintosh/Applications /Volumes/Daten'

# What location shall we back up to (without trailin "/")?
DEST='/Volumes/Elements'

# Any non-valuable stuff to exclude by name/location (seperated by ",")?
EXCLUDE='.DS_Store,/.chris/,.Trash/,tmp/,LastPass/pipes/,log/,.log'


# --- Get some data and make some declarations ---

# What's the local hostname?
HOST=`hostname -fs`

# Get the date
DATE=`date "+%Y-%m-%d-%H%M%S"`

# Set the folder for backups for this host
BACKUPPATH="$DEST/Backup/$HOST"

# Where shall we write the error log?
ERRORS="$BACKUPPATH/errors-$DATE.log"

# --- Set Growl parameters ---
 
# What will this script be called in the Growl prefpane?
GROWLNAME="Backup of $HOST"
 
# And what app's icon will appear in Growl notifications?
APPICON="/Users/chris/bin/Time-Machine.icns"

# --- Do it! ---

# Check if $DEST is mounted. Otherwise quit script
DESTMOUNTED=`mount | grep "$DEST"`
 
if [ -z "$DESTMOUNTED" ]; then
  /bin/growlnotify --name "$GROWLNAME" --image "$APPICON" 
    --message "$DEST is not mounted." "Ignoring scheduled backup"
  exit 1
fi 


 
PROCS=`ps -A -o "pid=,command="`
MYNAME="$0"
MYBASENAME=`basename $MYNAME`
MYPID=$$
 
# The next line works like so:
# * take the process list (for all users),
# * filter *in* processes named like this script (making sure we're on word boundaries),
# * filter *out* (-v) the one that *is* this script (by PID), and finally
# * filter *out* the grep commands themselves.
 
MERUNNING=`echo "$PROCS" | grep -E -e "b$MYBASENAMEb" 
  | grep -E -v "b$MYPIDb" | grep -v grep`
 
# Then, if anything's left (i.e. MERUNNING isn't a zero-length string...)
 
if [ ! -z "$MERUNNING" ]; then
  /bin/growlnotify --name "$GROWLNAME" --image "$APPICON" 
    --message "Another backup seems to be in progress" "Ignoring scheduled backup"
  exit 1
fi 

EXPEXCLUDES=`eval "echo --exclude={$EXCLUDE} "`

STARTTIME=`date "+%Y-%m-%d %H:%M:%S"`

/bin/growlnotify --name "$GROWLNAME" --image "$APPICON" --message "Backup of $HOST has been startet at $STARTTIME"
echo "Backup of $HOST has been startet at $STARTTIME" >> $ERRORS

for D in $SOURCES; do
    mkdir -p $BACKUPPATH/$DATE.inProgress$D
    rsync -aH $EXPEXCLUDES --link-dest=$BACKUPPATH/current$D $D/ $BACKUPPATH/$DATE.inProgress$D 2>>"$ERRORS"
done

FINISHTIME=`date "+%Y-%m-%d %H:%M:%S"`

NUMERRORS=`awk '{x++}END{ print x}' $ERRORS`
NUMERRORS=$[$NUMERRORS-1]

/bin/growlnotify --name "$GROWLNAME" --image "$APPICON" -s 
  --message "Completed backup of $HOST at $FINISHTIME. There were $NUMERRORS errors." "$HOST has been backed up to $DEST."
echo "Completed backup of $HOST at $FINISHTIME. There were $NUMERRORS errors." >> $ERRORS

mv $BACKUPPATH/$DATE.inProgress $BACKUPPATH/$DATE

rm -f "$BACKUPPATH/current" && ln -nsf "$BACKUPPATH/$DATE/" "$BACKUPPATH/current"