Skip to content

Instantly share code, notes, and snippets.

@R-omk
Last active December 20, 2024 10:02
Show Gist options
  • Save R-omk/8a69c63cb0dc744334353694178a3ad1 to your computer and use it in GitHub Desktop.
Save R-omk/8a69c63cb0dc744334353694178a3ad1 to your computer and use it in GitHub Desktop.
script to backup via restic plus rclone
#!/bin/bash
set -e
RESTIC_OPTIONS=()
command -v rclone >/dev/null 2>&1 || {
echo "rclone is not installed. Please install it and try again." >&2
exit 1
}
command -v restic >/dev/null 2>&1 || {
echo "restic is not installed. Please install it and try again." >&2
exit 1
}
# Function to create a template configuration file
confinit() {
if [ -f "$1" ]; then
echo "Configuration file already exists: $1"
return 1
fi
CONFIG_FILE=$1
# Generate a secure password for RESTIC
RESTIC_PASSWORD=$(head -c 24 /dev/urandom | base64)
cat <<EOL >"$CONFIG_FILE"
# Template configuration file for restic-rclone
RCLONENAME='your_rclone_connection' # Specify the name of the rclone connection that restic will use to access the repository; use 'rclone config' to start interactive config management
REPONAME='your_repo_name' # Specify the desired repository name, a directory with this name will be used
RESTIC_PASSWORD='$RESTIC_PASSWORD' # Warning: If you lose the RESTIC_PASSWORD, you will not be able to restore your backups.
EXCLUDE_DIRS='Downloads,.cache,tmp,ignore folder with space' # Add directories to exclude from backup to save space
BACKUP_DIR='$HOME'
EOL
echo "Template configuration file created: $CONFIG_FILE"
echo "Use the script as follows:"
echo "$0 --config $CONFIG_FILE {check|init|backup|prune|mount}"
echo "Important: Please make sure to store the RESTIC_PASSWORD securely, as it will be used to encrypt your backups."
echo "Warning: If you lose the RESTIC_PASSWORD, you will not be able to restore your backups."
}
load_config() {
if [ ! -f "$1" ]; then
echo "Configuration file not found: $1"
return 1
fi
source "$1"
# Check that all required variables are loaded successfully
REQUIRED_VARS=(RESTIC_PASSWORD RCLONENAME REPONAME EXCLUDE_DIRS BACKUP_DIR)
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var}" ]; then
echo "Error: variable '$var' not found in configuration file '$1'"
return 1
fi
done
RESTIC_OPTIONS=(--verbose --pack-size=4 --compression=max -o rclone.args="serve restic --stdio --b2-hard-delete" -r rclone:$RCLONENAME:$REPONAME)
}
# Function to check rclone connection
check() {
load_config $1 || exit 1
rclone lsd $RCLONENAME: --dry-run >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Connection successful."
else
echo "Connection error."
exit 1
fi
SNAPSHOTS_OUTPUT=$(RESTIC_PASSWORD=$RESTIC_PASSWORD restic "${RESTIC_OPTIONS[@]}" snapshots 2>&1)
if [ $? -eq 0 ]; then
echo "Repository exists. Here are the snapshots:"
echo "$SNAPSHOTS_OUTPUT"
echo ""
echo "Size:"
rclone size $RCLONENAME:$REPONAME
else
echo "No repository found at the specified location."
echo "Please initialize the repository using the 'init' command."
fi
}
# Function to initialize the restic repository
init_repo() {
load_config $1 || exit 1
RESTIC_PASSWORD=$RESTIC_PASSWORD restic "${RESTIC_OPTIONS[@]}" init --repository-version=latest
}
# Function to perform backup
backup() {
load_config $1 || exit 1
# Create a list of exclusions
EXCLUDES=()
IFS=',' read -ra ADDR <<<"$EXCLUDE_DIRS"
for dir in "${ADDR[@]}"; do
EXCLUDES+=("--exclude=$BACKUP_DIR/$dir")
done
# Perform backup
RCLONE_TRANSFERS=8 RCLONE_CHECKERS=16 RESTIC_PASSWORD=$RESTIC_PASSWORD restic "${RESTIC_OPTIONS[@]}" backup --one-file-system --tag default "${EXCLUDES[@]}" "$BACKUP_DIR"
}
# Function to remove unnecessary snapshots from the repository
# This function is used to clean up the repository and free up space
# It removes snapshots that are no longer needed based on the retention policy
prune() {
load_config $1 || exit 1
# Perform cleanup
RCLONE_TRANSFERS=24 RCLONE_CHECKERS=64 RESTIC_PASSWORD=$RESTIC_PASSWORD restic "${RESTIC_OPTIONS[@]}" forget --prune --tag=default --keep-last 100 --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 75
}
# Function to mount the restic repository
mount_repo() {
load_config $1 || exit 1
if [ -z "$2" ]; then
echo "You must specify a directory to mount."
return 1
fi
# Perform mounting
RESTIC_PASSWORD=$RESTIC_PASSWORD restic "${RESTIC_OPTIONS[@]}" mount "$2"
}
if [ "$#" -eq 0 ]; then
echo "Usage: $0 [--config <config_file>] {confinit|check|init|backup|prune|mount}"
echo "Note: If --config option is not specified, the configuration file will be created in $HOME/.restic_rclone_backup_config"
exit 1
fi
# Handle --config option
if [[ "$1" == "--config" && -n "$2" ]]; then
CONFIG_FILE="$2"
shift 2
else
CONFIG_FILE="$HOME/.restic_rclone_backup_config"
fi
case "$1" in
confinit)
confinit "$CONFIG_FILE"
;;
check)
check "$CONFIG_FILE"
;;
init)
init_repo "$CONFIG_FILE"
;;
backup)
backup "$CONFIG_FILE"
;;
prune)
prune "$CONFIG_FILE"
;;
mount)
mount_repo "$CONFIG_FILE" "$2"
;;
*)
echo "Invalid command: $1"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment