diff --git a/cloud_backup.conf b/cloud_backup.conf new file mode 100644 index 0000000..2fd6e8e --- /dev/null +++ b/cloud_backup.conf @@ -0,0 +1,27 @@ +#!/bin/bash + +# Path to nextclouds data folder +CONFIG_NC_DATA="/srv/nextcloud-data" +# Path to the web root of the nextcloud +CONFIG_NC_BASE="/var/www/nextcloud" +# Folder for the log file - relative to nextcloud data folder! +CONFIG_NC_LOGPATH="admin/files/System/" +# Where to find the file with folders to exclude from backup +CONFIG_EXCLUDE=/home/cloudbackup/.config/cloud_backup.exclude +# Host of the database +CONFIG_NC_DB_SERVER=localhost +# Name of the nextcloud database +CONFIG_NC_DB_NAME=nextclouddb +# User for the nextcloud datbase +CONFIG_NC_DB_USER=nextclouduser +# Folders to backup with rsync +BACKUP_SOURCES=(/srv/nextcloud-data /var/www/nextcloud) + +# Target server for backup +TOSSH= +# port to use for ssh/rsync +SSHPORT=10110 +# User for the backup server +SSHUSER="cloudbackup" +# target folder on the backup server +BACKUP_TARGET= diff --git a/cloud_backup.exclude b/cloud_backup.exclude new file mode 100644 index 0000000..9fa98ba --- /dev/null +++ b/cloud_backup.exclude @@ -0,0 +1,2 @@ +# List all folders to exclude, one folder per line +/srv/nextcloud-data/updater* diff --git a/cloud_backup.sh b/cloud_backup.sh new file mode 100755 index 0000000..5a3eaac --- /dev/null +++ b/cloud_backup.sh @@ -0,0 +1,195 @@ +#!/bin/bash +## File: cloud_backup.sh +## This automates backup of your nextcloud. +## Run as a backup user with the group rights of www-data and the ricght to sudo as that user. +## Within mariadb an user should exist, which has read permissions to everything, but only that! + +source ~/.config/cloud_backup.conf + +## Returns the binaries full path if existent. +function which_is() { + declare -n RETVAL=$1; # declare RETVAL a reference of $1 + local EXECUTABLE=$2; + local WITHFULLPATH=$(which ${EXECUTABLE} 2>/dev/null); + if [ -x "$WITHFULLPATH" ]; then + RETVAL="$WITHFULLPATH"; + return 0; + else + RETVAL="$EXECUTABLE not found!"; + return 1; + fi +} + +## Log levels for messages +LLMUTE=0 +LLMDTRY=1 +LLERROR=2 +LLWARNING=3 +LLINFO=4 +LLDEBUG=5 +## Actual log level of the logger used +LOGLEVEL=$LLDEBUG + +## Write log of the script +function logger() { + local LOGGINGLEVEL=$1; + local LOGMESSAGE=$2; + local _NOW=$($DATE +%Y%m%d_%H:%M:%S); + if [[ $LOGLEVEL -ge $LOGGINGLEVEL ]]; then + echo "cloud_backup $_NOW: ${LOGMESSAGE}" >> $LOGFILE; + fi + if [[ $LOGLEVEL -eq $LLDEBUG ]]; then + echo "cloud_backup $_NOW: ${LOGMESSAGE}"; + fi +} + +## updates nextcloud files cache for a given path +## $1 Path to update nextcloud filescache on. +## Attention: path is relative to nextcloud data folder without '/'! +## return 0 in case of success, 1 on fail. +update_filescache() { + local CLOUDPATH=$1; + logger $LLINFO "Updating file cache for $CLOUDPATH."; + logger $LLDEBUG "$SUDO -u www-data $PHP ${CONFIG_NC_BASE}occ files:scan --path=\"$CLOUDPATH\""; + $SUDO -u www-data $PHP ${CONFIG_NC_BASE}occ files:scan --path="$CLOUDPATH"; + return $?; +} + +## Cleanup and exit with exit value given. +function clean_up() { + local EXITVAL=$1; + logger $LLINFO "Cleaning up on exit $EXITVAL."; + # re-enable the cloud under all circumstances! + logger $LLINFO "Re-enabling cloud, switching maintenance mode off."; + $SUDO -u www-data $PHP ${CONFIG_NC_BASE}occ maintenance:mode --off; + logger $LLINFO "Making log file $CONFIG_NC_LOGPATH visible to cloud."; + update_filescache ${CONFIG_NC_LOGPATH}; # make logfile visible in cloud + if [ $? -ne 0 ]; then logger $LLWARNING "Could not update files cache of nextcloud!"; fi + logger $LLMDTRY "Exiting on $EXITVAL."; + exit $EXITVAL; +} + +#echo "Levels $LLMUTE $LLMDTRY $LLERROR $LLWARNING $LLINFO $LLDEBUG Loglevel: $LOGLEVEL"; + +## Check binaries availability +which_is SUDO 'sudo'; +if [ $? -ne 0 ]; then echo $SUDO; exit 1; fi + +which_is DATE 'date'; +if [ $? -ne 0 ]; then echo $DATE; exit 1; fi + +which_is MYSQLDUMP 'mysqldump'; +if [ $? -ne 0 ]; then echo $MYSQLDUMP; exit 1; fi + +which_is RSYNC 'rsync'; +if [ $? -ne 0 ]; then echo $RSYNC; exit 1; fi + +which_is LN 'ln'; +if [ $? -ne 0 ]; then echo $LN; exit 1; fi + +which_is RM 'rm'; +if [ $? -ne 0 ]; then echo $RM; exit 1; fi + +which_is SSH 'ssh'; +if [ $? -ne 0 ]; then echo $SSH; exit 1; fi + +which_is PHP 'php'; +if [ $? -ne 0 ]; then echo $PHP; exit 1; fi + +which_is TOUCH 'touch' +if [ $? -ne 0 ]; then echo $TOUCH; exit 1; fi + +which_is CHOWN 'chown' +if [ $? -ne 0 ]; then echo $CHOWN; exit 1; fi + +# Add slash to paths if missing +if [ "${BACKUP_TARGET:${#BACKUP_TARGET}-1:1}" != "/" ]; then + BACKUP_TARGET=$BACKUP_TARGET/ +fi + +if [ "${CONFIG_NC_DATA:${#CONFIG_NC_DATA}-1:1}" != "/" ]; then + CONFIG_NC_DATA=$CONFIG_NC_DATA/ +fi + +if [ "${CONFIG_NC_BASE:${#CONFIG_NC_BASE}-1:1}" != "/" ]; then + CONFIG_NC_BASE=$CONFIG_NC_BASE/ +fi +if [ "${CONFIG_NC_LOGPATH:${#CONFIG_NC_LOGPATH}-1:1}" != "/" ]; then + CONFIG_NC_LOGPATH=$CONFIG_NC_LOGPATH/ +fi + +## Logfile in nextcloud to have a visible result. +RUNDATE=$($DATE +%Y_%m_%d) +LOGFILE="$CONFIG_NC_DATA$CONFIG_NC_LOGPATH${RUNDATE}_cloudbackup.log"; +$TOUCH ${LOGFILE}; +if [ $? -ne 0 ]; then + echo "Could not create log file! exiting."; + exit 1; +fi +logger $LLINFO "Chown logfile $LOGFILE."; +$CHOWN :www-data ${LOGFILE}; +if [ $? -ne 0 ]; then + logger $LLWARNING "Cloud not set group ownership of log file."; # The logfile may not appaer in the clouds dedicated folder. + exit 1; +fi + +logger $LLINFO "Making log file $CONFIG_NC_LOGPATH visible to cloud."; +update_filescache $CONFIG_NC_LOGPATH; # make logfile visible in cloud +if [ $? -ne 0 ]; then + logger $LLWARNING "Could not update files cache of nextcloud!"; +fi + +TODAY=$($DATE +%y%m%d_%H%M) + +logger $LLMDTRY "Starting backup for ${TODAY}."; +## Let nextcloud enter maintenance mode +logger $LLDEBUG "$SUDO -u www-data $PHP ${CONFIG_NC_BASE}occ maintenance:mode --on;"; +logger $LLINFO "Enabling maintenance mode of nextcloud."; +$SUDO -u www-data $PHP ${CONFIG_NC_BASE}occ maintenance:mode --on; +if [[ "$?" != "0" ]]; then logger $LLERROR "Setting nextcloud maintenance mode failed!"; clean_up 1; fi +## Dump mariadb +logger $LLDEBUG "$MYSQLDUMP --single-transaction -h ${CONFIG_NC_DB_SERVER} -u ${CONFIG_NC_DB_USER} -p${CONFIG_NC_DB_PASSWD} ${CONFIG_NC_DB_NAME} > $CONFIG_NC_DATA/${TODAY}_nextcloud.sqlbkp;"; +logger $LLINFO "Dumping nextcloud database."; +$MYSQLDUMP --single-transaction -h ${CONFIG_NC_DB_SERVER} -u ${CONFIG_NC_DB_USER} ${CONFIG_NC_DB_NAME} > $CONFIG_NC_DATA/${TODAY}_nextcloud.sqlbkp; +if [[ "$?" != "0" ]]; then logger $LLERROR "Dump of the nextcloud database failed!"; clean_up 1; fi +## Connect to Borg Repo and backup the: +## - config folder, +## - data folder, +## - theme folder, +## - dumped database + +# Simple backup with rsync +# local-mode, tossh-mode, fromssh-mode + +### do not edit ### +RSYNCCONF=(--delete) + +LAST="last"; INC="--link-dest=$BACKUP_TARGET$LAST" + +if [ "$SSHUSER" ] && [ "$SSHPORT" ]; then + S="$SSH -p $SSHPORT -l $SSHUSER"; +else + logger $LLERROR "Invalid ssh command, port or user: »$SSH« »$SSHPORT« «$SSHUSER«"; + clean_up 1; +fi + +for SOURCE in "${BACKUP_SOURCES[@]}"; do + logger $LLDEBUG "$RSYNC -e $S --exclude-from=$CONFIG_EXCLUDE -avR $SOURCE ${RSYNCCONF[@]} $TOSSH:$BACKUP_TARGET$TODAY $INC"; + logger $LLINFO "Rsyncing $SOURCE."; + $RSYNC -e "$S" --exclude-from=$CONFIG_EXCLUDE -avR "$SOURCE" "${RSYNCCONF[@]}" "$TOSSH:$BACKUP_TARGET$TODAY" $INC; + if [ $? -ne 0 ]; then logger $LLERROR "Rsync of $SOURCE failed!"; fi +done +if [ "$S" ] && [ "$TOSSH" ] && [ -z "$FROMSSH" ]; then + logger $LLDEBUG "$S $TOSSH $LN -nsf $TARGET$TODAY $TARGET$LAST"; + logger $LLINFO "Setting Link to last to »$TARGET$TODAY«"; + $S $TOSSH "$LN -nsf $TARGET$TODAY $TARGET$LAST"; + if [ $? -ne 0 ]; then logger $LLERROR "Resetting link to last backup of todays failed!"; clean_up 1; fi +fi +logger $LLMDTRY "Backup of nextcloud done, cleaning up."; + +#if [[ "$?" != "0" ]]; then $(logger 1 "Borgbackup of the nextcloud data folder failed!"); exit 1; fi +#if [[ "$?" != "0" ]]; then $(logger 1 "Borgbackup of the nextcloud database failed!"); exit 1; fi + +## End maintenance mode of nextcloud end exit 0 +clean_up 0; +## EOF