#!/bin/sh
# Version: 1.2
# Description: Automates Borg backup process with logging, error handling,
# and repository initialization if required.
set -e
# =============================================================================
# Configuration
# =============================================================================
# Hostname setup
FULL_HOSTNAME=$(hostname)
SHORT_HOSTNAME=$(hostname -s)
# Passphrase file
BORG_PASSPHRASE_FILE=~/.borg_passphrase
# SSH key file location
SSH_KEY="/root/.ssh/id_ed25519_$SHORT_HOSTNAME"
# Backup server
REPO_SERVER="backup.servus.at"
# Backup repository location
REPO1="$SHORT_HOSTNAME@$REPO_SERVER:/./borg"
# Log file location
LOG="/var/log/borg_backup.log"
# Directories to backup
DIR_LIST_FILE="/root/scripts/backup_dirs.txt"
# Exclude file
EXCLUDE_FILE="/root/scripts/exclude_dirs.txt"
# =============================================================================
# Functions
# =============================================================================
# Function to log messages
log_message() {
echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" >> "$LOG"
}
# Function to send an email with error message
send_error_mail() {
ERROR_MSG=$1
echo "$ERROR_MSG" | mail -s "Borg Backup Error on $SHORT_HOSTNAME" root
log_message "$ERROR_MSG"
}
# Function to check if the repository exists
check_repo() {
borg list "$REPO1" --rsh="ssh -i $SSH_KEY" > /dev/null 2>&1
}
# Function to initialize the repository if it does not exist
init_repo() {
log_message "Repository not found. Initializing new Borg repository: $REPO1"
if borg init --encryption=repokey "$REPO1" --rsh="ssh -i $SSH_KEY"; then
log_message "Repository initialized successfully: $REPO1"
else
ERROR_MSG="Error initializing repository: $REPO1"
send_error_mail "$ERROR_MSG"
exit 1
fi
}
# Function to perform backup
perform_backup() {
log_message "Starting backup of directories: $BACKUP_DIRS"
if borg create --progress --lock-wait 10 --read-special $EXCLUDES "$REPO1::'{hostname}-{now:%Y-%m-%d}'" $BACKUP_DIRS --rsh="ssh -i $SSH_KEY"; then
log_message "Backup completed successfully."
else
ERROR_MSG="Error during backup creation."
send_error_mail "$ERROR_MSG"
exit 1
fi
}
# Function to prune old backups
prune_backups() {
log_message "Starting pruning of old backups"
if borg prune -v --list "$REPO1" --keep-daily=7 --keep-weekly=4 --keep-monthly=6 --rsh="ssh -i $SSH_KEY"; then
log_message "Pruning completed successfully."
else
ERROR_MSG="Error during pruning."
send_error_mail "$ERROR_MSG"
exit 1
fi
}
# =============================================================================
# Main Process
# =============================================================================
log_message "Borg backup process started."
# Get the system's hostname and short hostname
if [ "$FULL_HOSTNAME" != "$SHORT_HOSTNAME" ]; then
log_message "Warning: Full hostname ($FULL_HOSTNAME) differs from short hostname ($SHORT_HOSTNAME)"
fi
# Setup Borg passphrase from a secure file
if [ ! -f "$BORG_PASSPHRASE_FILE" ]; then
log_message "Passphrase file is empty or not found: $BORG_PASSPHRASE_FILE"
exit 1
fi
export BORG_PASSPHRASE=$(cat "$BORG_PASSPHRASE_FILE")
# Check if the repository exists
if ! check_repo; then
init_repo
else
log_message "Repository found: $REPO1"
fi
# Check if the directories list file exists
if [ ! -f "$DIR_LIST_FILE" ]; then
ERROR_MSG="Backup directories list file not found: $DIR_LIST_FILE"
send_error_mail "$ERROR_MSG"
exit 1
fi
BACKUP_DIRS=$(cat "$DIR_LIST_FILE" | xargs)
log_message "Directories to be backed up: '$BACKUP_DIRS'"
# Check if the exclude file exists, create if not
if [ ! -f "$EXCLUDE_FILE" ]; then
log_message "Exclude directories list file not found: $EXCLUDE_FILE, creating it."
touch "$EXCLUDE_FILE"
fi
EXCLUDES=$(awk '{print "--exclude " $0}' "$EXCLUDE_FILE" | xargs)
# Perform backup and prune old backups
perform_backup
prune_backups
log_message "Borg backup process completed."
# Unset sensitive variables
unset BORG_PASSPHRASE