staging.inyokaproject.org

Script für verteilte, verschlüsselte Backups mit Versionierung

Status: Ungelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

matze69

Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Hallo zusammen,

ich habe ein kleines Bash-Script geschrieben, das täglich, wöchentlich und monatlich ein verschlüsseltes Backup an mehreren Orten ablegt und alte Backupdateien entfernt. Es sollte täglich per crontab ausgeführt werden. Außerdem muss rsync vorhanden sein, damit es wie vorgesehen funktioniert.

Ich stelle das Script hier zur Verfügung, vielleicht ist es ja jemandem nützlich.

Außerdem freue ich mich über Tipps und Hinweise zur Verbesserung des Codes.

Viele Grüße

matze

Moderiert von redknight:

Verschoben.

backup.sh (2.7 KiB)
Download backup.sh

ChickenLipsRfun2eat Team-Icon

Supporter
Avatar von ChickenLipsRfun2eat

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12070

Hallo und danke fürs Teilen! Ich vermute aber, dass du mehr Hinweise über den Code bekommst, wenn er hier im Codeblock steht und kein Download nötig ist.

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Gute Idee! Also hier der Code:

#!/bin/bash

							###########################################
							###					###
							###	(c) 2016 by Matthias Ewering	###
							###					###
							###	 matthias.ewering@posteo.de	###
							###					###
							###	!! No warranty whatsoever !!	###
							###					###
							###########################################

source=/path/to/source														#The element to be backed up
daily=/path/to/backup/daily													#The directory that will contain the daily backup files
weekly=/path/to/backup/weekly													#The directory that will contain the weekly backup files
monthly=/path/to/backup/monthly													#The directory that will contain the monthly backup files
main=/path/to/backup														#The main backup directory for all backup cycles
mirror1=/path/to/backup_mirror1													#The first mirror of the main backup directory
mirror2=/path/to/backup_mirror2													#The second mirror of the main backup directory
#mirrorn=/foo/bar														#The n^th mirror of the main backup directory

tar -czPf ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz $source									#Create a compressed tarball with the contents to be backed up

gpg --symmetric --cipher-algo aes256 --passphrase secret -o ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz.gpg ./*_backup.*		#Encrypt the tarball. Remember to replace "secret" with A CUSTOM, SECURE PASSPHRASE!

mv ./*.gpg $daily														#Move the encrypted backup file to the main daily backup directory

rm ./*_backup.*															#Delete the unencrypted tarball

find $daily -type f | sort -rd | sed -e '1,7d' | xargs -d '\n' rm --								#Delete any file from the main daily backup directory with the 8th oldest timestamp or older

if [ $(date +"%u") = "7" ]													#
																#
	then 	find $daily -type f | sort -d | sed -e'1,6d' | xargs cp -t $weekly						#
																#On a Sunday, copy the latest daily backup file to the weekly backup directory,... 
		find $weekly -type f | sort -rd | sed -e '1,5d' | xargs -d '\n' rm --						#...then delete any file from the weekly backup directory with the 6th oldest...
																#...timestamp or older
fi																#

if [ $(date +"%d") = "01" ]													#
																#On the first of a month, copy the latest daily backup file to the monthly backup directory
	then 	find $daily -type f | sort -d | sed -e'1,6d' | xargs cp -t $monthly						#
																#
fi																#

rsync -a --delete $main $mirror1												#Synchronize the first mirror directory with the main backup directory

rsync -a --delete $main $mirror2												#Synchronize the second mirror directory with the main backup directory

#rsync -a --delete $main $mirrorn												#Synchronize the n^th mirror directory with the main backup directory

exit 0

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Kann mir jemand verraten, warum der Thread gemeldet wurde...?

senden9

Avatar von senden9

Anmeldungsdatum:
8. Februar 2010

Beiträge: 965

Nur Zum Stil: Ich mag es persönlich lieber wenn die Dokumentation und die Optionen für den Endanwender (Zeile 13-20) in einer separaten readme.md oder in einem Kommentarblock am Anfang der Datei stehen. Im jetzigen Format sieht das ganze in einem Terminal in einem kleinen Fenster etwas zerrissen aus (wegen den vielen Leerzeichen).

ChickenLipsRfun2eat Team-Icon

Supporter
Avatar von ChickenLipsRfun2eat

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12070

matze69 schrieb:

Kann mir jemand verraten, warum der Thread gemeldet wurde...?

Weil es besser in "Projekte" passt, da es dein Projekt ist und keine Supportanfrage enthält. Zumal es da nicht so schnell "untergeht". Das dient dem Aufräumen und dem Einsortieren in die richtige Kategorie. "Melden" ist nicht automatisch "böse" ☺ Für mehr Details siehe Richtig fragen und die jeweiligen Forenstickies mit dem Titel "Welche Themen gehören hier her und welche nicht?"

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Danke senden9! Für (meinen) Hausgebrauch habe ich lieber alles in einer Datei. Wer gern Teile auslagern möchte, kann das Script natürlich gern nach seinem Gusto ändern 😉

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Danke auch Dir, Chicken. Das Thema kann gern verschoben werden!

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Noch ein Kommentar zum Handwerklichen:

Du erlaubst ja in den Zeilen 13 ... 20 beliebige Pfade, also auch mit Leer- und Sonderzeichen drin.

Konsequenterweise musst Du dann auch den Aufruf aller dieser Variablen im Skript später immer "quoten", damit nicht im Falle besagter Leer- oder Sonderzeichen ein Unglück geschieht. - Das solltest Du also auf jeden Fall noch nachtragen.

LG,

track

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Ein guter Hinweis, danke sehr! Ich habe die quotes eingefügt.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

... nur leider nicht in den hier veröffentlichen Versionen ! - die sind beide noch unkorrigiert.

Bitte schreib die korrigierte Version auch hier irgendwo hin, damit die Leute die korrigierte Variante benutzen können.
Oder möchtest Du, dass jeder für sich das nochmal korrigiert ? 😉

LG,

track

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Keineswegs 😉

Hier die aktuelle Fassung:

#!/bin/bash

###########################################
###					###
###	(c) 2016 by Matthias Ewering	###
###					###
###	 matthias.ewering@posteo.de	###
###					###
###	!! No warranty whatsoever !!	###
###					###
###########################################

source=/path/to/source	#The element to be backed up
daily=/path/to/backup/daily	#The directory that will contain the daily backup files
weekly=/path/to/backup/weekly	#The directory that will contain the weekly backup files
monthly=/path/to/backup/monthly	#The directory that will contain the monthly backup files
main=/path/to/backup	#The main backup directory for all backup cycles
mirror1=/path/to/backup_mirror1	#The first mirror of the main backup directory
mirror2=/path/to/backup_mirror2	#The second mirror of the main backup directory
#mirrorn=/foo/bar	#The n^th mirror of the main backup directory

tar -czPf ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz "$source"	#Create a compressed tarball with the contents to be backed up

gpg --symmetric --cipher-algo aes256 --passphrase secret -o ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz.gpg ./*_backup.*	#Encrypt the tarball. Remember to replace "secret" with A CUSTOM, SECURE PASSPHRASE!

mv ./*.gpg "$daily"	#Move the encrypted backup file to the main daily backup directory

rm ./*_backup.*	#Delete the unencrypted tarball

find "$daily" -type f | sort -rd | sed -e '1,7d' | xargs -d '\n' rm --	#Delete any file from the main daily backup directory with the 8th oldest timestamp or older

if [ $(date +"%u") = "7" ]

	then 	find "$daily" -type f | sort -d | sed -e'1,6d' | xargs cp -t "$weekly"
											#On a Sunday, copy the latest daily backup file to the weekly backup directory,... 
		find "$weekly" -type f | sort -rd | sed -e '1,5d' | xargs -d '\n' rm --	#...then delete any file from the weekly backup directory with the 6th oldest...
											#...timestamp or older
fi

if [ $(date +"%d") = "01" ]
											#On the first of a month, copy the latest daily backup file to the monthly backup directory
	then 	find "$daily" -type f | sort -d | sed -e'1,6d' | xargs cp -t "$monthly"

fi

rsync -a --delete "$main" "$mirror1"	#Synchronize the first mirror directory with the main backup directory

rsync -a --delete "$main" "$mirror2"	#Synchronize the second mirror directory with the main backup directory

#rsync -a --delete "$main" "$mirrorn"	#Synchronize the n^th mirror directory with the main backup directory

exit 0
backup.sh (2.4 KiB)
Download backup.sh

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Ich habe das Script um eine Funktion erweitert, die nach Ablauf eines Jahres die monatlichen Sicherungen in einen Archivordner verschiebt. Meine Lösung dazu scheint mir leider etwas umständlich, kennt jemand eine elegantere Methode?

Hier der aktuelle Code:

#!/bin/bash

###########################################
###					###
###	(c) 2016 by Matthias Ewering	###
###					###
###	 matthias.ewering@posteo.de	###
###					###
###	!! No warranty whatsoever !!	###
###					###
###########################################

source=/path/to/source	#The element to be backed up
daily=/path/to/backup/daily	#The directory that will contain the daily backup files
weekly=/path/to/backup/weekly	#The directory that will contain the weekly backup files
monthly=/path/to/backup/monthly	#The directory that will contain the monthly backup files
main=/path/to/backup	#The main backup directory for all backup cycles
mirror1=/path/to/backup_mirror1	#The first mirror of the main backup directory
mirror2=/path/to/backup_mirror2	#The second mirror of the main backup directory
#mirrorn=/foo/bar	#The n^th mirror of the main backup directory

tar -czPf ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz "$source"	#Create a compressed tarball with the contents to be backed up

gpg --symmetric --cipher-algo aes256 --passphrase secret -o ./$(date +"%Y-%m-%d_%H-%M")_backup.tar.gz.gpg ./*_backup.*	#Encrypt the tarball. Remember to replace "secret" with A CUSTOM, SECURE PASSPHRASE!

mv ./*.gpg "$daily"	#Move the encrypted backup file to the main daily backup directory

rm ./*_backup.*	#Delete the unencrypted tarball

find "$daily" -type f | sort -rd | sed -e '1,7d' | xargs -d '\n' rm --	#Delete any file from the main daily backup directory with the 8th oldest timestamp or older

if [ $(date +"%u") = "7" ]

	then 	find "$daily" -type f | sort -d | sed -e '1,6d' | xargs cp -t "$weekly"
											#On a Sunday, copy the latest daily backup file to the weekly backup directory,... 
		find "$weekly" -type f | sort -rd | sed -e '1,5d' | xargs -d '\n' rm --	#...then delete any file from the weekly backup directory with the 6th oldest...
											#...timestamp or older
fi

if [ $(find "$daily" -type f | sort -rd | awk -F '/' '{print $NF}' | cut -c1-4 | head -2 | tail -1) -lt $(date +"%Y") ]
                                                                                                                #When a new year has begun, create an archive directory for...
        then    mkdir "$main"/$(($(date +"%Y") - 1))                                                            #...the old year and move the monthly files to that archive directory

                mv "$monthly"/*.gpg "$main"/$(($(date +"%Y") - 1))

fi

if [ $(date +"%d") = "01" ]
											#On the first of a month, copy the latest daily backup file to the monthly backup directory
	then 	find "$daily" -type f | sort -d | sed -e '1,6d' | xargs cp -t "$monthly"

fi

rsync -a --delete "$main" "$mirror1"	#Synchronize the first mirror directory with the main backup directory

rsync -a --delete "$main" "$mirror2"	#Synchronize the second mirror directory with the main backup directory

#rsync -a --delete "$main" "$mirrorn"	#Synchronize the n^th mirror directory with the main backup directory

exit 0

edit: Fehler in der Sortierung bereinigt.

backup.sh (2.9 KiB)
Download backup.sh

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Hallo,

ich habe das Script komplett neu geschrieben. Dadurch sind einige mögliche Fehlerquellen eliminiert für den Fall, dass das Script in bei einem vorherigen Termin einmal nicht korrekt durchgelaufen sein sollte. Wie immer freue ich mich über Tipps und Hinweise zur Verbesserung des Codes.

#!/bin/bash


# Define the directory structure:

source=/path/to/source
destination=/path/to/destination
daily="$destination"/daily
weekly="$destination"/weekly
monthly="$destination"/monthly
mirror_1=/path/to/mirror_1
mirror_2=/path/to/mirror_2


# Create a tarball containing the data:

tar -czPf ./$(date +"%Y%m%d")_backup.tar.gz $source


# Encrypt the tarball to the daily backup directory.
# Hint: You may also give the passphrase as a string
# rather than reading it from an external file.

gpg --symmetric --cipher-algo aes256 --passphrase $(cat /path/to/passphrase.txt) -o "$daily"/$(date +"%Y%m%d")_backup.tar.gz.gpg ./*_backup.tar.gz


# Delete the unencrypted tarball:

rm ./*_backup.tar.gz


# Delete the 8th oldest (and older) daily backup file(s):

find "$daily" -type f | sort -rd | sed -e '1,7d' | xargs -d '\n' rm -f


# If the calendar week in the 2nd most recent daily backup file's
# timestamp does not match the current calendar week, copy the oldest
# daily backup fily to the weekly backup directory and then delete
# the 6th oldest (and older) weekly backup file(s):

if [ $(date -d $(find "$daily" -type f | sort -d | awk -F / '{print $NF}' | tail -n2 | head -n1 | cut -c1-8) +%V) -ne $(date +%V) ] ;

	then	

		find "$daily" -type f | sort -d | head -n1 | xargs cp -t "$weekly"

		find "$weekly" -type f | sort -rd | sed -e '1,5d' | xargs -d '\n' rm -f

fi


# If the month in the latest weekly backup file's timestamp does not
# match the current month, copy the oldest weekly backup file to the
# monthly backup directory:

if [ $(find "$weekly" -type f | sort -d | awk -F / '{print $NF}' | tail -n1 | cut -c5-6) -ne $(date +%m) ] ;

	then	

		find "$weekly" -type f | sort -d | head -n1 | xargs cp -t "$monthly"

fi


# Move each backup file in the monthly backup directory whose timestamp's
# year does not match the current year to an archive directory for the
# pertaining year. If no appropriate archive direcotry exists, create it
# first:

for i in `find "$monthly" -type f` ; do

        if [ $(echo $i | awk -F / '{print $NF}' | cut -c1-4) -ne $(date +%Y) ] ;

                then    

			year=$(echo $i | awk -F / '{print $NF}' | cut -c1-4)

                        if [ $(find "$destination" -maxdepth 1 -type d -name "*$year*" | wc -l) -ne 0 ] ;

                        	then    

					mv $i "$destination"/"$year"

                        	else    

					mkdir "$destination"/"$year"

                                	mv $i "$destination"/"$year"

                        fi

        fi

done


# Synchronize the entire backup set to mirror1:

rsync -a --delete "$destination" "$mirror_1"


# Synchronize the entire backup set to mirror2:

rsync -a --delete "$destination" "$mirror_2"

backup.sh (2.7 KiB)
Download backup.sh

matze69

(Themenstarter)
Avatar von matze69

Anmeldungsdatum:
23. November 2008

Beiträge: 112

Hallo,

und noch ein Update: Ich habe eine Funktion hinzugefügt, die nach jedem Updatezyklus eine Mail versendet und so über Dauer und Größe des aktuellen Backups sowie des gesamten Datensatzes informiert. Außerdem wird ersichtlich, welche Backupaufrufe an dem entsprechenden Tag gemacht wurden. Damit das Reporting per Mail funktioniert, muss msmtp installiert und natürlich zum Versenden von Mails konfiguriert sein.

Wie immer freue ich mich über Tipps und Hinweise zur Verbesserung des Codes.

#!/bin/bash


# Keep track of time:

SECONDS=0
starttime=$(date)


# Initialize job control variables:

dailydone=0
weeklydone=0
monthlydone=0
yearlydone=0


# Define the directory structure:

source=/path/to/source
destination=/path/to/destination
daily="$destination"/daily
weekly="$destination"/weekly
monthly="$destination"/monthly
mirror_1=/path/to/mirror_1
mirror_2=/path/to/mirror_2
mirror_3=/path/to/mirror_3


# Create a tarball containing the data:

tar -czPf ./$(date +"%Y%m%d")_backup.tar.gz $source


# Encrypt the tarball to the daily backup directory.
# Hint: You may also give the passphrase as a string
# rather than read it from an external file.

gpg --symmetric --cipher-algo aes256 --passphrase $(cat /path/to/backuppass.txt) -o "$daily"/$(date +"%Y%m%d")_backup.tar.gz.gpg ./*_backup.tar.gz


# Delete the unencrypted tarball:

rm ./*_backup.tar.gz


# Delete the 8th oldest (and older) daily backup file(s):

find "$daily" -type f | sort -rd | sed -e '1,7d' | xargs -d '\n' rm -f

dailydone=1

# If the calendar week in the 2nd most recent daily backup file's
# timestamp does not match the current calendar week, copy the oldest
# daily backup fily to the weekly backup directory and then delete
# the 6th oldest (and older) weekly backup file(s):

if [ $(date -d $(find "$daily" -type f | sort -d | awk -F / '{print $NF}' | tail -n2 | head -n1 | cut -c1-8) +%V) -ne $(date +%V) ] ;

	then	

		find "$daily" -type f | sort -d | head -n1 | xargs cp -t "$weekly"

		find "$weekly" -type f | sort -rd | sed -e '1,5d' | xargs -d '\n' rm -f

		weeklydone=1

fi


# If the month in the latest weekly backup file's timestamp does not
# match the current month, copy the oldest weekly backup file to the
# monthly backup directory:

if [ $(find "$weekly" -type f | sort -d | awk -F / '{print $NF}' | tail -n1 | cut -c5-6) -ne $(date +%m) ] ;

	then	

		find "$weekly" -type f | sort -d | head -n1 | xargs cp -t "$monthly"

		monthlydone=1

fi


# Move each backup file in the monthly backup directory whose timestamp's
# year does not match the current year to an archive directory for the
# pertaining year. If no appropriate archive direcotry exists, create it
# first:

for i in `find "$monthly" -type f` ; do

        if [ $(echo $i | awk -F / '{print $NF}' | cut -c1-4) -ne $(date +%Y) ] ;

                then    

			year=$(echo $i | awk -F / '{print $NF}' | cut -c1-4)

			yearlydone=1

                        if [ $(find "$destination" -maxdepth 1 -type d -name "*$year*" | wc -l) -ne 0 ] ;

                        	then    

					mv $i "$destination"/"$year"

                        	else    

					mkdir "$destination"/"$year"

                                	mv $i "$destination"/"$year"

                        fi

        fi

done


# Keep track of time:

timestamp_0=$SECONDS


# Synchronize the entire backup set to mirror_1:

rsync -a --delete "$destination" "$mirror_1"


# Keep track of time:

timestamp_1=$(( $SECONDS - $timestamp_0 ))


# Synchronize the entire backup set to mirror_2:

rsync -a --delete "$destination" "$mirror_2"


# Keep track of time:

timestamp_2=$(( $SECONDS - $timestamp_0 - $timestamp_1 ))


# Synchronize the entire backup set to mirror_3:

rsync -a --delete "$destination" "$mirror_3"


# Keep track of time:

timestamp_3=$(( $SECONDS - $timestamp_0 - $timestamp_1 - $timestamp_2 ))

endtime=$(date)


# Send a notification after the backup cycle is complete:

echo "From: Backup script <donotreply@backup.sys>" >> ./mailtext

echo "To: Herr/Frau Empfänger(in) <name@e-mail.net>" >> ./mailtext

echo "Date: $(date)" >> ./mailtext

echo "Subject: [$(date +%Y/%m/%d)] Daily backup report" >> ./mailtext

echo -e "\n" >> ./mailtext

echo "	+++ BEGIN MESSAGE +++" >> ./mailtext

echo " " >> ./mailtext

echo " " >> ./mailtext

echo "Startzeit:        $starttime" >> ./mailtext

echo "Endzeit:		 $endtime" >> ./mailtext

echo " " >> ./mailtext

echo " " >> ./mailtext

echo "Gesamtdauer:      $(($SECONDS/3600))h $(($SECONDS/60))m $(($SECONDS % 60))s" >> ./mailtext

echo " " >> ./mailtext

echo "Master:		$(($timestamp_0/3600))h $(($timestamp_0/60))m $(($timestamp_0 % 60))s" >> ./mailtext

echo "Mirror 1:	$(($timestamp_1/3600))h $(($timestamp_1/60))m $(($timestamp_1 % 60))s" >> ./mailtext

echo "Mirror 2:	$(($timestamp_2/3600))h $(($timestamp_2/60))m $(($timestamp_2 % 60))s" >> ./mailtext

echo "Mirror 3:	$(($timestamp_3/3600))h $(($timestamp_3/60))m $(($timestamp_3 % 60))s" >> ./mailtext

echo " " >> ./mailtext

echo " " >> ./mailtext

if [ $dailydone -eq 1 ] ;

	then

		echo "Täglich:	JA" >> ./mailtext

	else

		echo "Täglich:	NEIN" >> ./mailtext

fi

if [ $weeklydone -eq 1 ] ;

	then

		echo "Wöchentlich:	JA" >> ./mailtext

	else

		echo "Wöchentlich:	NEIN" >> ./mailtext

fi

if [ $monthlydone -eq 1 ] ;

	then

		echo "Monatlich:	JA" >> ./mailtext

	else

		echo "Monatlich:	NEIN" >> ./mailtext

fi

if [ $yearlydone -eq 1 ] ;

	then

		echo "Jährlich:	JA" >> ./mailtext

	else

		echo "Jährlich:	NEIN" >> ./mailtext

fi

echo " " >> ./mailtext

echo " " >> ./mailtext

echo "Größe:		$(du -h $daily | tail -n1 | awk '{print $1}')" >> ./mailtext

echo "Gesamtgröße:	$(du -h $destination | tail -n1 | awk '{print $1}')" >> ./mailtext

echo " " >> ./mailtext

echo " " >> ./mailtext

echo "	+++ END MESSAGE +++" >> ./mailtext

echo -e "\n" >> ./mailtext

msmtp -a default name@e-mail.net < ./mailtext

rm -f ./mailtext

Antworten |