Skip to content

Instantly share code, notes, and snippets.

@jhollinger
Last active July 6, 2023 09:54
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jhollinger/3805605 to your computer and use it in GitHub Desktop.
Save jhollinger/3805605 to your computer and use it in GitHub Desktop.
rbackup - time-stamped, hard-linked backups powered by rsync

rbackup

rbackup is a lightweight, rsync-powered backup utility that creates time-stamped backups.

Features

It can save backups to your local filesystem (probably an attached USB device) or to a remote host.

Backups are saved in time-stamped directories. Backups are cheap on storage, because hard-links are used for files that haven't changed between backups.

Examples

Backup home to disk:

rbackup ~/ /media/backups/mybox

Backup home to remote host:

rbackup ~/ user@example.com:backups

Configuration

Your target directory (~/ in the examples above) may contain an .rbackup directory. Here are some sample config files useful for ~/:

.rbackup/exclude

# By default, ignore all those top-level hidden files in $HOME
/.*
# Ignore backup files by vim and gedit
**/*.swp
**/*~
# Ignore those Ruby gems and npm modules I installed for development
/devel/**/vendor/bundle
/devel/**/node_modules
# If I downloaded it once, I can download it again
/Downloads

.rbackup/include

# I just want these hidden files
/.vimrc

Scheduling

Just use cron. If you're going to cron remote backups, you'll need to set up an SSH key.

#!/bin/bash
# Create time-stamped backups locally or on a remote host
target=$1
backup_target=$2
[ $3 ] && remote_port=$3 || remote_port=22
init_backup="`dirname $0`/rbackup-init-backup.sh"
config=".rbackup"
if [ ! $target ] || [ ! $backup_target ] || [ ! -e "$target" ]; then
echo "Usage: rbackup /my/files [user@host:]/my/backups [remote port]"
exit 1
fi
# Initialize local backup
if [ -e "$backup_target" ]; then
backup_destination="$backup_target/"
cd "$backup_target"
sh $init_backup
# Initialize remote backup
else
# Parse remote host and path
if [[ "$backup_target" != *:* ]]; then
backup_target="$backup_target:"
fi
remote_host_and_user=${backup_target%:*}
remote_host=${remote_host_and_user#*@}
remote_dir=${backup_target#*:}
# Die if remote host is not reachable
nc -z -w 1 $remote_host $remote_port || { echo "$remote_host could not be reached"; exit 1; }
# Initialize backup
ssh $remote_host_and_user -p $remote_port "cd \"$remote_dir\"; `cat $init_backup`"
if [ $remote_dir ]; then
backup_destination="$remote_host_and_user:$remote_dir/"
else
backup_destination="$remote_host_and_user:"
fi
fi
# Go to the backup target
cd "$target"
# Load config
if [ -f "$config/exclude" ]; then
exclude="--exclude-from=$config/exclude"
fi
if [ -f "$config/include" ]; then
include="--include-from=$config/include"
fi
# Sync away!
rsync -e "ssh -p $remote_port" -avz --hard-links --link-dest="../previous" $include $exclude . "$backup_destination""latest"
new_backup_dir=`date +'%Y-%m-%d_%H-%M-%S'`
# Create new backup directory, or exit if fail
mkdir $new_backup_dir
if [ $? -ne 0 ]; then exit 1; fi
# Remove the old "latest" and "previous", and create new ones
if [ -e previous ]; then rm previous; fi
if [ -e latest ]; then
prev_backup_dir=`ls -l latest | grep -o "[0-9]\{4\}-[0-9]\+-[0-9]\+_[0-9_-]\+"`
rm latest
else
prev_backup_dir=$new_backup_dir
fi
ln -s $prev_backup_dir previous
ln -s $new_backup_dir latest
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment