In this article, I’m going to share the solution, that I personally use to back up this site. When looking for it, I wanted it to meet the following requirements:
In this way, I came to the decision to use ownCloud for my backups. Among the reasons are:
So, I installed the ownCloud console client using the following command:
# apt-get install owncloud-client-cmd
The console client still uses many libraries from the X environment, therefore the aforementioned command will install them as well. But, don’t worry – it won’t install X, only some of its libraries.
It should also be noted, that ownCloud syncs files in two directions. That is, it can update your file on the server, if it believes, that the version of the file in the could is newer. This was one of the problems, that I faced. In my case, these were bugs in the client, but, anyway, server system files should never be updated from the cloud!
So, to prevent the server files from being updated by the ownCloud client, I run it under a special dedicated user, that does not have write access to such files (the id
command shows details about the user):
$ id sync uid=4(sync) gid=34(backup) groups=34(backup)
Certainly, I made sure, that all the files, that I want to backup, are readable by this user. Also, I checked, that no such files are world-writable. Otherwise, the ownCloud client would still be able to override them.
Another problem is, that the ownCloud client needs to store its state files in the directory, it synchronizes, so it should be able to write and update such state files there. Therefore, I changed the group of all such directories to backup
(luckily, it was safe to) and made them writable by this group:
# chgrp backup <directory> # chmod g+w <directory>
However, it should also be recalled, that, if a user is able to write new files to a directory, it will also be able to rename files of that directory, even if it’s not able to modify or delete them directly (yeah, I faced this problem too). This can be solved by the sticky bit, that does not allow users to rename files, that they do not own:
# chmod +t <directory>
Now, it’s safe to run the following command to backup the directory $local_dir
:
$ su - sync -s /bin/sh -c "owncloudcmd -u $user -p $password $local_dir $remote_location"
Here, $remote_location
is the URL to a directory in the cloud, that should already exist and initially be empty (see also the code below).
In addition to the cloud storage, I prefer to have the data, that are backed up from the server, on my local computer as well. Therefore, I also installed the ownCloud client on my desktop and pointed it to the cloud, where the data are stored. As a result, now I can see, what data have been changed on the server since the last backup.
This introduces a couple of new benefits of this ownCloud-based backup solution:
issues
table will get updated (I backup dump of each table separately).In this way, this ownCloud-based solution can serve not only for the backup purpose.
At last, here is the code of the script for backing up data (I put it into /etc/cron.daily/
, what makes it run once a day):
#!/bin/sh
svn=/usr/bin/svn
owncloud=/usr/bin/owncloudcmd
svnadmin=/usr/bin/svnadmin
mysqldump=/usr/bin/mysqldump
safe_owncloud=/usr/local/bin/safe_owncloud
BACKUPS_DIR=/root/Backups
OWNDRIVE_URL=<owncloud.host.com>/remote.php/webdav
OWNDRIVE_USERNAME=<username>
OWNDRIVE_PASSWORD=<password>
OWNDRIVE_ARGS="--silent --non-interactive --user $OWNDRIVE_USERNAME --password $OWNDRIVE_PASSWORD"
OWNDRIVE=ownclouds://$OWNDRIVE_URL
REDMINE_PASSWORD=<password>
WORDPRESS_PASSWORD=<password>
MYSQLDUMP_ARGS="--compact --skip-tz-utc --add-drop-table"
# Backup configuration
$safe_owncloud $OWNDRIVE_ARGS /etc/apache2 $OWNDRIVE/Configuration/Apache 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /etc/postfix $OWNDRIVE/Configuration/Postfix 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /etc/redmine $OWNDRIVE/Configuration/Redmine 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /etc/ssh $OWNDRIVE/Configuration/OpenSSH 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /etc/cron.daily $OWNDRIVE/Configuration/Cron 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /etc/wordpress $OWNDRIVE/Configuration/WordPress 2> /dev/null
# Backup system tools
$safe_owncloud $OWNDRIVE_ARGS /usr/local/bin $OWNDRIVE/Tools 2> /dev/null
# Backup database
for TABLE in `mysql -u redmine -p$REDMINE_PASSWORD redmine -E -e 'SHOW TABLES' | grep '^Tables_in_redmine:' | cut -b20-`; do
$mysqldump -u redmine -p$REDMINE_PASSWORD $MYSQLDUMP_ARGS redmine $TABLE > $BACKUPS_DIR/Redmine/$TABLE.mydump2
if cmp -s $BACKUPS_DIR/Redmine/$TABLE.mydump $BACKUPS_DIR/Redmine/$TABLE.mydump2; then
rm $BACKUPS_DIR/Redmine/$TABLE.mydump2
else
mv $BACKUPS_DIR/Redmine/$TABLE.mydump2 $BACKUPS_DIR/Redmine/$TABLE.mydump
fi
done
$owncloud $OWNDRIVE_ARGS $BACKUPS_DIR/Redmine $OWNDRIVE/Redmine/Database 2> /dev/null
for TABLE in `mysql -u wordpress -p$WORDPRESS_PASSWORD wordpress -E -e 'SHOW TABLES' | grep '^Tables_in_wordpress:' | cut -b22-`; do
$mysqldump -u wordpress -p$WORDPRESS_PASSWORD $MYSQLDUMP_ARGS wordpress $TABLE > $BACKUPS_DIR/WordPress/$TABLE.mydump2
if cmp -s $BACKUPS_DIR/WordPress/$TABLE.mydump $BACKUPS_DIR/WordPress/$TABLE.mydump2; then
rm $BACKUPS_DIR/WordPress/$TABLE.mydump2
else
mv $BACKUPS_DIR/WordPress/$TABLE.mydump2 $BACKUPS_DIR/WordPress/$TABLE.mydump
fi
done
$owncloud $OWNDRIVE_ARGS $BACKUPS_DIR/WordPress $OWNDRIVE/WordPress/Database 2> /dev/null
# Backup code
$safe_owncloud $OWNDRIVE_ARGS /usr/share/redmine $OWNDRIVE/Redmine/Code 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /usr/share/wordpress $OWNDRIVE/WordPress/Code 2> /dev/null
# Backup subversion
# to restore: svnadmin create <repo>; svnadmin load <repo> < <repo>.svndump
for SVN_REPOSITORY in /var/lib/svn/*; do
REPOSITORY_DATE=`$svn info file://$SVN_REPOSITORY | grep '^Last Changed Date' | cut -d' ' -f4-5 | tr -cd '[:digit:]'`
BACKUP_DATE=`stat -c %y $BACKUPS_DIR/Subversion/${SVN_REPOSITORY##*/}.svndump 2> /dev/null | cut -d. -f1 | tr -cd '[:digit:]'`
if [ "x$BACKUP_DATE" = "x" ] || [ $REPOSITORY_DATE -gt $BACKUP_DATE ]; then
$svnadmin dump $SVN_REPOSITORY > $BACKUPS_DIR/Subversion/${SVN_REPOSITORY##*/}.svndump 2> /dev/null
fi
done
$owncloud $OWNDRIVE_ARGS $BACKUPS_DIR/Subversion $OWNDRIVE/Subversion 2> /dev/null
# Backup attachments/files
$safe_owncloud $OWNDRIVE_ARGS /var/lib/redmine $OWNDRIVE/Redmine/Attachments 2> /dev/null
$safe_owncloud $OWNDRIVE_ARGS /var/lib/wordpress/wp-content $OWNDRIVE/WordPress/Content 2> /dev/null
Here, you can see the code, which is used to:
Finally, here is what’s inside /usr/local/bin/safe_owncloud
(this was discussed above):
#!/bin/sh
su=/bin/su
owncloudcmd=/usr/bin/owncloudcmd
OWNCLOUD_USER=sync
OWNCLOUD_SHELL=/bin/sh
$su - $OWNCLOUD_USER -s $OWNCLOUD_SHELL -c "$owncloudcmd $*"
exit 1
]]>