From a8bce140307bf05a6714c4351ce74cd96acc742f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rasmus=20Vester=20Th=C3=B8gersen?= Date: Thu, 25 Sep 2025 22:44:28 +0200 Subject: [PATCH 1/4] Add .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env From 50f4c2e14ddb207dbb803337a280d77a89d0c561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rasmus=20Vester=20Th=C3=B8gersen?= Date: Thu, 25 Sep 2025 22:44:48 +0200 Subject: [PATCH 2/4] Add initial version of backup script --- backup.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 backup.sh diff --git a/backup.sh b/backup.sh new file mode 100644 index 0000000..a57a337 --- /dev/null +++ b/backup.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +#This script will automatically make an encrypted backup to a restic repository as specified with --source +# +helpFunction() +{ + echo "" + echo "Usage: $0 -i INPUT -c CONFIG_DIR -l LOG_DIR" + echo -e "\t-i Input folder that should be backed up." + echo -e "\t-c Location of config directory containing repository, password and uuid files." + echo -e "\t-l Location of where the log should be outputted to." + echo -e "Example:" + echo -e "If you pass -i ~/MyServices/SeRvIce1, then the directory you pass as -c must contain files service1_repository, service1_password and service1_uuid (note lower case)" + exit 1 # Exit script after printing help +} + +while getopts "i:c:l:" opt +do + case "$opt" in + i ) INPUT="$OPTARG" ;; + c ) CONFIG_DIR="$OPTARG" ;; + l ) LOG_DIR="$OPTARG" ;; + ? ) helpFunction ;; # Print helpFunction in case parameter is non-existent + esac +done + +# Print helpFunction in case parameters are empty +if [ -z "$INPUT" ] || [ -z "$CONFIG_DIR" ] || [ -z "$LOG_DIR" ] +then + echo "Some or all of the parameters are empty"; + helpFunction +fi + +# Begin script in case all parameters are correct + +# Set environment variables +set -a && source .env && set +a + +SERVICE=${INPUT##*/} +SERVICE=${SERVICE,,} +DATE=$(date +%Y-%m-%d_%H%M%S) +LOG_FILE="${LOG_DIR}/${SERVICE}_${DATE}.log" + + + +REPOSITORY_FILE="${CONFIG_DIR}/${SERVICE}_repository" +PASSWORD_FILE="${CONFIG_DIR}/${SERVICE}_password" +UUID_FILE="${CONFIG_DIR}/${SERVICE}_uuid" + +echo -e "--- START OF BACKUP FOR ${SERVICE^^} - ${DATE} ---\n\n" > $LOG_FILE +restic backup $INPUT --verbose --repository-file $REPOSITORY_FILE --password-file $PASSWORD_FILE >> $LOG_FILE + +echo -e "\n\n Current snapshots:\n\n" >> $LOG_FILE +restic snapshots --verbose --repository-file $REPOSITORY_FILE --password-file $PASSWORD_FILE >> $LOG_FILE + +echo -e "\n\n Health check:\n\n" >> $LOG_FILE +restic check --verbose --repository-file $REPOSITORY_FILE --password-file $PASSWORD_FILE >> $LOG_FILE + +echo -e "\n\n Move to external storage:\n\n" >> $LOG_FILE +rsync -rahPv --delete-after -e "ssh -p ${EXTERNAL_STORAGE_PORT}" "$(<$REPOSITORY_FILE)" $EXTERNAL_STORAGE_USER@$EXTERNAL_STORAGE_URL:$EXTERNAL_STORAGE_ROOT_DIR/"$(<$UUID_FILE)" >> $LOG_FILE From e659f919c442fba7162bc84b4ceae90e7426447d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rasmus=20Vester=20Th=C3=B8gersen?= Date: Fri, 26 Sep 2025 22:19:25 +0200 Subject: [PATCH 3/4] Add initial version of repo setup script --- setup_repo.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 setup_repo.sh diff --git a/setup_repo.sh b/setup_repo.sh new file mode 100644 index 0000000..476549a --- /dev/null +++ b/setup_repo.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# +#This script will automatically make an encrypted backup to a restic repository as specified with --source +# + +helpFunction() +{ + echo "" + echo "Usage: $0 -i INPUT -c CONFIG_DIR -l LOG_DIR" + echo -e "\t-i Input folder to create a repository for." + echo -e "\t-c Location of config directory where the repository, password and uuid files are stored." + exit 1 # Exit script after printing help +} + +while getopts "i:c:l:" opt +do + case "$opt" in + i ) INPUT="$OPTARG" ;; + c ) CONFIG_DIR="$OPTARG" ;; + ? ) helpFunction ;; # Print helpFunction in case parameter is non-existent + esac +done + +SERVICE=${INPUT##*/} +SERVICE=${SERVICE,,} + +PASSWORD=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 50) +UUID=$(uuidgen) + +echo $PASSWORD > $CONFIG_DIR/${SERVICE}_password +echo $UUID > $CONFIG_DIR/${SERVICE}_uuid + +echo "Created required backup directories for $INPUT" +echo "Password: $PASSWORD" +echo "UUID: $UUID" +echo "Make sure to note this down in your password manager to be able to decrypt the repositories, and to map the repositories on the external storage" + + From 8853bc812970e763dc663d4f129b7adc89efcf17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rasmus=20Vester=20Th=C3=B8gersen?= Date: Wed, 1 Oct 2025 20:18:28 +0200 Subject: [PATCH 4/4] Rename file and add bunch of things --- init-repo.sh | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ setup_repo.sh | 38 ----------------- 2 files changed, 114 insertions(+), 38 deletions(-) create mode 100755 init-repo.sh delete mode 100644 setup_repo.sh diff --git a/init-repo.sh b/init-repo.sh new file mode 100755 index 0000000..fef9a07 --- /dev/null +++ b/init-repo.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +#This script will initialise the required files and directories for automatic backup of Docker data. +# + +helpFunction() +{ + echo "" + echo "Usage: $0 -i INPUT -c CONFIG_DIR -l LOG_DIR" + echo -e "\t-i Input folder to create a repository for." + echo -e "\t-c Location of config directory where the repository, password and uuid files are stored." + echo -e "\t-n Name of the Docker container. Required to stop the container and restart it before backing up." + exit 1 # Exit script after printing help +} + +while getopts "i:c:n:f" opt +do + case "$opt" in + i ) INPUT="$OPTARG" ;; + c ) CONFIG_DIR="$OPTARG" ;; + n ) CONTAINER_NAME="$OPTARG" ;; + f ) FORCE=true ;; + ? ) helpFunction ;; # Print helpFunction in case parameter is non-existent + esac +done + +# Verify that required parameters are present + +set -a && source .env && set +a + +REQUIRED_PARAMS=( + INPUT + CONFIG_DIR + CONTAINER_NAME + EXTERNAL_STORAGE_URL + EXTERNAL_STORAGE_USER + EXTERNAL_STORAGE_PORT + EXTERNAL_STORAGE_ROOT_DIR + INTERNAL_STORAGE_ROOT_DIR +) + +for variable in "${REQUIRED_PARAMS[@]}" ; do + if [ -z "${!variable+x}" ]; then + echo "$variable is not set. Make sure your .env file is complete, and you have passed in all required flags."; + exit; + fi +done + +echo $FORCE + +# Parse the input to create the SERVICE variable (lower case) +SERVICE=${INPUT##*/} +SERVICE=${SERVICE,,} + +# Set the location of the internal repo +INTERNAL_REPO_LOCATION=$INTERNAL_STORAGE_ROOT_DIR/$SERVICE + + +# Generate random password and UUID +PASSWORD=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 50) +UUID=$(uuidgen) + +# Set filenames +REPO_FILE_PATH="$CONFIG_DIR/${SERVICE}_repository" +PWD_FILE_PATH="$CONFIG_DIR/${SERVICE}_password" +UUID_FILE_PATH="$CONFIG_DIR/${SERVICE}_uuid" +CONTAINER_NAME_FILE_PATH="$CONFIG_DIR/${SERVICE}_container_name" + + +# Make the config directory if it does not already exist +if [ ! -d "$CONFIG_DIR" ]; then + mkdir $CONFIG_DIR +fi + +# Run the code only if the config files for the service does not already exist, or if force overwrite is specified +if [[ ! -f "$CONFIG_DIR/${SERVICE}_repository" ]] || [[ $FORCE == true ]]; then + # Prompt user if they are sure whether to force overwrite + if [[ $FORCE == true ]]; then + while true; do + read -p "The config for ${INPUT} already exists, but you specified to force overwrite. This will also delete what is already in the restic repository and recreate an empty repo. Are you sure? [y/n] " yn + case $yn in + [Yy]* ) break;; + [Nn]* ) echo "Exiting without overwriting..."; exit;; + * ) echo "Please anser yes or no." + esac + done + fi + + # Write the config files + echo $INTERNAL_REPO_LOCATION > $REPO_FILE_PATH + echo $PASSWORD > $PWD_FILE_PATH + echo $UUID > $UUID_FILE_PATH + echo $CONTAINER_NAME > $CONTAINER_NAME_FILE_PATH + + echo "Created required backup directories for $INPUT" + echo "Password: $PASSWORD" + echo "UUID: $UUID" + echo "Make sure to note this down in your password manager to be able to decrypt the repositories, and to map the repositories on the external storage" + + # Make the internal restic repository + if [ -d "$INTERNAL_REPO_LOCATION" ]; then + cp -r $INTERNAL_REPO_LOCATION ${INTERNAL_REPO_LOCATION}_old_$(date +%Y%m%d_%H%M%S) + rm -r $INTERNAL_REPO_LOCATION + fi + + restic init --repository-file $REPO_FILE_PATH -p $PWD_FILE_PATH + + + +else + echo "Repository config already exists for the service you specified. You can override this by passing the -f flag." + +fi + diff --git a/setup_repo.sh b/setup_repo.sh deleted file mode 100644 index 476549a..0000000 --- a/setup_repo.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# -#This script will automatically make an encrypted backup to a restic repository as specified with --source -# - -helpFunction() -{ - echo "" - echo "Usage: $0 -i INPUT -c CONFIG_DIR -l LOG_DIR" - echo -e "\t-i Input folder to create a repository for." - echo -e "\t-c Location of config directory where the repository, password and uuid files are stored." - exit 1 # Exit script after printing help -} - -while getopts "i:c:l:" opt -do - case "$opt" in - i ) INPUT="$OPTARG" ;; - c ) CONFIG_DIR="$OPTARG" ;; - ? ) helpFunction ;; # Print helpFunction in case parameter is non-existent - esac -done - -SERVICE=${INPUT##*/} -SERVICE=${SERVICE,,} - -PASSWORD=$(tr -dc 'A-Za-z0-9!?%=' < /dev/urandom | head -c 50) -UUID=$(uuidgen) - -echo $PASSWORD > $CONFIG_DIR/${SERVICE}_password -echo $UUID > $CONFIG_DIR/${SERVICE}_uuid - -echo "Created required backup directories for $INPUT" -echo "Password: $PASSWORD" -echo "UUID: $UUID" -echo "Make sure to note this down in your password manager to be able to decrypt the repositories, and to map the repositories on the external storage" - -