All checks were successful
Check scripts syntax / check-scripts-syntax (push) Successful in 22s
292 lines
9.5 KiB
Bash
292 lines
9.5 KiB
Bash
#!/bin/bash
|
|
|
|
# NAS Backup Script to Google Drive using rclone and 7zip
|
|
# For each folder on BACKUP_SOURCE, it gets the sha256 checksum of it, checks the checksum against the previous backup, and if it has changed, it creates a 7zip archive of the folder with encryption.
|
|
# It then uploads the archive to Google Drive using rclone.
|
|
|
|
# Install: curl -sSL https://git.ivanch.me/ivanch/server-scripts/raw/branch/main/nas-gdrive-backup.sh | bash -s -- --install
|
|
# Run manually: /usr/local/bin/nas-gdrive-backup.sh
|
|
|
|
# Configuration
|
|
BACKUP_SOURCE="/export/Backup"
|
|
META_DIR="/export/Backup/.gdrive"
|
|
TMP_DIR="/export/Backup/.gdrive/tmp"
|
|
ZIP_PASSWORD="password"
|
|
GDRIVE_REMOTE="gdrive"
|
|
GDRIVE_PATH="/NAS-Backups"
|
|
ARCHIVE_NAME="backup.7z"
|
|
LOG_FILE="/var/log/nas-gdrive-backup.log"
|
|
|
|
# Function for logging
|
|
log() {
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
clean_up() {
|
|
log "Cleaning up temporary files"
|
|
rm -rf "$TMP_DIR"
|
|
}
|
|
|
|
trap clean_up EXIT
|
|
|
|
create_7z() {
|
|
local folder="$1"
|
|
local archive_name="$2"
|
|
log "Creating 7zip archive of $folder"
|
|
7z a -p"$ZIP_PASSWORD" -mhe=on -mx=3 "$archive_name" "$folder"
|
|
if [ $? -ne 0 ]; then
|
|
log "ERROR: Failed to create 7zip archive of $folder"
|
|
fi
|
|
}
|
|
|
|
upload_to_gdrive() {
|
|
local archive_name="$1"
|
|
log "Uploading $archive_name to Google Drive"
|
|
|
|
# Should replace existing file if it exists
|
|
rclone copy "$archive_name" "$GDRIVE_REMOTE:$GDRIVE_PATH" \
|
|
--progress \
|
|
--check-first \
|
|
--transfers 1 \
|
|
--checkers 1 \
|
|
--retries 1 \
|
|
--low-level-retries 10
|
|
if [ $? -ne 0 ]; then
|
|
log "ERROR: Failed to upload $archive_name to Google Drive"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
# Check if 7z is installed
|
|
if ! which 7z > /dev/null; then
|
|
log "ERROR: 7z is not installed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if rclone is installed
|
|
if ! which rclone > /dev/null; then
|
|
log "ERROR: rclone is not installed"
|
|
exit 1
|
|
fi
|
|
|
|
# Create meta directory if it doesn't exist
|
|
if [ ! -d "$META_DIR" ]; then
|
|
log "Creating meta directory: $META_DIR"
|
|
mkdir -p "$META_DIR"
|
|
fi
|
|
|
|
# Fix permissions for the meta directory (777 recursively)
|
|
chmod -R 777 "$META_DIR"
|
|
|
|
# Loop through each folder in the backup source
|
|
for folder in "$BACKUP_SOURCE"/*; do
|
|
if [ -d "$folder" ]; then
|
|
log "Processing folder: $folder"
|
|
# Get the sha256 checksum of the folder
|
|
CHECKSUM=$(find "$folder" -type f -exec sha256sum {} + | sha256sum | awk '{print $1}')
|
|
META_FILE="$META_DIR/$(basename "$folder").sha256"
|
|
# Check if the checksum file exists
|
|
if [ -f "$META_FILE" ]; then
|
|
# Read the previous checksum from the file
|
|
PREV_CHECKSUM=$(cat "$META_FILE")
|
|
# Compare the checksums
|
|
if [ "$CHECKSUM" != "$PREV_CHECKSUM" ]; then
|
|
log "Changes detected in $folder - creating new archive"
|
|
|
|
create_7z "$folder" "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
upload_to_gdrive "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
|
|
# Update the checksum file
|
|
echo "$CHECKSUM" > "$META_FILE"
|
|
|
|
# Remove the temporary archive file
|
|
log "Removing temporary archive file"
|
|
rm "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
else
|
|
log "No changes detected in $folder"
|
|
fi
|
|
else
|
|
log "No previous checksum found for $folder - creating new archive"
|
|
|
|
create_7z "$folder" "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
upload_to_gdrive "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
|
|
# Create a checksum file for the folder
|
|
echo "$CHECKSUM" > "$META_FILE"
|
|
|
|
# Remove the temporary archive file
|
|
log "Removing temporary archive file"
|
|
rm "$TMP_DIR/$(basename "$folder")_$ARCHIVE_NAME"
|
|
fi
|
|
else
|
|
log "Skipping $folder, not a directory"
|
|
fi
|
|
log ""
|
|
done
|
|
|
|
# Fix permissions for the meta directory (777 recursively)
|
|
chmod -R 777 "$META_DIR"
|
|
|
|
log "Backup process completed successfully"
|
|
|
|
# Exit with success
|
|
exit 0
|
|
}
|
|
|
|
###########################
|
|
### Installation script ###
|
|
###########################
|
|
# Function to install a dependency if not already installed
|
|
install_dependency() {
|
|
local package="$1"
|
|
if ! dpkg -l | grep -q "$package"; then
|
|
install_log_info "Installing $package"
|
|
apt-get update && apt-get install -y "$package"
|
|
if [ $? -ne 0 ]; then
|
|
install_log_error "ERROR: Failed to install $package"
|
|
exit 1
|
|
fi
|
|
install_log_ok "$package installed successfully"
|
|
else
|
|
install_log_ok "$package is already installed"
|
|
fi
|
|
}
|
|
|
|
install_log_ok() {
|
|
echo -e "\e[32m[✓]\e[0m $1"
|
|
}
|
|
install_log_error() {
|
|
echo -e "\e[31m[✗]\e[0m $1"
|
|
}
|
|
install_log_info() {
|
|
echo -e "\e[34m[!]\e[0m $1"
|
|
}
|
|
install_log_separator() {
|
|
echo -e "\e[36m========================================\e[0m"
|
|
}
|
|
|
|
install_script() {
|
|
echo -e ""
|
|
install_log_separator
|
|
install_log_info "Starting installation of NAS to Google Drive backup script"
|
|
install_log_separator
|
|
echo -e ""
|
|
|
|
install_log_separator
|
|
# Check if running as root
|
|
install_log_info "Checking if the script is running as root"
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
install_log_error "ERROR: This script must be run as root"
|
|
exit 1
|
|
else
|
|
install_log_ok "Running as root"
|
|
fi
|
|
install_log_separator
|
|
|
|
# Check for dependencies
|
|
install_log_info "Checking for required dependencies"
|
|
install_dependency "rclone"
|
|
install_dependency "p7zip-full"
|
|
install_log_separator
|
|
|
|
# Check if crontab exists
|
|
install_log_info "Checking if crontab is installed"
|
|
if ! command -v crontab &>/dev/null; then
|
|
install_log_error "crontab is not installed"
|
|
exit 1
|
|
else
|
|
install_log_ok "crontab is installed"
|
|
fi
|
|
install_log_separator
|
|
|
|
install_log_info "Installing script to /usr/local/bin/nas-gdrive-backup.sh"
|
|
curl -sSL https://git.ivanch.me/ivanch/server-scripts/raw/branch/main/nas-gdrive-backup.sh -o /usr/local/bin/nas-gdrive-backup.sh
|
|
chmod +x /usr/local/bin/nas-gdrive-backup.sh
|
|
|
|
install_log_info "Setting up ZIP_PASSWORD in $0"
|
|
if [ -z "$ZIP_PASSWORD" ]; then
|
|
install_log_error "ERROR: ZIP_PASSWORD is not set"
|
|
exit 1
|
|
fi
|
|
read -p "Enter ZIP_PASSWORD: " ZIP_PASSWORD </dev/tty
|
|
if [ -z "$ZIP_PASSWORD" ]; then
|
|
install_log_error "ERROR: ZIP_PASSWORD cannot be empty"
|
|
exit 1
|
|
fi
|
|
# Update the ZIP_PASSWORD in the script
|
|
sed -i "s/^ZIP_PASSWORD=.*/ZIP_PASSWORD=\"$ZIP_PASSWORD\"/" /usr/local/bin/nas-gdrive-backup.sh
|
|
log "ZIP_PASSWORD updated in /usr/local/bin/nas-gdrive-backup.sh"
|
|
install_log_separator
|
|
|
|
# Check for existence of source directories
|
|
install_log_info "Checking if BACKUP_SOURCE, META_DIR, and TMP_DIR exists"
|
|
if ! [ -d "$BACKUP_SOURCE" ]; then
|
|
install_log_error "ERROR: BACKUP_SOURCE directory does not exist"
|
|
exit 1
|
|
else
|
|
install_log_ok "BACKUP_SOURCE directory exists: $BACKUP_SOURCE"
|
|
fi
|
|
if ! [ -d "$META_DIR" ]; then
|
|
install_log_info "Creating META_DIR: $META_DIR"
|
|
mkdir -p "$META_DIR"
|
|
fi
|
|
if ! [ -d "$TMP_DIR" ]; then
|
|
install_log_info "Creating TMP_DIR: $TMP_DIR"
|
|
mkdir -p "$TMP_DIR"
|
|
fi
|
|
install_log_info "Setting permissions for $META_DIR and $TMP_DIR to 777"
|
|
chmod -R 777 "$META_DIR" "$TMP_DIR"
|
|
install_log_ok "Directories checked and are ok"
|
|
|
|
# Check for existing .sha256 files, if there are any, prompt to remove them
|
|
install_log_info "Verifying existing .sha256 files in $META_DIR"
|
|
for file in "$META_DIR"/*; do
|
|
if [ -f "$file" -a -name "*.sha256" ]; then
|
|
install_log_info "Found .sha256 file: $file"
|
|
read -p "Do you want to remove this file? [y/N]: " choice </dev/tty
|
|
if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
|
|
install_log_info "Removing $file"
|
|
rm "$file"
|
|
else
|
|
install_log_info "Skipping $file"
|
|
fi
|
|
fi
|
|
done
|
|
install_log_ok "Existing .sha256 files checked"
|
|
|
|
install_log_separator
|
|
|
|
install_log_info "Setting up rclone configuration"
|
|
if ! rclone config show gdrive &>/dev/null; then
|
|
install_log_error "ERROR: rclone gdrive remote is not configured"
|
|
install_log_error "Please run 'rclone config' to set up your Google Drive remote"
|
|
exit 1
|
|
fi
|
|
install_log_ok "rclone gdrive remote is configured"
|
|
install_log_separator
|
|
|
|
install_log_info "Setting up cron job for backup script"
|
|
(crontab -l 2>/dev/null; echo "55 23 * * 1 $0 > /tmp/nas-gdrive-backup.log") | crontab -
|
|
install_log_ok "Cron job set up to run $0 every Monday at 23:55"
|
|
install_log_separator
|
|
|
|
echo -e ""
|
|
install_log_separator
|
|
install_log_ok "Installation completed successfully!"
|
|
install_log_separator
|
|
echo -e ""
|
|
echo -e "You can now run the script manually with: \e[32m/usr/local/bin/nas-gdrive-backup.sh\e[0m"
|
|
echo -e "Or it will run automatically according to the cron schedule."
|
|
|
|
# Exit with success
|
|
exit 0
|
|
}
|
|
|
|
# Check for install flag
|
|
if [[ "$1" == "--install" ]]; then
|
|
install_script
|
|
exit 0
|
|
fi
|
|
|
|
main "$@"
|
|
exit 0 |