Skip to content

Instantly share code, notes, and snippets.

@researcx
Created October 1, 2020 20:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save researcx/4ec53ed98270aa60f8ea93b3cf465aeb to your computer and use it in GitHub Desktop.
Save researcx/4ec53ed98270aa60f8ea93b3cf465aeb to your computer and use it in GitHub Desktop.
server backup script for host files and lxd containers (supports backing up into luks images)
#!/bin/bash
#set -x
# configuration
hostname=$(hostname)
lxc="/snap/bin/lxc"
path="/mount/backups/$hostname/"
path_host=$path"host/"
path_lxd=$path"lxd/"
path_lxd_core=$path"lxd/core/"
mail=1 # email a log and important server information (disk space, etc)
mailto="root"
make_encrypted=1 # luks encrypt the host files and lxd container images
encryption_passphrase="passphrase" # passphrase for luks encrypted container
path_crypt="luks/"
crypt_ext=".encrypted"
days=7 # delete backups older than x days
run=1 # whether to actually run commands (set to 0 for debugging)
wait=15 # amount of time to wait between running backup commands, helps calm server load
timestamp=$(date +%Y%m%d_%H%M%S)
# make the directories
/bin/mkdir -p $path
/bin/mkdir -p $path_host
/bin/mkdir -p $path_lxd
/bin/mkdir -p $path_lxd_core
if [[ "$make_encrypted" == 1 ]]; then
/bin/mkdir -p $path$path_crypt
fi
# functions
convertsecs() {
((h=${1}/3600))
((m=(${1}%3600)/60))
((s=${1}%60))
/usr/bin/printf "%02d:%02d:%02d\n" $h $m $s
}
lxdbackup() {
container=$1
folder=$2
snapshotname=$container-$timestamp.snapshot
backupname=lxd-image-$container-$timestamp
$lxc snapshot $container $snapshotname
$lxc publish --force $container/$snapshotname --alias $backupname
$lxc image export $backupname $folder$backupname
$lxc delete $container/$snapshotname
$lxc image delete $backupname
}
# use encrypted folders?
make_encrypted_container(){
name=$1
file=$2
mountpoint="$2/enc/"
size=$(du -s $file | awk '{print $1}')
if [ "$size" -lt "65536" ]; then # cryptsetup: luks images need to be +32mb in order to be able to be formatted/opened
size=65536
else
size="$(($size + 65536))" #just being safe! hopefully
fi
crypt_filename=$hostname-$name-$timestamp$crypt_ext
crypt_mapper=$hostname-$name-$timestamp
crypt_devmapper="/dev/mapper/$crypt_mapper"
/usr/bin/fallocate -l "$size"KB $path$path_crypt$crypt_filename
/usr/bin/printf $encryption_passphrase | /sbin/cryptsetup luksFormat $path$path_crypt$crypt_filename -
/usr/bin/printf $encryption_passphrase | /sbin/cryptsetup luksOpen $path$path_crypt$crypt_filename $crypt_mapper
/sbin/mkfs -t ext4 $crypt_devmapper
/bin/mkdir -p $mountpoint
/bin/mount $crypt_devmapper $mountpoint
}
unmount_encrypted_container(){
name=$1
mountpoint="$2/enc/"
crypt_mapper=$hostname-$name-$timestamp
crypt_devmapper="/dev/mapper/$crypt_mapper"
/bin/umount $mountpoint
/sbin/cryptsetup luksClose $crypt_mapper
}
# host files
host_files=("/root/.bashrc" "/root/.bash_profile" "/root/.bash_history" "/root/.tmux.conf" "/root/.local/share/fish" "/root/scripts" "/etc/wireguard" "/etc/logrotate.d" "/etc/profile" "/etc/netdata" "/etc/fish" "/etc/fail2ban" "/etc/ssh" "/etc/sysctl.conf" "/etc/cron.d" "/etc/cron.daily" "/etc/cron.weekly" "/etc/cron.hourly" "/etc/cron.deny" "/etc/crontab" "/var/spool/cron" "/etc/sysconfig" "/etc/fstab" "/etc/crypttab" "/etc/postfix" "/etc/hosts" "/etc/resolv.conf" "/etc/aliases" "/etc/rsyslog.d" "/etc/ufw" "/etc/pam.d" "/etc/netplan" "/etc/wpa_supplicant" "/etc/network" "/etc/networks" "/etc/apt" "/etc/apticron" "/etc/yum.repos.d")
# lxd containers (names, space separated)
core=("nginx mariadb mail")
# log
logname=backup-$hostname-$timestamp.log
log=$path$logname
# clean up old backups
if [[ "$make_encrypted" == 1 ]]; then
find $path$path_crypt -maxdepth 1 -name "*$crypt_ext" -type f -mtime +$days -print -delete >> $log
fi
find $path_host -maxdepth 1 -name "*.zip" -type f -mtime +$days -print -delete >> $log
find $path_host -maxdepth 1 -name "*.log" -type f -mtime +$days -print -delete >> $log
find $path_lxd_core -maxdepth 1 -name "*.tar.gz" -type f -mtime +$days -print -delete >> $log
# start main code
START_TIME=$(date +%s)
echo "Backup:: Script start -- $timestamp" >> $log
echo "Backup:: Host: $hostname -- Date: $timestamp" >> $log
# host files
echo "Backup:: Backing up the following host files to $path_host" >> $log
echo $host_files >> $log
for host_file in ${host_files[@]}; do
echo "Backup:: Starting backup of $host_file to $path_host" >> $log
host_file_safe=$(echo $host_file | sed 's|/|-|g')
if [[ "$run" == 1 ]]; then
zip -r $path_host$host_file_safe-$timestamp.zip "$host_file" >> $log
fi
done
echo "Backup:: Host files successfully backed up" >> $log
if [[ "$run" == 1 ]]; then
if [[ "$make_encrypted" == 1 ]]; then
echo "Backup:: Making an encrypted container for host files" >> $log
make_encrypted_container "host" $path_host
echo "Backup:: Moving files to encrypted container" >> $log
/bin/mv $path_host/*.zip "$path_host/enc/"
echo "Backup:: Unmounting encrypted container" >> $log
unmount_encrypted_container "host" $path_host
/bin/rm -rf $path_host
echo "Backup:: Successfully encrypted host backup" >> $log
fi
fi
# containers
echo "Backup:: Backing up containers" >> $log
for container in ${core[@]}; do
echo "Backup:: Starting backup on $container to $path_lxd_core" >> $log
if [[ "$run" == 1 ]]; then
lxdbackup $container $path_lxd_core $ >> $log
/bin/sleep $wait
fi
done
if [[ "$run" == 1 ]]; then
if [[ "$make_encrypted" == 1 ]]; then
echo "Backup:: Making an encrypted container for core containers" >> $log
make_encrypted_container "core" $path_lxd_core
echo "Backup:: Moving files to encrypted container" >> $log
/bin/mv $path_lxd_core/*.tar.gz "$path_lxd_core/enc/"
echo "Backup:: Unmounting encrypted container" >> $log
unmount_encrypted_container "core" $path_lxd_core
/bin/rm -rf $path_lxd_core
echo "Backup:: Successfully encrypted core container backup" >> $log
fi
/bin/sleep $wait
fi
END_TIME=$(date +%s)
# end main code
elapsed_time=$(( $END_TIME - $START_TIME ))
echo "Backup :: Script End -- $(date +%Y%m%d_%H%M)" >> $log
echo "Elapsed Time :: $(convertsecs $elapsed_time) " >> $log
backup_size=`find $path -maxdepth 5 -type f -mmin -360 -exec du -ch {} + | grep total$ | awk '{print $1}'`
backup_stored=`find $path -maxdepth 5 -type f -exec du -ch {} + | grep total$ | awk '{print $1}'`
disk_remaining=`df -Ph $path | tail -1 | awk '{print $4}'`
echo -e "Subject: [$hostname] Backup Finished [$backup_size] [stored: $backup_stored | disk remaining: $disk_remaining] (took $(convertsecs $elapsed_time))\n\n$(cat $log)" > $log
if [[ "$mail" == 1 ]]; then
/usr/sbin/sendmail -v $mailto < $log
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment