A simple and easy to download backup from remote servers using CRON and SCP. This example keeps last 4 weekly and 12 monthly backups. Change the values you desire. The way this works is that the remote server creates a zip backup at a specific time (cron) and then 15 minutes later (cron) local server downloads that zip file using SCP.
Before running the commands below in your terminal replace ssh-ed25519 yourlongsshkeygoeshere BackupUser with your own SSH Key (line 26).
Remote Server Setup
## Server Setup
# SSH commands for creating user and download upload directories
groupadd backupusers
useradd -g backupusers -s /sbin/nologin backupuser
mkdir -p /mnt/SystemAdmin/BackupStorage/{upload,download}
chown backupuser:backupusers /mnt/SystemAdmin/BackupStorage/{upload,download}
chown root:root /mnt/SystemAdmin/BackupStorage
chmod 755 /mnt/SystemAdmin/BackupStorage
echo "
Match User backupuser
AuthorizedKeysFile /mnt/SystemAdmin/AuthorizedKeys/BackupUser
ForceCommand internal-sftp
PasswordAuthentication no
ChrootDirectory /mnt/SystemAdmin/BackupStorage
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
" >> /etc/ssh/sshd_config
# Paste your generated SSH key below
mkdir -p /mnt/SystemAdmin/AuthorizedKeys
cat > /mnt/SystemAdmin/AuthorizedKeys/BackupUser << EOF
ssh-ed25519 yourlongsshkeygoeshere BackupUser
EOF
chmod 0600 /mnt/SystemAdmin/AuthorizedKeys/BackupUser
chown -R backupuser:backupusers /mnt/SystemAdmin/AuthorizedKeys/BackupUser
systemctl restart sshd
Bash script to find files to backup and zip them, include your desired file extensions to backup. Working dir starts at /var/www, change it to your desired start of working directory and the script will recursively search and include the files in the backup zip file.
#!/bin/bash
wdir="/var/www"
backup_dir="/mnt/SystemAdmin/BackupStorage/download"
backupfilename="${backup_dir}/Backup.zip"
find "$wdir" -type f '(' -name '*.db' -o -name '*.php' -o -name '*.ini' ')' -exec zip -r "$backupfilename" {} +
logger -t SystemAdmin -p warning "Zip Backup job complete"
exit 0
Cron setup. It creates a cron job at 5:30 and calls the zip-backup.sh bash script which zips the files in the archive that you want to include in the backup
30 5 * * * /bin/bash /root/Scripts/zip-backup.sh > /dev/null 2>&1CopyLocal Backup Server Setup
Change the path to /pathtosshkey/id_ed25519_BackupUser your SSH key file
Create two bash files below
#!/bin/bash
FILENAME_PREFIX="/root/Downloads/Server1Weekly"
FILENAME_EXTENSION="zip"
NUM_COPIES_TO_KEEP=4
# Do not use name with any space or special characters
SCRIPT_NAME="[RemoteServer1]"
NL="\n"
LOCKFILE="/var/tmp/${SCRIPT_NAME}Weekly.lock"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
NEW_FILENAME="${FILENAME_PREFIX}_${TIMESTAMP}.${FILENAME_EXTENSION}"
scp -o StrictHostKeyChecking=accept-new -i /pathtosshkey/id_ed25519_BackupUser backupuser@www.remoteserver1.com:/download/Backup.zip ${NEW_FILENAME}
if [ $? -eq 0 ]; then
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Download successful"
log_message+="${NL}${SCRIPT_NAME} Download successful"
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Downloading backup to ${NEW_FILENAME}"
log_message="${SCRIPT_NAME} Downloading backup to ${NEW_FILENAME}"
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Managing old copies"
log_message+="${NL}${SCRIPT_NAME} Managing old copies"
OLD_FILES_TO_DELETE=$(ls -tr "${FILENAME_PREFIX}_"*".${FILENAME_EXTENSION}" | head -n -"${NUM_COPIES_TO_KEEP}")
if [ -n "$OLD_FILES_TO_DELETE" ]; then
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Deleting old copies"
log_message+="${NL}${SCRIPT_NAME} Deleting old copies"
echo "$OLD_FILES_TO_DELETE" | while read -r file; do
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Deleting: $file"
rm "$file"
echo "$file">>"/var/tmp/deleteoldfiles${SCRIPT_NAME}Weekly.txt"
done
IFS=$'\n'
for line in $(cat "/var/tmp/deleteoldfiles${SCRIPT_NAME}Weekly.txt"); do
log_message+="${NL}${SCRIPT_NAME} $line Deleted"
done
rm "/var/tmp/deleteoldfiles${SCRIPT_NAME}Weekly.txt"
else
logger -t SystemAdmin -p warning "${SCRIPT_NAME} No old copies to delete or fewer than ${NUM_COPIES_TO_KEEP} copies present"
log_message+="${NL}${SCRIPT_NAME} No old copies to delete or fewer than ${NUM_COPIES_TO_KEEP} copies present"
fi
if [ -e $LOCKFILE ]
then
rm $LOCKFILE
fi
else
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Download failed"
log_message+="${NL}${SCRIPT_NAME} Download failed"
touch $LOCKFILE
fi
# Notification API if you need one
#generate_post_data()
#{
#cat <<EOF
#{
#"token": "password",
#"title": "$SCRIPT_NAME Backup",
#"message": "$log_message"
#}
#EOF
#}
#curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST --data "$(generate_post_data)" "http://example.com/notification-json.php"
exit 0
Monthly backup bash script
#!/bin/bash
FILENAME_PREFIX_WEEKLY="/root/Downloads/Server1Weekly"
FILENAME_PREFIX="/root/Downloads/Server1Monthly"
FILENAME_EXTENSION="zip"
NUM_COPIES_TO_KEEP=12
# Do not use name with any space or special characters
SCRIPT_NAME="[RemoteServer1]"
NL="\n"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
LOCKFILE="/var/tmp/${SCRIPT_NAME}Weekly.lock"
if [ -e $LOCKFILE ]
then
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Monthly copy failed because of lock file"
echo "ERROR: Monthly copy failed because of lock file"
log_message+="${NL}${SCRIPT_NAME} Monthly copy failed because of lock file"
else
NEW_FILENAME="${FILENAME_PREFIX}_${TIMESTAMP}.${FILENAME_EXTENSION}"
LATEST_FILE_TO_COPY=$(ls -t "${FILENAME_PREFIX_WEEKLY}_"*".${FILENAME_EXTENSION}" | head -n 1)
if [ -n "$LATEST_FILE_TO_COPY" ]; then
cp "$LATEST_FILE_TO_COPY" ${NEW_FILENAME}
if [ $? -eq 0 ]; then
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Monthly copy successful"
log_message+="${NL}${SCRIPT_NAME} Monthly copy successful"
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Monthly backup to ${NEW_FILENAME}"
log_message="${SCRIPT_NAME} Monthly backup to ${NEW_FILENAME}"
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Managing old monthly copies"
log_message+="${NL}${SCRIPT_NAME} Managing old monthly copies"
OLD_FILES_TO_DELETE=$(ls -tr "${FILENAME_PREFIX}_"*".${FILENAME_EXTENSION}" | head -n -"${NUM_COPIES_TO_KEEP}")
if [ -n "$OLD_FILES_TO_DELETE" ]; then
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Deleting old monthly copies"
log_message+="${NL}${SCRIPT_NAME} Deleting old monthly copies"
echo "$OLD_FILES_TO_DELETE" | while read -r file; do
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Deleting: $file"
rm "$file"
echo "$file">>"/var/tmp/deleteoldfiles${SCRIPT_NAME}Monthly.txt"
done
IFS=$'\n'
for line in $(cat "/var/tmp/deleteoldfiles${SCRIPT_NAME}Monthly.txt"); do
log_message+="${NL}${SCRIPT_NAME} $line Deleted"
done
rm "/var/tmp/deleteoldfiles${SCRIPT_NAME}Monthly.txt"
else
logger -t SystemAdmin -p warning "${SCRIPT_NAME} No old copies to delete or fewer than ${NUM_COPIES_TO_KEEP} monthly copies present"
log_message+="${NL}${SCRIPT_NAME} No old copies to delete or fewer than ${NUM_COPIES_TO_KEEP} monthly copies present"
fi
else
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Monthly copy failed"
log_message+="${NL}${SCRIPT_NAME} Monthly copy failed"
fi
else
logger -t SystemAdmin -p warning "${SCRIPT_NAME} Error: Monthly copy failed, file does not exist or is inaccessible."
log_message+="${NL}${SCRIPT_NAME} Error: Monthly copy failed, file does not exist or is inaccessible."
echo "${SCRIPT_NAME} Error: Monthly copy failed, file does not exist or is inaccessible."
fi
# Notification API if you need one
#generate_post_data()
#{
#cat <<EOF
#{
#"token": "password",
#"title": "$SCRIPT_NAME Backup",
#"message": "$log_message"
#}
#EOF
#}
#curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST --data "$(generate_post_data)" "http://example.com/notification-json.php"
fi
exit 0
Cron setup for backup server. Create two cron jobs for backup, one weekly / daily and one monthly. It creates a cron job at 5:45, 15 minutes after the remote server made a backup zip file (at 5:30 above). It runs on 1,7,14,21,28 of every month, change it to daily if you want daily backup and change the numbers of backup to keep.
45 5 1,7,14,21,28 * * /bin/bash /root/SCP-Server1Weekly.sh > /dev/null 2>&1CopyMonthly cron to create last 12 monthly backups.
55 5 1 * * /bin/bash /root/SCP-Server1Monthly.sh > /dev/null 2>&1CopyLet me know if you have any comments or if there is any error in this guide.