This repository has been archived on 2025-04-03. You can view files and clone it, but cannot push or open issues or pull requests.
linux-bash-scripts/borgmatic/borgmatic_setup.sh

1032 lines
37 KiB
Bash
Executable File

#!/usr/bin/env bash
###############################################################################
# Copyright (c) 2024 Zion Networks UG #
# #
# Permission is hereby granted, free of charge, to any person obtaining a #
# copy of this software and associated documentation files (the "Software"), #
# to deal in the Software without restriction, including without limitation #
# the rights to use, copy, modify, merge, publish, distribute, sublicense, #
# and/or sell copies of the Software, and to permit persons to whom the #
# Software is furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in #
# all copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER #
# DEALINGS IN THE SOFTWARE. #
###############################################################################
# Planned Features:
# - Add support for more distributions
# - Add support for databases
# - Pre-Backup commands
# - Post-Backup commands
# - Add support to run, restore, prune, check, delete and list backups
# - Add support for multiple backup repositories
# - Add support for multiple backup configurations
# - Add support for multiple backup servers
# SETTINGS - Make sure to adjust these settings to your needs
DEBUG=0 # Set to 1 to enable debug mode
BACKUP_REPO="Backups/$(hostname | tr '[:lower:]' '[:upper:]')" # Repository path on the backup server
BACKUP_ENCRYPTION="none" # Encryption method for the backup repository (default: none)
BACKUP_PASSPHRASE='example' # Make sure to change this to a secure passphrase (will be ignored if encryption is set to none)
BACKUP_DIRS="/etc /var/log /home" # Directories to backup, separated by space
BACKUP_LABEL_PREFIX="BACKUP-" # Prefix for the backup label
BACKUP_CRON_SCHEDULE="0 3 * * *" # Cron schedule for backups (default: daily at 3:00 AM)
BORGMATIC_CONFIG_FILE="/etc/borgmatic/config.yaml" # Path to the borgmatic configuration file - DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING
SSH_HOST="127.0.0.1" # Hostname or IP address of the backup server
SSH_PORT="22" # SSH port of the backup server (default: 22)
SSH_USER="root" # SSH user on the backup server
SSH_PASSWORD='12345678' # Only required for copying the ssh key to the backup server
SSH_KEY_NAME="borgmatic"
SSH_KEY_TYPE="ed25519" # SSH key type (e.g. rsa, dsa, ecdsa, ed25519), default: ed25519
SSH_KEY_FILE="/root/.ssh/${SSH_KEY_NAME}_${SSH_KEY_TYPE}"
# SCRIPT - DO NOT EDIT
# internal variables
AUTO=0 # Set to 1 to enable automatic, non-interactive mode
DO_UPGRADE_ALL=0 # Set to 1 to upgrade all installed packages
DO_UPGRADE_REQUIRED=0 # Set to 1 to upgrade only required packages
FIRST_BACKUP=0 # Set to 1 to run the first backup after setup
IS_REMOTE_SYNOLGY=0 # Set to 1 if the remote end is a Synology NAS
OVERRIDE_CRONTAB=0 # Set to 1 to override the existing crontab file
OVERRIDE_CONFIG=0 # Set to 1 to override the existing borgmatic configuration file
OVERRIDE_REPOSITORY=0 # Set to 1 to override the existing backup repository
SKIP_CONFIG=0 # Set to 1 to skip the borgmatic configuration
# constants
readonly SCRIPT_NAME="Borgmatic Backup Setup Tool"
readonly SCRIPT_AUTHOR="Zion Networks at admin@zion-networks.de"
readonly SCRIPT_SUPPORT="admin@zion-networks.de"
readonly VERSION="1.2.4"
# logging functions
function inf {
echo -e "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1"
}
function wrn {
echo -e "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1"
}
function err {
echo -e "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1"
}
function dbg {
if [ $DEBUG -eq 1 ]; then
echo -e "\e[94m[$(date +%H:%M:%S)] \e[1mDBG\e[0m \e[3m$1\e[0m"
fi
}
# logging prompt functions
function infp {
echo -e -n "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1 "
read -p "" -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
else
return 0
fi
}
function wrnp {
echo -e -n "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1 "
read -p "" -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
else
return 0
fi
}
function errp {
echo -e -n "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1 "
read -p "" -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
else
return 0
fi
}
# logging functions that wait for user input (single key)
function infw {
echo -e -n "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1 "
read -n 1 -r
}
function wrnw {
echo -e -n "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1 "
read -n 1 -r
}
function errw {
echo -e -n "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1 "
read -n 1 -r
}
# logging functions with follow up (like "[HH:MM:SS] INF Installig package ... OK" where OK is a follow up)
function inf_follow {
if [ $DEBUG -eq 1 ]; then
echo -e "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1"
else
echo -e -n "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1"
fi
dbg "Running ${@:4}"
${@:4}
_r=$?
dbg "Follow exit status: $_r"
if [ $_r -eq 0 ]; then
if [ $DEBUG -eq 1 ]; then
echo -e "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1: $2"
else
echo -e " $2"
fi
else
if [ $DEBUG -eq 1 ]; then
echo -e "\e[97m[$(date +%H:%M:%S)] \e[1mINF\e[0m $1: $3"
else
echo -e " $3"
fi
fi
return $_r
}
function wrn_follow {
if [ $DEBUG -eq 1 ]; then
echo -e "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1"
else
echo -e -n "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1"
fi
_r=$(${@:4})
dbg "Follow exit status: $_r"
if [ $_r -eq 0 ]; then
if [ $DEBUG -eq 1 ]; then
echo -e "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1: $2"
else
echo -e " $2"
fi
else
if [ $DEBUG -eq 1 ]; then
echo -e "\e[93m[$(date +%H:%M:%S)] \e[1mWRN\e[0m $1: $3"
else
echo -e " $3"
fi
fi
}
function err_follow {
if [ $DEBUG -eq 1 ]; then
echo -e "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1"
else
echo -e -n "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1"
fi
_r=$(${@:4})
dbg "Follow exit status: $_r"
if [ $_r -eq 0 ]; then
if [ $DEBUG -eq 1 ]; then
echo -e "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1: $2"
else
echo -e " $2"
fi
else
if [ $DEBUG -eq 1 ]; then
echo -e "\e[91m[$(date +%H:%M:%S)] \e[1mERR\e[0m $1: $3"
else
echo -e " $3"
fi
fi
}
# setup functions
function apt_update {
exec 3>&1
status=$(apt-get update 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function apt_upgrade {
exec 3>&1
status=$(apt-get upgrade -y 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function apt_upgrade_selected {
exec 3>&1
status=$(apt-get install -y $* 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function apt_install {
exec 3>&1
status=$(apt-get install -y $1 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function pipx_install {
exec 3>&1
status=$(pipx install $1 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function pipx_upgrade {
exec 3>&1
status=$(pipx upgrade $1 2>&1 | while read -r line; do dbg "$line"; done 1>&3)
exec 3>&-
return $status
}
function apt_is_installed {
status=$(dpkg -l $1 2>&1 | tee >(while read -r line; do dbg "$line"; done))
dbg "Status: $status"
# Check if package is installed based on the output of dpkg -l
if echo "$status" | grep -q "^ii"; then
return 0
else
return 1
fi
}
function pipx_is_installed {
if ! check_command pipx; then
return 1
fi
status=$(pipx list 2>&1 | tee >(while read -r line; do dbg "$line"; done) | grep -q $1)
return $?
}
function check_command {
exec 3>&1
command -v $1 >/dev/null 2>&1
status=$?
if [ $status -eq 0 ]; then
echo "$1 exists" | while read -r line; do dbg "$line"; done 1>&3
else
echo "$1 does not exist" | while read -r line; do dbg "$line"; done 1>&3
fi
exec 3>&-
return $status
}
function run_command {
dbg "Running command: sudo $*"
exec 3>&1
output=$(sudo "$@" 2>&1)
status=$?
echo "$output" | while read -r line; do dbg "$line"; done 1>&3
exec 3>&-
dbg "Command exit status: $status"
return $status
}
function run_command_logged {
# run command and log output using inf function for each line
dbg "Running command: sudo $*"
exec 3>&1
sudo "$@" 2>&1 | while read -r line; do inf "$line"; done 1>&3
status=$?
exec 3>&-
dbg "Command exit status: $status"
return $status
}
function file_exists {
if [ -f $1 ]; then
return 0
else
return 1
fi
}
function dir_exists {
if [ -d $1 ]; then
return 0
else
return 1
fi
}
function add_crontab {
if check_crontab; then
if [ $OVERRIDE_CRONTAB -eq 1 ]; then
wrn "Crontab file already exists. Overriding existing crontab file."
else
err "Crontab file already exists. Please remove the existing crontab file or use the --override-crontab option."
return 1
fi
fi
echo "$BACKUP_CRON_SCHEDULE root PATH=\$PATH:/usr/bin:/usr/local/bin /root/.local/bin/borgmatic --verbosity -1 --syslog-verbosity 1" > /etc/cron.d/borgmatic
return $?
}
function check_crontab {
# check for file /etc/cron.d/borgmatic
if [ -f /etc/cron.d/borgmatic ]; then
return 0
else
return 1
fi
}
function is_remote_synology {
run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" "$SSH_USER@$SSH_HOST" test -f /etc/synoinfo.conf
return $?
}
# main script
# Available arguments:
# -a, --auto: Enable automatic, non-interactive mode
# -d, --debug: Enable debug mode
# -f, --first-backup: Run the first backup after setup
# -o, --override-crontab: Override the existing crontab file
# -c, --override-config: Override the existing borgmatic configuration file
# -r, --override-repository: Override the existing backup repository
# -s, --upgrade-required: Upgrade only required packages
# -u, --upgrade-all: Upgrade all installed packages
# -v, --version: Show script version
# -h, --help: Show help message
#
# -R, --repo: Set the backup repository path
# -E, --encryption: Set the encryption method
# -P, --passphrase: Set the backup passphrase
# -D, --dirs: Set the backup directories (separated by space as a string, for example: --dirs "/etc /var/log /home")
# -L, --label: Set the backup label prefix
# -S, --schedule: Set the cron schedule
#
# -H, --host: Set the backup server hostname or IP address
# -P, --port: Set the backup server SSH port
# -U, --user: Set the backup server SSH user
# -W, --password: Set the backup server SSH password
# -K, --key-name: Set the SSH key name
# -T, --key-type: Set the SSH key type
# -F, --key-file: Set the SSH key file path
#
# Example usage:
# ./borgmatic_setup.sh -R "Backups/MyServer" \
# -E "none" -P "example" \
# -D "/etc /var/log /home" \
# -L "BACKUP-" \
# -S "0 3 * * *" \
# -H "192.168.1.200" \
# -P "22" \
# -U "root" \
# -W "12345678" \
# -K "borgmatic" \
# -T "ed25519" \
# -F "/root/.ssh/borgmatic_ed25519"
#
# or with long options:
# ./borgmatic_setup.sh --repo "Backups/MyServer" \
# --encryption "none" --passphrase "example" \
# --dirs "/etc /var/log /home" \
# --label "BACKUP-" \
# --schedule "0 3 * * *" \
# --host "192.168.1.200" \
# --port "22" \
# --user "root" \
# --password "12345678"
# --key-name "borgmatic" \
# --key-type "ed25519" \
# --key-file "/root/.ssh/borgmatic_ed25519"
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-a|--auto)
AUTO=1
shift
;;
-d|--debug)
DEBUG=1
shift
;;
-v|--version)
echo "$SCRIPT_NAME v$VERSION"
exit 0
;;
-s|--upgrade-required)
DO_UPGRADE_REQUIRED=1
shift
;;
-u|--upgrade-all)
DO_UPGRADE_ALL=1
shift
;;
-f|--first-backup)
FIRST_BACKUP=1
shift
;;
-o|--override-crontab)
OVERRIDE_CRONTAB=1
shift
;;
-c|--override-config)
OVERRIDE_CONFIG=1
shift
;;
-k|--skip-config)
SKIP_CONFIG=1
shift
;;
-r|--override-repository)
OVERRIDE_REPOSITORY=1
shift
;;
-h|--help)
inf "Usage: borgmatic_setup.sh [options]"
inf ""
inf "Options will override the default settings set in the script."
inf "If no options are provided, the script will run in interactive mode."
inf "All options are optional."
inf ""
if [ "$EUID" -ne 0 ]; then
inf "\e[1m\e[31mImportant: The script must be run as root to work properly.\e[0m"
inf ""
fi
inf "Options:"
inf " -a, --auto: Enable automatic, non-interactive mode"
inf " -d, --debug: Enable debug mode"
inf " -f, --first-backup: Run the first backup after setup"
inf " -o, --override-crontab: Override the existing crontab file"
inf " -c, --override-config: Override the existing borgmatic configuration file"
inf " -k, --skip-config: Skip the borgmatic configuration"
inf " -r, --override-repository: Override the existing backup repository"
inf " -s, --upgrade-required: Upgrade only required packages"
inf " -u, --upgrade-all: Upgrade all installed packages"
inf " -v, --version: Show script version"
inf " -h, --help: Show help message"
inf ""
inf " -R, --repo: Set the backup repository path"
inf " -E, --encryption: Set the encryption method"
inf " -P, --passphrase: Set the backup passphrase (if set but empty, the script will ask for the passphrase)"
inf " -D, --dirs: Set the backup directories (separated by space as a string, for example: --dirs \"/etc /var/log /home\")"
inf " -L, --label: Set the backup label prefix"
inf " -S, --schedule: Set the cron schedule"
inf ""
inf " -H, --host: Set the backup server hostname or IP address"
inf " -P, --port: Set the backup server SSH port"
inf " -U, --user: Set the backup server SSH user"
inf " -W, --password: Set the backup server SSH password (if set but empty, the script will ask for the password)"
inf " -K, --key-name: Set the SSH key name"
inf " -T, --key-type: Set the SSH key type"
inf " -F, --key-file: Set the SSH key file path"
inf ""
inf "Example usage:"
inf "./borgmatic_setup.sh --dirs \"/etc /var/log /home\" --host \"192.168.1.200\" --encryption \"none\""
inf ""
inf "or for an encrypted backup:"
inf "./borgmatic_setup.sh --dirs \"/etc /var/log /home\" --host \"192.168.1.200\" --encryption \"repokey\" --passphrase \"example\""
exit 0
;;
-R|--repo)
BACKUP_REPO="$2"
shift
shift
;;
-E|--encryption)
BACKUP_ENCRYPTION="$2"
shift
shift
;;
-P|--passphrase)
if [ -z $BACKUP_PASSPHRASE ]; then
BACKUP_PASSPHRASE="$2"
shift
shift
else
BACKUP_PASSPHRASE=""
shift
fi
;;
-D|--dirs)
BACKUP_DIRS="$2"
shift
shift
;;
-L|--label)
BACKUP_LABEL_PREFIX="$2"
shift
shift
;;
-S|--schedule)
BACKUP_CRON_SCHEDULE="$2"
shift
shift
;;
-H|--host)
SSH_HOST="$2"
shift
shift
;;
-P|--port)
SSH_PORT="$2"
shift
shift
;;
-U|--user)
SSH_USER="$2"
shift
shift
;;
-W|--password)
if [ -z $SSH_PASSWORD ]; then
SSH_PASSWORD="$2"
shift
shift
else
SSH_PASSWORD=""
shift
fi
;;
-K|--key-name)
SSH_KEY_NAME="$2"
shift
shift
;;
-T|--key-type)
SSH_KEY_TYPE="$2"
shift
shift
;;
-F|--key-file)
SSH_KEY_FILE="$2"
shift
shift
;;
*)
shift
;;
esac
done
echo -e "\e[97m╭─────────────────────────────────────────────────────────────────────────────╮"
echo -e "│ │"
echo -e "│ \e[1m$SCRIPT_NAME\e[0m │"
echo -e "│ \e[1mv$VERSION\e[0m │"
echo -e "│ │"
echo -e "╰─────────────────────────────────────────────────────────────────────────────╯\e[0m"
inf "For support please contact $SCRIPT_AUTHOR"
if [ $DO_UPGRADE_ALL -eq 1 ]; then
DO_UPGRADE_REQUIRED=1
fi
if [ $DEBUG -eq 1 ]; then
dbg "Debug mode is enabled. This will print additional information."
fi
# check if script is running as root
if [ "$EUID" -ne 0 ]; then
err "Please run this script as root"
exit 1
fi
# check if script is running on a supported OS (Ubuntu or Debian)
if [ ! -f /etc/os-release ]; then
err "This script currently only supports Ubuntu and Debian"
exit 1
fi
wrn "This script will install \e[1mborgbackup\e[0m, \e[1mpipx\e[0m, python3-venv"
wrn "and \e[1msshpass\e[0m from the official repositories and \e[1mborgmatic\e[0m"
wrn "from the official PyPI repository."
inf ""
inf "The following settings will be used for the backup setup:"
inf "Backup repository: $BACKUP_REPO"
inf "Backup encryption: $BACKUP_ENCRYPTION"
inf "Backup directories: $BACKUP_DIRS"
inf "Backup cron schedule: $BACKUP_CRON_SCHEDULE"
inf "Backup server host: $SSH_USER@$SSH_HOST:$SSH_PORT"
inf ""
if [ $DO_UPGRADE_ALL -eq 1 ]; then
wrn "All installed packages will be upgraded!"
fi
if [ $OVERRIDE_CRONTAB -eq 1 ]; then
wrn "Existing cron job at /etc/cron.d/borgmatic will be overridden!"
fi
if [ $OVERRIDE_CONFIG -eq 1 ]; then
wrn "Existing borgmatic configuration file at $BORGMATIC_CONFIG_FILE will be overridden!"
fi
# only ask for confirmation in interactive mode
if [ $AUTO -eq 0 ] && ! wrnp "Do you want to continue? [y/N]"; then
inf "Aborted."
exit 1
fi
if ! check_command apt-get; then
err "apt-get is not installed. This script currently only supports Ubuntu and Debian."
exit 1
fi
if ! check_command dpkg; then
err "dpkg is not installed. This script only currently supports Ubuntu and Debian."
exit 1
fi
if ! inf_follow "Updating package lists..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_update; then
exit 1
fi
if ! check_command sshpass; then
if ! inf_follow "Installing sshpass..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_install sshpass; then
err "Installation of sshpass failed!"
exit 1
fi
else
if ! inf_follow "Upgrading sshpass..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade sshpass; then
err "Upgrade of sshpass failed!"
exit 1
fi
fi
if ! inf_follow "Checking if python3-venv is installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" apt_is_installed python3-venv; then
if ! inf_follow "Installing python3-venv..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_install python3-venv; then
err "Installation of python3-venv failed!"
exit 1
fi
fi
if [ $DO_UPGRADE_ALL -eq 1 ]; then
if [ $AUTO -eq 1 ] || wrnp "Do you want to upgrade all installed packages? [y/N]"; then
if ! inf_follow "Upgrading packages..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade; then
exit 1
fi
fi
fi
if [ $DO_UPGRADE_REQUIRED -eq 1 ]; then
if [ $AUTO -eq 1 ] || wrnp "Do you want to upgrade only required packages? [y/N]"; then
inf "Upgrading required packages..."
if ! inf_follow "Upgrading borgbackup..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade_selected borgbackup; then
err "Upgrade of borgbackup failed!"
exit 1
fi
if ! inf_follow "Upgrading pipx..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade_selected pipx; then
err "Upgrade of pipx failed!"
exit 1
fi
if ! inf_follow "Upgrading borgmatic..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade_selected borgmatic; then
err "Upgrade of borgmatic failed!"
exit 1
fi
if ! inf_follow "Upgrading python3-venv..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade_selected python3-venv; then
err "Upgrade of python3-venv failed!"
exit 1
fi
if ! inf_follow "Upgrading sshpass..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_upgrade_selected sshpass; then
err "Upgrade of sshpass failed!"
exit 1
fi
fi
fi
if ! inf_follow "Checking if borgbackup is installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" apt_is_installed borgbackup; then
if ! inf_follow "Installing borgbackup..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_install borgbackup; then
err "Installation of borgbackup failed!"
exit 1
fi
if ! inf_follow "Validating ..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" check_command borg; then
err "Installation of borgbackup failed!"
exit 1
fi
fi
if ! inf_follow "Checking if pipx is installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" apt_is_installed pipx; then
if ! inf_follow "Installing pipx..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" apt_install pipx; then
err "Installation of pipx failed!"
exit 1
fi
fi
if ! inf_follow "Checking if borgmatic is installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" pipx_is_installed borgmatic; then
if ! inf_follow "Installing borgmatic..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" pipx_install borgmatic; then
err "Installation of borgmatic failed!"
exit 1
fi
else
if [ $DO_UPGRADE_REQUIRED -eq 1 ]; then
if [ $AUTO -eq 1 ] || wrnp "Do you want to upgrade borgmatic? [y/N]"; then
if ! inf_follow "Upgrading borgmatic..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" pipx_upgrade borgmatic; then
err "Upgrade of borgmatic failed!"
exit 1
fi
fi
fi
fi
if ! inf_follow "Checking for ~/.ssh directory..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" dir_exists ~/.ssh; then
if ! inf_follow "Creating ~/.ssh directory..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" mkdir -p ~/.ssh; then
err "Failed to create ~/.ssh directory."
err "Please make sure you have the required permissions."
exit 1
fi
fi
if ! inf_follow "Checking for default ssh key at $SSH_KEY_FILE..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" file_exists $SSH_KEY_FILE; then
inf "Generating a new ssh key pair..."
ssh-keygen -t $SSH_KEY_TYPE -C "borgmatic_backup_$(hostname)" -f $SSH_KEY_FILE -N "" 2>&1 | while read -r line; do dbg "$line"; done
if [ $? -eq 0 ]; then
inf "Successfully generated a new ssh key pair."
else
err "Failed to generate a new ssh key pair."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
# check first if ssh key is already present on the remote end
if ! inf_follow "Checking if ssh key is already present on $SSH_HOST..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" run_command ssh -oStrictHostKeyChecking=no -oBatchMode=yes -i "$SSH_KEY_FILE" -p "$SSH_PORT" -l "$SSH_USER" "$SSH_HOST" exit; then
wrn "Please enter the password for the ssh key to copy it to the backup server."
wrn "This is required to enable passwordless ssh login for backups."
if ! inf_follow "Copying ssh key to $SSH_HOST..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command ssh-copy-id -oStrictHostKeyChecking=no -oBatchMode=no -i "$SSH_KEY_FILE.pub" -p "$SSH_PORT" "$SSH_USER@$SSH_HOST"; then
err "Failed to copy ssh key to $SSH_HOST."
err "Please validate your ssh password and and host settings and try again."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
else
if ! inf_follow "Checking if ssh key is working..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" exit; then
err "Failed to connect to $SSH_HOST using the ssh key."
err "Please validate you have the correct ssh key and host settings."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
fi
if ! inf_follow "Checking if remote end has borg installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" borg --version; then
if inf_follow "Checking if remote end is a Synology NAS..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" is_remote_synology; then
IS_REMOTE_SYNOLGY=1
fi
if [ $IS_REMOTE_SYNOLGY -eq 1 ]; then
wrn "The remote end appears to be a Synology NAS."
wrn "Please make sure you have installed borg on the remote end."
wrn "To install borg on a Synology NAS you can use the Synology Package Center:"
wrn "- Open the Package Center"
wrn "- Go to Settings > Package Sources"
wrn "- Add a package source named 'Community' with the Location http://packages.synocommunity.com"
wrn "- Go to the Community section and search for 'Borg'"
wrn "- Install the 'Borg' package"
wrn ""
wrn "You also need to enable user homes in the Synology Control Panel:"
wrn "- Open the Control Panel"
wrn "- Go to User & Group > Advanced"
wrn "- At the bottom, check 'Enable user home service'"
wrn "- Apply the changes"
wrn ""
wrn "PLEASE DO NOT CONTINUE UNTIL YOU HAVE INSTALLED BORG ON THE REMOTE END."
wrn ""
wrnw "Press any key to continue..."
if ! inf_follow "Checking if remote end has borg installed..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" borg --version; then
if inf_follow "Checking if borg was installed at /usr/local/bin..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" test -f /usr/local/bin/borg; then
if inf_follow "Creating symlink to /bin/borg..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" ln -s /usr/local/bin/borg /bin/borg; then
inf "Successfully created symlink to /bin/borg."
else
err "Failed to create symlink to /bin/borg."
err "Please login to the remote end via ssh at $SSH_USER@$SSH_HOST and create the symlink manually."
err "The required command is: sudo ln -s /usr/local/bin/borg /bin/borg"
err "Please to not continue until you have created the symlink."
err ""
errw "Press any key to continue..."
fi
else
err "Borg could not be found on the remote end at /usr/local/bin (which is the default installation path for Synology NAS)."
err "Please make sure you have installed borg on the remote end."
exit 1
fi
fi
else
if [ $AUTO -eq 1 ] || wrnp "The remote end does not have borg installed. Do you want to install it now? [y/N]"; then
if ! inf_follow "Updating package repositories on remote end" "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" apt-get update; then
err "Failed to update package repositories on remote end."
err "Please make sure you have the required access rights."
exit 1
fi
if ! inf_follow "Installing borg on remote end..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command ssh -i "$SSH_KEY_FILE" -p "$SSH_PORT" -oStrictHostKeyChecking=no -oBatchMode=yes -l "$SSH_USER" "$SSH_HOST" apt-get install -y borgbackup; then
err "Failed to install borg on remote end."
err "Please make sure you have the required access rights"
exit 1
fi
else
err "Please make sure borg is installed on the remote end."
err "This is required in order to do backups using borgmatic."
exit 1
fi
fi
fi
inf "Setting up borgmatic configuration..."
# check if directory path exists
if ! inf_follow "Checking for borgmatic configuration directory..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" dir_exists $(dirname $BORGMATIC_CONFIG_FILE); then
if ! inf_follow "Creating borgmatic configuration directory..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" mkdir -p $(dirname $BORGMATIC_CONFIG_FILE); then
err "Failed to create borgmatic configuration directory."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
if [ "${BACKUP_REPO:0:1}" == "/" ]; then
wrn "Your backup repository path starts with a '/', which is not recommended."
wrn "It will be removed automatically, but please make sure you have set the correct"
wrn "path. Leading slashes will cause the config validation to fail."
BACKUP_REPO=${BACKUP_REPO:1}
fi
# check if borgmatic configuration file already exists and abort if $OVERRIDE_CONFIG is not set
if [ -f $BORGMATIC_CONFIG_FILE ] && [ $OVERRIDE_CONFIG -ne 1 ]; then
if [ $SKIP_CONFIG -eq 1 ]; then
wrn "Skipping borgmatic configuration setup."
wrn "Please make sure you have set up the configuration file manually."
else
err "A borgmatic configuration file already exists at $BORGMATIC_CONFIG_FILE."
err "Please remove the existing configuration file or use the --override-config option."
exit 1
fi
elif [ -f $BORGMATIC_CONFIG_FILE ] && [ $OVERRIDE_CONFIG -eq 1 ]; then
wrn "Existing borgmatic configuration file will be overridden!"
fi
if [ $SKIP_CONFIG -eq 0 ]; then
cat > $BORGMATIC_CONFIG_FILE <<EOF
ssh_command: ssh -i $SSH_KEY_FILE -p $SSH_PORT
source_directories:
$(echo $BACKUP_DIRS | tr ' ' '\n' | sed -e 's/^/- /')
repositories:
- path: ssh://$SSH_USER@$SSH_HOST:$SSH_PORT/$BACKUP_REPO
label: $BACKUP_LABEL_PREFIX$(hostname | tr '[:lower:]' '[:upper:]')
keep_daily: 7
keep_weekly: 4
keep_monthly: 12
keep_yearly: 1
checks:
- name: repository
- name: archives
frequency: 4 weeks
EOF
if [ $? -eq 0 ]; then
inf "Successfully created borgmatic configuration file."
else
err "Failed to create borgmatic configuration file."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
if ! inf_follow "Validating borgmatic configuration..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command /root/.local/pipx/venvs/borgmatic/bin/borgmatic config validate; then
err "Validation of borgmatic configuration failed."
err "Please check the configuration file at $BORGMATIC_CONFIG_FILE."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
# check for existing borg repository and abort if $OVERRIDE_REPOSITORY is not set
if inf_follow "Checking for existing borgmatic repository..." "\e[1;32mYes\e[0m" "\e[1;31mNo\e[0m" run_command /root/.local/pipx/venvs/borgmatic/bin/borgmatic info; then
if [ $OVERRIDE_REPOSITORY -ne 1 ]; then
if [ $AUTO -eq 0 ] && ! wrnp "A borgmatic repository already exists. Do you want to override it? [y/N]"; then
err "A borgmatic repository already exists."
err "Please remove the existing repository or use the --override-repository option."
exit 1
elif [ $AUTO -eq 1 ]; then
err "A borgmatic repository already exists."
err "Please remove the existing repository or use the --override-repository option."
exit 1
fi
else
wrn "Existing borgmatic repository will be overridden!"
fi
else
inf "No existing borgmatic repository found."
fi
# ask for backup passphrase if none is set and encryption is enabled
if [ -z "$BACKUP_PASSPHRASE" ] && [ "$BACKUP_ENCRYPTION" != "none" ]; then
wrn "Please enter the passphrase for the backup encryption."
wrn "This is required to encrypt your backups."
read -r -s -p "Passphrase: " BACKUP_PASSPHRASE
echo ""
fi
if [ "$BACKUP_ENCRYPTION" == "none" ]; then
if ! inf_follow "Setting up borgmatic repository without encryption..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command /root/.local/pipx/venvs/borgmatic/bin/borgmatic init --make-parent-dirs --encryption=none; then
err "Failed to set up borgmatic repository without encryption."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
else
if ! inf_follow "Setting up borgmatic repository with encryption..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command BORG_PASSPHRASE="$BACKUP_PASSPHRASE" /root/.local/pipx/venvs/borgmatic/bin/borgmatic init --make-parent-dirs --encryption="$BACKUP_ENCRYPTION"; then
err "Failed to set up borgmatic repository with encryption."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
if ! inf_follow "Adding borgmatic cron job..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" add_crontab; then
err "Failed to add borgmatic cron job."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
else
if ! inf_follow "Validating borgmatic cron job..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" check_crontab; then
err "Validation of borgmatic cron job failed."
err "Please check if the file exists using 'cat /etc/cron.d/borgmatic'."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
fi
fi
if [ $FIRST_BACKUP -eq 1 ]; then
if [ $AUTO -eq 1 ] || infp "Do you want to run the first backup now? [Y/n]"; then
if ! inf_follow "Running first backup (this may take a while!)..." "\e[1;32mOK\e[0m" "\e[1;31mFAILED\e[0m" run_command_logged /root/.local/pipx/venvs/borgmatic/bin/borgmatic create --verbosity 1 --list --stats; then
err "Failed to run first backup."
err "If the error persists, please contact the support at $SCRIPT_SUPPORT."
exit 1
else
inf "Your first backup has been created successfully!"
fi
else
inf "Skipping first backup."
inf "Setup completed."
exit 0
fi
fi
inf "Setup completed."
exit 0