ownCloud Backup Script

Problem

I am running ownCloud on my Synology NAS for some months now and I am pretty happy how reliable it works. But if in some case my RAID would fail I’d loose all my private data. A periodic backup needed to be set up that backs up all my data in addition to the ownCloud configuration and database.

Solution

A bash script! What else? It somehow built up from a simple copy to a full fledged backup-split-dump-log bash script that I’d like to share with you. The full script is at the bottom of this page. I’d now like to talk about the parameters you should now to use this script on your installation.

What it does

The script simply backs up all you ownCloud data and configuration so that you could make a fresh install in case of a total failure.

  1. Makes a database dump and copies it to the backup destination
  2. Archives, splits and copies the ownCloud data in 1GB files to the backup destination
  3. Copies the ownCloud configuration dir to the backup destination

Requirements

This script should work with every installation of ownCloud using a MySQL database. I am running it on my Synology now but it was running on an Ubuntu Server for a year now successfully. Additionally you need a MySQL user that has SELECT and LOCK TABLES permissions on the owncloud database.

Parameters

All user dependant parameters are located on the top of the script. They are:

[table id=3 /]

Usage

I am running the script through Task Scheduler once a week.

  1. Control Panel -> Task Scheduler
  2. Create -> Scheduled Task -> User-defined Script
  3. Task: ocbackup User: root This is very important
  4. Task Settings User-defined Script: Location of the ocbackup.sh file

The Script

Also available here: https://gist.github.com/noah95/9cd484c894ae629963c00a1ef973e8f9

Enjoy!

#!/bin/bash

# Author:	noah huetter - dlatch.com
# 
# v2: 
#	- added database backup
#	- partial file transfer for no big file junk on /tmp
# v3:
# 	- Variables for user settings
# 	- Comments and functions

################################################################################
## USER SETTINGS
################################################################################
## Set to 1 to make a dry run without writing anything or 0 for normal mode
DRY_RUN=0

## Set to 1 to delete the oldest backup on the destination before this backup
## starts.
DELETE_OLDEST_BACKUP=1

## Log file location
LOG_FILE=/var/services/homes/admin/ocbackup/logs/ocbackup_log_`date +%Y-%m-%d.%H%M%S`.txt

## Default backup detination if none is passed to the script
DEFAULT_DEST=/volume1/remotes/usbshare1/ocbackup/

## Location of the owncloud command line tool
OCC_LOCATION=/volume1/web/owncloud/occ

## owncloud Installation directory
OC_LOCATION=/volume1/web/owncloud

## Web user to run occ
OC_WEB_USR=http

## Owncloud data location
SOURCE=/volume3/clouddata/clouddata/

## Database user, needs SELECT access on DB_NAME
DB_USR=backup

## Database user password
DB_PW=supersecretpassword42

## owncloud database name
DB_NAME=owncloud

################################################################################
## FUNCTIONS
################################################################################

## On Exit
function finish {
	echo "Disable maintenance.."
	if [ "$DRY_RUN" == "0" ]; then
		sudo -u $OC_WEB_USR php56 $OCC_LOCATION maintenance:mode --off
	fi
	echo "Done"
	# copy log file to destination
	cp -v $LOG_FILE $DEST/$FOLDERNAME
}
trap finish EXIT

##
## @brief      Check folder Access and exit if no write permission
##
function checkFolderAccess {
	USER=$(whoami)
	INFO=( $(stat -L -c "%a %G %U" $DEST) )
	PERM=${INFO[0]}
	GROUP=${INFO[1]}
	OWNER=${INFO[2]}
	ACCESS=no
	if [[ $PERM && 0002 != 0 ]]; then
	    # Everyone has write access
	    ACCESS=yes
	elif [[ $PERM && 0020 != 0 ]]; then
	    # Some group has write access.
	    # Is user in that group?
	    gs=( $(groups $USER) )
	    for g in "${gs[@]}"; do
	        if [[ $GROUP == $g ]]; then
	            ACCESS=yes
	            break
	        fi
	    done
	elif [[ $PERM && 0200 != 0 ]]; then 
	    # The owner has write access.
	    # Does the user own the file?
	    [[ $USER == $OWNER ]] && ACCESS=yes
	fi

	if [ "$ACCESS" == "no" ]; then
		echo "No write access on destination directory!"
		exit
	fi
}

##
## @brief      Check for read access on the specified database and exit if failed
##
function checkDbAccess {
	echo "USE $DB_NAME; show tables;" | mysql -u $DB_USR --password=$DB_PW > /dev/null
	STATUS=$?
	if [ $STATUS != 0 ]; then
		echo "DB Access denied"
		exit
	fi
}

##
## @brief      Enables the maintennance.
##
function enableMaintennance {
	if [ "$DRY_RUN" == "0" ]; then
		sudo -u $OC_WEB_USR php56 $OCC_LOCATION maintenance:mode --on
	fi
}

##
## @brief      Disables the maintennance.
##
function disableMaintennance {
	if [ "$DRY_RUN" == "0" ]; then
		sudo -u $OC_WEB_USR php56 $OCC_LOCATION maintenance:mode --off
	fi
}

##
## @brief      Calculates the data size.
##
function calcDataSize {
	SIZE=`sudo du -sk $SOURCE | cut -f 1`
	return $SIZE
}

##
## @brief      Specify target directory
##
function specifyTarget {
	if [ ! $1 ]; then
		echo "No target specified! Using default."
		DEST=$DEFAULT_DEST
	else
		DEST=$1
	fi
}

##
## @brief      Delete old backup and create new folder
##
function prepareDestination {
	ls -al $DEST

	# delete oldest folder
	DIRS=$(ls $DEST)
	OLDDIR=$(echo $DIRS | head -n1 | cut -d " " -f1)

	if [ "$DRY_RUN" == "0" ]; then
		if [ "$DELETE_OLDEST_BACKUP" == "1" ]; then
			echo "Delete old Folder $OLDDIR"
			rm -rf $DEST/$OLDDIR
			echo "Deleted!"
		fi
	fi

	FOLDERNAME=`date +%Y-%m-%d.%H%M%S`
	if [ "$DRY_RUN" == "0" ]; then
		mkdir $DEST/$FOLDERNAME
	fi
}

################################################################################
## ENTRY
################################################################################
# Start logging
exec > >(tee -i $LOG_FILE)
exec 2>&1
echo "####################################################################"
date
echo "Starting ocbackup"

echo "Specify Target directory"
specifyTarget

echo "Check for write permission on target"
checkFolderAccess

echo "Check for DB access"
checkDbAccess

echo "Reading clouddata source directory filesize..."
calcDataSize
echo Approx $(expr $SIZE / 1024 / 1024)GB of Data

echo "Enable maintenance.."
enableMaintennance

echo "Check for old directory"
prepareDestination

echo "####################################################################"
echo "Destination Foldername:"$DEST/$FOLDERNAME

echo "Dump database"
if [ "$DRY_RUN" == "0" ]; then
	mysqldump -u $DB_USR --password=$DB_PW $DB_NAME > $DEST/$FOLDERNAME/owncloud.sql
fi
STATUS=$?
if [ $STATUS != 0 ]; then
	echo "DB Access denied"
	exit
fi

echo "Copy data and compress"
if [ "$DRY_RUN" == "0" ]; then
	# unfortunately pv is not available on synology...
	# tar cpf - $SOURCE | pv -p -t -e -r -s ${SIZE}k | split -b 1024MiB --suffix-length=4 --numeric-suffix - $DEST/$FOLDERNAME/$NAME.tar_
	tar cpf - $SOURCE | split -b 1024MiB --suffix-length=4 --numeric-suffix - $DEST/$FOLDERNAME/ocbackup.tar_
fi

echo "Split into" `find $DEST/$FOLDERNAME -type f | wc -l` "Files"

echo "Copy config dir"
if [ "$DRY_RUN" == "0" ]; then
	cp -rv $OC_LOCATION/config $DEST/$FOLDERNAME/
fi

echo "Fixing permissions"
if [ "$DRY_RUN" == "0" ]; then
	chown -R root:root  $DEST/$FOLDERNAME
fi

echo "####################################################################"

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.