Skip to content

Instantly share code, notes, and snippets.

@frg
Last active August 9, 2023 11:50
Show Gist options
  • Save frg/843c5df207c3fbe2c7535c6fdc000bfb to your computer and use it in GitHub Desktop.
Save frg/843c5df207c3fbe2c7535c6fdc000bfb to your computer and use it in GitHub Desktop.

Automated Backup to SMB

This script provides an automated solution for backing up data to an SMB share, with features like pruning old backups, bandwidth limiting, and notifications via Discord.

Features:

  • Backup to SMB: Backs up specified directory to an SMB share.
  • Pruning: Automatically deletes backups older than a specified number of days.
  • Bandwidth Limiting: Limits the bandwidth used during backup.
  • Notifications: Sends notifications to Discord on start, completion, and on errors.
  • Scheduled Backups: Allows scheduling of the backup operation using crontab.
  • Logging: Logs backup operations and errors to /var/log/backup_to_smb.log.

Parameters:

  • -s, --source: Source directory for backup (required).
  • -i, --ip: SMB server IP (required).
  • -n, --share: SMB share name (required).
  • -u, --username: SMB username (required).
  • -p, --password: SMB password (required).
  • -w, --webhook: Discord webhook URL (required).
  • -r, --prune: Days after which to prune old backups (default is 30).
  • -c, --cron: Crontab schedule expression (default is '0 3 * * *' for 3 AM daily).
  • -b, --bwlimit: Bandwidth limit in KB/s (default is 12500 for 100 Mbit/s).

Installation:

To install and set up the script directly from the gist, use the following command:

curl -s -O backup_to_smb.sh [GIST_RAW_URL] && \
chmod +x backup_to_smb.sh && \
./backup_to_smb.sh \
    --source <SOURCE_DIR> \
    --ip <SMB_IP> \
    --share <SHARE_NAME> \
    --username <SMB_USERNAME> \
    --password <SMB_PASSWORD> \
    --webhook <DISCORD_WEBHOOK_URL> \
    [--prune <DAYS_TO_PRUNE>] \
    [--cron <CRON_SCHEDULE>] \
    [--bwlimit <BANDWIDTH_LIMIT>]
#!/bin/bash
# Function to display help message
display_help() {
echo "Usage: $0 [OPTION]..."
echo "Install and setup automated backup to SMB."
echo
echo " -s, --source Source directory for backup (required)"
echo " -i, --ip SMB server IP (required)"
echo " -n, --share SMB share name (required)"
echo " -u, --username SMB username (required)"
echo " -p, --password SMB password (required)"
echo " -w, --webhook Discord webhook URL (required)"
echo " -r, --prune Days after which to prune old backups (default is 30)"
echo " -c, --cron Crontab schedule expression (default is '0 3 * * *' for 3 AM daily)"
echo " -b, --bwlimit Bandwidth limit in KB/s (default is 12500 for 100 Mbit/s)"
echo " -h, --help Display this help and exit"
exit 1
}
# Default values
PRUNE_DAYS=30
CRON_SCHEDULE="0 3 * * *"
BWLIMIT=12500 # Default bandwidth limit is 100 Mbit/s or 12500 KB/s
# Parse named arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
-s|--source) SOURCE_DIR="$2"; shift ;;
-i|--ip) SMB_IP="$2"; shift ;;
-n|--share) SHARE_NAME="$2"; shift ;;
-u|--username) SMB_USERNAME="$2"; shift ;;
-p|--password) SMB_PASSWORD="$2"; shift ;;
-w|--webhook) DISCORD_WEBHOOK="$2"; shift ;;
-r|--prune) PRUNE_DAYS="$2"; shift ;;
-c|--cron) CRON_SCHEDULE="$2"; shift ;;
-b|--bwlimit) BWLIMIT="$2"; shift ;;
-h|--help) display_help ;;
*) echo "Unknown parameter passed: $1"; exit 1 ;;
esac
shift
done
# Check for required parameters
if [ -z "$SOURCE_DIR" ] || [ -z "$SMB_IP" ] || [ -z "$SHARE_NAME" ] || [ -z "$SMB_USERNAME" ] || [ -z "$SMB_PASSWORD" ] || [ -z "$DISCORD_WEBHOOK" ]; then
display_help
fi
# Install SMB Client
sudo apt-get update
sudo apt-get install -y cifs-utils
# Create SMB credentials file in a secure location
CREDENTIALS_FILE="/etc/smb_credentials"
echo "username=${SMB_USERNAME}" | sudo tee $CREDENTIALS_FILE > /dev/null
echo "password=${SMB_PASSWORD}" | sudo tee -a $CREDENTIALS_FILE > /dev/null
# Secure the file
sudo chmod 600 $CREDENTIALS_FILE
LOG_FILE="/var/log/backup_to_smb.log"
# Create the backup script
cat << EOL > ~/backup_to_smb.sh
#!/bin/bash
TARGET_DIR="/mnt/smb_share"
LOG_FILE="/var/log/backup_to_smb.log"
RUN_ID=\$(uuidgen)
# Ensure log file exists
touch \$LOG_FILE
# Check if the share is already mounted
if ! mountpoint -q \$TARGET_DIR; then
# Mount the SMB share
mkdir -p \$TARGET_DIR
sudo mount -t cifs //${SMB_IP}/${SHARE_NAME} \$TARGET_DIR -o credentials=${CREDENTIALS_FILE}
if [ \$? -ne 0 ]; then
echo "\$(date -u +'%Y-%m-%dT%H:%M:%SZ') - Run ID: \$RUN_ID - Failed to mount SMB share" >> \$LOG_FILE
curl -X POST -H "Content-Type: application/json" -d "{\"content\": \"❌ Failed to mount SMB share.\"}" ${DISCORD_WEBHOOK}
exit 1
fi
fi
# Notification on start
curl -X POST -H "Content-Type: application/json" -d '{"content": "🏁 Backup to SMB started."}' ${DISCORD_WEBHOOK}
START_TIME=\$(date -u +%s)
# Backup using rsync. Only backup files which are younger than the prune value.
TMP_FILE_LIST="/tmp/files_to_backup.txt"
find $SOURCE_DIR -type f -mtime -$PRUNE_DAYS > \$TMP_FILE_LIST
rsync -avz --no-relative --bwlimit=$BWLIMIT --files-from=\$TMP_FILE_LIST / \$TARGET_DIR
rm -f \$TMP_FILE_LIST
# Check if rsync completed successfully
if [ \$? -ne 0 ]; then
echo "\$(date -u +'%Y-%m-%dT%H:%M:%SZ') - Run ID: \$RUN_ID - Rsync failed" >> $LOG_FILE
curl -X POST -H "Content-Type: application/json" -d '{"content": "❌ Backup to SMB failed!"}' ${DISCORD_WEBHOOK}
fi
END_TIME=\$(date -u +%s)
DURATION=\$((END_TIME - START_TIME))
# Notification on successful completion
curl -X POST -H "Content-Type: application/json" -d '{"content": "💾 Backup to SMB completed in '\$DURATION' seconds."}' ${DISCORD_WEBHOOK}
# Prune old backups, excluding .lock files
find \$TARGET_DIR -mtime +$PRUNE_DAYS -type f ! -name '*.lock' -delete
# Unmount the SMB share
sudo umount \$TARGET_DIR
# Prune the log file to keep it under 50MB
tail -c 50M $LOG_FILE > \$LOG_FILE.tmp
mv \$LOG_FILE.tmp $LOG_FILE
EOL
sudo chmod +x ~/backup_to_smb.sh
# Check if the cron job already exists
CRON_EXISTING=$(crontab -l | grep "~/backup_to_smb.sh")
# Schedule the backup only if it's not already there
if [ -z "$CRON_EXISTING" ]; then
(crontab -l 2>/dev/null; echo "$CRON_SCHEDULE ~/backup_to_smb.sh") | crontab -
fi
echo "Installation and setup complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment