#!/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/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