Last active
May 31, 2023 19:20
-
-
Save researcx/aff274bf5f806af0cf77d23da4c8aa34 to your computer and use it in GitHub Desktop.
proxmox containers backup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -l | |
# set -x | |
# make sure you have zip installed | |
# running: /path/to/proxmox-backup.sh [0/1] | |
# use 0 for debugging, 1 to run | |
# gist.github.com/researcx | |
# configuration | |
backups_folder="/Backups/Pi/$hostname" # needs to exist | |
path="/tmp/backup-$hostname/" | |
path_host=$path"host/" # main sysetm (host) files | |
path_containers="/var/lib/vz/dump" # proxmox container backup storage | |
mail=1 # email a log and important server information (disk space, etc) | |
mailto="root" | |
make_encrypted=0 # luks encrypt the host files and lxd container images | |
encryption_passphrase="passphrase" # passphrase for luks encrypted container | |
path_crypt="luks/" | |
crypt_ext=".crypt" | |
days=7 # delete backups older than x days | |
run=$1 # whether to actually run commands (set to 0 for debugging) | |
wait=120 # amount of seconds to wait between running backup commands, helps calm server load | |
timestamp=$(date +%Y%m%d_%H%M%S) | |
# host files (this is kind of a catch-all) (good to get via history | grep "nano /etc"), space separated | |
host_files=("/root/.bashrc" "/root/.ssh" "/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" "/etc/iptables.rules" "/etc/ip6tables.rules" "/etc/iptables" "/etc/modprobe.d" "/etc/pve" "/etc/udev" "/etc/modules-load.d" "/etc/systemd" "/etc/update-motd.d" "/etc/lightdm" "/etc/groups" "/etc/passwd" "/etc/nsswitch.conf" "/etc/netatalk" "/etc/samba" "/etc/avahi" "/etc/default" "/etc/nanorc" "/etc/X11" "/etc/netconfig") | |
# proxmox containers, numbers, space separated | |
core=("100" "101" "102" "103") # dnscrypt, nginx, ldap, ircd | |
# log | |
log_file=backup-$hostname-$timestamp.log | |
log=$path$log_file | |
# make the directories | |
rm -r $path | |
rm -r $path_containers | |
mkdir -p $path | |
mkdir -p $path_host | |
mkdir -p $path_containers | |
mkdir -p $backups_folder | |
if [[ "$make_encrypted" == 0 ]]; then | |
mkdir -p $path$path_crypt | |
fi | |
# functions | |
convertsecs() { | |
((h=${1}/3600)) | |
((m=(${1}%3600)/60)) | |
((s=${1}%60)) | |
printf "%02d:%02d:%02d\n" $h $m $s | |
} | |
proxmox_backup() { | |
container=$1 | |
vzdump $container | |
pct unlock $container | |
} | |
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" | |
fallocate -l "$size"KB $path$path_crypt$crypt_filename | |
printf $encryption_passphrase | cryptsetup luksFormat $path$path_crypt$crypt_filename - | |
printf $encryption_passphrase | cryptsetup luksOpen $path$path_crypt$crypt_filename $crypt_mapper | |
mkfs -t ext4 $crypt_devmapper | |
mkdir -p $mountpoint | |
mount $crypt_devmapper $mountpoint | |
} | |
unmount_encrypted_container(){ | |
name=$1 | |
mountpoint="$2/enc/" | |
crypt_mapper=$hostname-$name-$timestamp | |
crypt_devmapper="/dev/mapper/$crypt_mapper" | |
umount $mountpoint | |
cryptsetup luksClose $crypt_mapper | |
} | |
# clean up old backups | |
if [[ "$run" == 1 ]]; then | |
if [[ "$make_encrypted" == 1 ]]; then | |
find $backups_folder -maxdepth 1 -name "*$crypt_ext" -type f -mtime +$days -print -delete >> $log | |
fi | |
find $backups_folder -maxdepth 1 -name "*.log" -type f -mtime +$days -print -delete >> $log | |
find $backups_folder -maxdepth 1 -name "*.tar" -type f -mtime +$days -print -delete >> $log | |
find $backups_folder -maxdepth 1 -name "*.zip" -type f -mtime +$days -print -delete >> $log | |
fi | |
# start main code | |
START_TIME=$(date +%s) | |
echo "Backup:: Script start -- $timestamp" >> $log | |
echo "Backup:: Host: $hostname -- Date: $timestamp" >> $log | |
echo "Paths:: Host: $path" >> $log | |
echo "Paths:: Containers: $path_containers" >> $log | |
echo "Paths:: Backups: $backups_folder" >> $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 | |
mv $path_host/*.zip "$path_host/enc/" | |
echo "Backup:: Unmounting encrypted container" >> $log | |
unmount_encrypted_container "host" $path_host | |
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_containers" >> $log | |
if [[ "$run" == 1 ]]; then | |
proxmox_backup $container >> $log | |
sleep $wait | |
fi | |
done | |
if [[ "$run" == 1 ]]; then | |
if [[ "$make_encrypted" == 1 ]]; then | |
echo "Backup:: Making an encrypted container for containers" >> $log | |
make_encrypted_container "containers" $path_containers | |
echo "Backup:: Moving files to encrypted container" >> $log | |
mv $path_containers/*.tar.gz "$path_containers/enc/" | |
echo "Backup:: Unmounting encrypted container" >> $log | |
unmount_encrypted_container "core" $path_containers | |
rm -rf $path_containers/* | |
echo "Backup:: Successfully encrypted core container backup" >> $log | |
fi | |
sleep $wait | |
fi | |
rsync -a --progress $log $backups_folder >> $log | |
if [[ "$make_encrypted" == 1 ]]; then | |
rsync -a --progress $path$path_crypt $backups_folder >> $log | |
else | |
rsync -a --progress $path_host $backups_folder >> $log | |
rsync -a --progress $path_containers/ $backups_folder >> $log | |
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 $backups_folder | 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 | |
sendmail -v $mailto < $log | |
fi | |
sleep $wait | |
rm -r $path | |
rm -r $path_containers |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi!
It runs vzdump on each VM listed in
core
on line 34https://gist.github.com/researcx/aff274bf5f806af0cf77d23da4c8aa34#file-proxmox-backup-sh-L34
path_containers
(/var/lib/vz/dump by default) is the location where the vzdump images/backups get saved by vzdump, if this location is different for you, then specify it, otherwise leave itif make_encrypted is set to 1 then it will make LUKS images to put the folder containing the vzdump images and host files such as things from /etc/ into
the idea of this script is to encrypt VM and host backups if you want to upload them somewhere