OSBN

Martins Schmierzettel

Code-Schnippsel: Backup über SSH mit rsync (2)



Seit meinem letzten Beitrag über mein Backup-Script ist schon wieder eine Weile vergangen und ich möchte hier mal wieder den aktuellen Stand pro­to­kol­lie­ren.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#! /bin/bash


#### Diese Variablen bitte auf die eigenen Bedürfnisse anpassen
BACKUP_PFADE="/home/martin /etc /root /usr/local"
                        # Pfade die gesichert werden sollen
ZIELPFAD=/mnt/backup    # Pfad auf dem Backupserver (ohne abschließenden /)
ZIEL_EXT=true       # true = Wechseldatenträger, false = interner Speicher
ANZAHL_TAGE=7           # Tägliches Backup für x Tage
BENUTZER=martin         # Benutzername auf dem Backupserver
SERVER=backup           # IP-Adresse oder Hostname des Backupservers
PORT=1418               # SSH-Port des Backupservers
MAC=88:ae:1d:31:cd:17   # MAC-Adresse des Servers für WOL
EXCLUDES="--exclude .cache/ \
--exclude cache/ --exclude Cache/"  # TODO: Elegantere Lösung finden 
HISTORY=/root/.backup_hist      # Protokoll-Datei
LISTE=/root/installed_packages.txt  # Speicherort für Liste der installierten Pakete


#### Don't touch this; domdididom
#### Ab hier bitte nichts anfassen, wenn du nicht sicher weißt was du tust
MONAT=$(date +%-m)
VORMONAT=$(expr $MONAT - 1)
HOST=$(hostname)

# Backup-Server bereit?
if  ! ping -c 1 $SERVER > /dev/null 
    then

    # Backup-Server hochfahren
    wakeonlan $MAC 1>/dev/null

    sleep 60

    if ! ping -c 1 $SERVER > /dev/null 
        then
        echo "Backup konnte nicht durchgeführt werden. Der Server war nicht erreichbar." \
        | mail -s 'Backup fehlgeschlagen!' $(whoami)@$HOST
        exit
    fi
fi

# Falls Zieldatenträger Wechselplatte, diese einhängen
if $ZIEL_EXT
    then
    ssh -p $PORT $BENUTZER\@$SERVER "sudo mount $ZIELPFAD" >/dev/null

    # Datei CURRENT zur Protokollierung der aktiven Backups existiert?
    if ! ssh -p $PORT $BENUTZER\@$SERVER stat $ZIELPFAD/CURRENT \> /dev/null 2\>\&1
            then
            ssh -p $PORT $BENUTZER\@$SERVER "touch $ZIELPFAD/CURRENT && echo "0" > $ZIELPFAD/CURRENT"
    fi

    # CURRENT auslesen und inkrementieren
    CURRENT=$(ssh -p $PORT $BENUTZER\@$SERVER "cat $ZIELPFAD/CURRENT")
    CURRENT=$(echo "$CURRENT + 1" | bc)
    ssh -p $PORT $BENUTZER\@$SERVER "echo $CURRENT > $ZIELPFAD/CURRENT"

fi

# Link 0 -> 12 (für Link auf letztes Backup im Januar) existiert?
if ! ssh -p $PORT $BENUTZER\@$SERVER stat $ZIELPFAD/$HOST/0 \> /dev/null 2\>\&1
    then
    ssh -p $PORT $BENUTZER\@$SERVER "ln -s $ZIELPFAD/$HOST/12 $ZIELPFAD/$HOST/0"
fi

# Bei Problemen zu Testzwecken auskommentieren
# ssh -v -p $PORT $BENUTZER@$SERVER /bin/true

# Eine Liste der installierten Pakete erstellen
dpkg --get-selections > $LISTE

# Backup per rsync
for PFAD in $BACKUP_PFADE
do
    rsync -az --delete-excluded $EXCLUDES --rsync-path='sudo rsync' --rsh="ssh -p $PORT" \
    --link-dest=../$VORMONAT $PFAD $BENUTZER@$SERVER:$ZIELPFAD/$HOST/$MONAT
done

# Erstellen von Snapshots der letzten x Tage
ssh -p $PORT $BENUTZER\@$SERVER "sudo rm -rf $ZIELPFAD/$HOST/daily.$ANZAHL_TAGE"

if [ $ANZAHL_TAGE -gt 1 ]
    then

    for (( ANZAHL=$ANZAHL_TAGE ; ANZAHL >= 2 ; ANZAHL-- ))
    do
        ssh -p $PORT $BENUTZER\@$SERVER \
        "sudo mv $ZIELPFAD/$HOST/daily.$(expr $ANZAHL - 1) $ZIELPFAD/$HOST/daily.$ANZAHL"
    done
fi

if [ ! $ANZAHL_TAGE -eq 0 ]
    then
    ssh -p $PORT $BENUTZER\@$SERVER "sudo mv $ZIELPFAD/$HOST/daily.latest $ZIELPFAD/$HOST/daily.1"
    ssh -p $PORT $BENUTZER\@$SERVER "sudo cp -al $ZIELPFAD/$HOST/$MONAT $ZIELPFAD/$HOST/daily.latest"
fi

# Falls Zieldatenträger Wechselplatte, diese aushängen sofern kein weiteres Backup aktiv ist (Variable Current)
if $ZIEL_EXT
        then
    CURRENT=$(ssh -p $PORT $BENUTZER\@$SERVER "cat $ZIELPFAD/CURRENT")
    if [ $CURRENT -eq 1 ]
        then
        ssh -p $PORT $BENUTZER\@$SERVER "echo "0" > $ZIELPFAD/CURRENT"
            ssh -p $PORT $BENUTZER\@$SERVER "sudo umount $ZIELPFAD" >/dev/null
        else
        CURRENT=$(echo "$CURRENT - 1" | bc)
                ssh -p $PORT $BENUTZER\@$SERVER "echo "$CURRENT" > $ZIELPFAD/CURRENT"
    fi 
fi

# Datum und Uhrzeit des Backups protokollieren
date >> $HISTORY

Das Script sorgt dafür, dass mein home /home/martin, sowie /etc und /usr/local/bin gesichert werden.

Ich habe auch eine Rotation eingebaut, die mir erlaubt auf einen Snapshot der letzten 7 Si­che­run­gen zu­zu­grei­fen und es werden Snapshots der letzten 11 Monate aufbewahrt.

Durch Nutzung von Hardlinks reduziere ich den Spei­cher­platz­ver­bauch auf ein Minimum.

Das Script ist darauf ausgelegt den Backup-Server per WOL auf­zu­we­cken, eine externe Festplatte zu mounten und das Backup durch­zu­füh­ren. Das mag ein recht spe­zi­fi­sches Setup sein, aber vielleicht kann es ja mal jemand brauchen oder zumindest Teile davon für eigene Scripte recyclen.

Dieses Script wird einmal täglich von anachron aufgerufen und sorgt dafür, dass ich mich nicht mehr bewusst um Backups kümmern muss.

Angefangen hat das Script als einfaches rsync-Kommando das mein Home-Ver­zeich­nis /home/martin per SSH auf eine USB-Festplatte auf meinem Server kopiert hat. Mit der Zeit habe ich aber immer mehr Ver­bes­se­run­gen vor­ge­nom­men und es ist eine recht gute Backup-Lösung geworden.

In den Kommentaren können folgende Formatierungen genutzt werden.

Kurztipp: Eine bestimmte Stelle eines Youtube-Videos verlinken » « Erste Schritte mit YaCy