Automating Backups with rsync and cron: Complete Guide

Learn to create robust automated backup systems using rsync and cron. Master delta transfers, scheduling, remote backups, and best practices.

Automating Backups with rsync and cron

Table of Contents

1. [Introduction](#introduction) 2. [Understanding rsync](#understanding-rsync) 3. [Understanding cron](#understanding-cron) 4. [Basic rsync Usage](#basic-rsync-usage) 5. [Advanced rsync Options](#advanced-rsync-options) 6. [Setting Up Automated Backups](#setting-up-automated-backups) 7. [Backup Strategies](#backup-strategies) 8. [Remote Backups](#remote-backups) 9. [Monitoring and Logging](#monitoring-and-logging) 10. [Troubleshooting](#troubleshooting) 11. [Best Practices](#best-practices)

Introduction

Automated backups are essential for data protection and disaster recovery. The combination of rsync and cron provides a powerful, flexible, and reliable solution for creating automated backup systems on Unix-like operating systems. This guide covers everything from basic concepts to advanced implementation strategies.

rsync is a fast, versatile file copying tool that can work locally or with remote systems. It uses a delta-transfer algorithm that sends only the differences between source and destination files, making it extremely efficient for incremental backups.

cron is a time-based job scheduler that allows you to run commands or scripts at specified intervals automatically. Together, these tools create a robust backup automation system.

Understanding rsync

What is rsync

rsync stands for "remote sync" and is a utility for efficiently transferring and synchronizing files between directories, disks, and networked computers. It was written by Andrew Tridgell and Paul Mackerras and first released in 1996.

Key Features of rsync

| Feature | Description | |---------|-------------| | Delta Transfer | Only transfers changed portions of files | | Preservation | Maintains file permissions, ownership, timestamps | | Compression | Can compress data during transfer | | Remote Sync | Works over SSH, RSH, or direct socket connections | | Incremental | Supports incremental backups efficiently | | Verification | Built-in data verification mechanisms | | Bandwidth Control | Can limit bandwidth usage | | Dry Run | Test mode to preview operations |

rsync Algorithm

The rsync algorithm works by:

1. Dividing files into fixed-size blocks 2. Computing checksums for each block 3. Comparing checksums between source and destination 4. Transferring only blocks that differ 5. Reconstructing files at the destination

This approach makes rsync extremely efficient for large files with small changes.

Understanding cron

What is cron

cron is a daemon that runs continuously in the background and executes scheduled tasks at specified times and dates. It reads configuration files called "crontabs" that contain lists of commands and their schedules.

Cron Components

| Component | Description | |-----------|-------------| | crond | The cron daemon that runs scheduled tasks | | crontab | Command to edit cron schedules | | /etc/crontab | System-wide cron configuration | | /var/spool/cron | User-specific cron files | | /etc/cron.d/ | Additional system cron files | | /etc/cron.hourly/ | Scripts run hourly | | /etc/cron.daily/ | Scripts run daily | | /etc/cron.weekly/ | Scripts run weekly | | /etc/cron.monthly/ | Scripts run monthly |

Crontab Syntax

The crontab format consists of six fields:

` * command │ │ │ │ │ │ │ │ │ └─── Day of week (0-7, Sunday = 0 or 7) │ │ │ └───── Month (1-12) │ │ └─────── Day of month (1-31) │ └───────── Hour (0-23) └─────────── Minute (0-59) `

Crontab Special Characters

| Character | Meaning | Example | |-----------|---------|---------| | | Any value | (every minute) | | , | List separator | 1,15 (1st and 15th minute) | | - | Range | 1-5 (minutes 1 through 5) | | / | Step values | /15 * (every 15 minutes) | | @reboot | At startup | @reboot /path/script | | @yearly | Once per year | @yearly /path/script | | @monthly | Once per month | @monthly /path/script | | @weekly | Once per week | @weekly /path/script | | @daily | Once per day | @daily /path/script | | @hourly | Once per hour | @hourly /path/script |

Basic rsync Usage

Installation

Most Linux distributions include rsync by default. If not installed:

`bash

Ubuntu/Debian

sudo apt-get install rsync

CentOS/RHEL/Fedora

sudo yum install rsync

or

sudo dnf install rsync

macOS (using Homebrew)

brew install rsync `

Basic Syntax

`bash rsync [OPTIONS] SOURCE DESTINATION `

Essential rsync Options

| Option | Description | Example | |--------|-------------|---------| | -a | Archive mode (recursive, preserve attributes) | rsync -a /source/ /dest/ | | -v | Verbose output | rsync -av /source/ /dest/ | | -r | Recursive | rsync -r /source/ /dest/ | | -u | Update (skip newer files at destination) | rsync -au /source/ /dest/ | | -z | Compress during transfer | rsync -avz /source/ /dest/ | | -h | Human-readable output | rsync -avh /source/ /dest/ | | -P | Show progress and keep partial files | rsync -avP /source/ /dest/ | | --delete | Delete files in destination not in source | rsync -av --delete /source/ /dest/ | | --dry-run | Preview without making changes | rsync -av --dry-run /source/ /dest/ | | --exclude | Exclude files/directories | rsync -av --exclude '*.log' /source/ /dest/ |

Basic Examples

#### Local Directory Sync

`bash

Sync contents of /home/user/documents to /backup/documents

rsync -av /home/user/documents/ /backup/documents/

Note: Trailing slash on source matters

/source/ means "contents of source"

/source means "source directory itself"

`

#### Sync with Progress Display

`bash rsync -avP /home/user/documents/ /backup/documents/ `

#### Dry Run to Preview Changes

`bash rsync -av --dry-run /home/user/documents/ /backup/documents/ `

#### Exclude Specific Files

`bash

Exclude log files and temporary directories

rsync -av --exclude '*.log' --exclude 'tmp/' /home/user/documents/ /backup/documents/ `

Advanced rsync Options

File Selection and Filtering

| Option | Description | Example | |--------|-------------|---------| | --include | Include files matching pattern | --include '*.txt' | | --exclude | Exclude files matching pattern | --exclude '*.tmp' | | --exclude-from | Read exclude patterns from file | --exclude-from=excludes.txt | | --include-from | Read include patterns from file | --include-from=includes.txt | | --files-from | Transfer only files listed in file | --files-from=filelist.txt | | --max-size | Don't transfer files larger than SIZE | --max-size=100M | | --min-size | Don't transfer files smaller than SIZE | --min-size=1K |

Performance and Network Options

| Option | Description | Example | |--------|-------------|---------| | --bwlimit | Limit bandwidth usage (KB/s) | --bwlimit=1000 | | --compress-level | Set compression level (0-9) | --compress-level=6 | | --partial | Keep partially transferred files | --partial | | --partial-dir | Store partial files in directory | --partial-dir=/tmp/rsync-partial | | --timeout | Set I/O timeout in seconds | --timeout=300 | | --contimeout | Set connection timeout | --contimeout=60 |

Advanced Examples

#### Complex Exclude Pattern

`bash rsync -av \ --exclude '.git/' \ --exclude '*.log' \ --exclude '*.tmp' \ --exclude 'node_modules/' \ --exclude '__pycache__/' \ /home/user/projects/ /backup/projects/ `

#### Using Exclude File

Create an exclude file rsync-excludes.txt:

` *.log *.tmp .git/ node_modules/ __pycache__/ .DS_Store Thumbs.db `

Then use it:

`bash rsync -av --exclude-from=rsync-excludes.txt /home/user/projects/ /backup/projects/ `

#### Bandwidth Limited Transfer

`bash rsync -avz --bwlimit=500 --progress /large/dataset/ user@remote:/backup/dataset/ `

Setting Up Automated Backups

Creating Backup Scripts

#### Basic Local Backup Script

Create a file /usr/local/bin/backup-local.sh:

`bash #!/bin/bash

Local backup script using rsync

Author: System Administrator

Date: $(date +%Y-%m-%d)

Configuration

SOURCE_DIR="/home/user/documents" BACKUP_DIR="/backup/documents" LOG_FILE="/var/log/backup-local.log" DATE=$(date +%Y-%m-%d_%H-%M-%S)

Create log entry

echo "[$DATE] Starting backup of $SOURCE_DIR to $BACKUP_DIR" >> $LOG_FILE

Perform backup

rsync -av --delete \ --exclude '*.tmp' \ --exclude '.cache/' \ --exclude 'Downloads/' \ "$SOURCE_DIR/" "$BACKUP_DIR/" >> $LOG_FILE 2>&1

Check exit status

if [ $? -eq 0 ]; then echo "[$DATE] Backup completed successfully" >> $LOG_FILE exit 0 else echo "[$DATE] Backup failed with errors" >> $LOG_FILE exit 1 fi `

Make it executable:

`bash sudo chmod +x /usr/local/bin/backup-local.sh `

#### Advanced Backup Script with Rotation

Create /usr/local/bin/backup-incremental.sh:

`bash #!/bin/bash

Incremental backup script with rotation

Creates timestamped backups and maintains specified number of copies

Configuration

SOURCE_DIR="/home/user/documents" BACKUP_BASE="/backup" BACKUP_NAME="documents" KEEP_BACKUPS=7 LOG_FILE="/var/log/backup-incremental.log" DATE=$(date +%Y-%m-%d_%H-%M-%S) CURRENT_BACKUP="$BACKUP_BASE/${BACKUP_NAME}_$DATE" LATEST_LINK="$BACKUP_BASE/${BACKUP_NAME}_latest"

Function to log messages

log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE }

Function to send notification (optional)

send_notification() { local status=$1 local message=$2 # Uncomment and configure for email notifications # echo "$message" | mail -s "Backup $status" admin@example.com }

Start backup

log_message "Starting incremental backup of $SOURCE_DIR"

Create backup directory

mkdir -p "$CURRENT_BACKUP"

Perform incremental backup using hard links

if [ -d "$LATEST_LINK" ]; then log_message "Using $LATEST_LINK as reference for incremental backup" rsync -av --delete --link-dest="$LATEST_LINK" \ --exclude '*.tmp' \ --exclude '.cache/' \ "$SOURCE_DIR/" "$CURRENT_BACKUP/" >> $LOG_FILE 2>&1 else log_message "No previous backup found, creating full backup" rsync -av --delete \ --exclude '*.tmp' \ --exclude '.cache/' \ "$SOURCE_DIR/" "$CURRENT_BACKUP/" >> $LOG_FILE 2>&1 fi

Check backup status

if [ $? -eq 0 ]; then log_message "Backup completed successfully" # Update latest link rm -f "$LATEST_LINK" ln -s "$CURRENT_BACKUP" "$LATEST_LINK" # Cleanup old backups log_message "Cleaning up old backups (keeping $KEEP_BACKUPS)" cd "$BACKUP_BASE" ls -1t ${BACKUP_NAME}_20* 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs rm -rf send_notification "SUCCESS" "Backup completed successfully at $DATE" exit 0 else log_message "Backup failed with errors" send_notification "FAILED" "Backup failed at $DATE" exit 1 fi `

Configuring Cron Jobs

#### View Current Cron Jobs

`bash

View current user's cron jobs

crontab -l

View specific user's cron jobs (as root)

crontab -l -u username

View system cron jobs

cat /etc/crontab `

#### Edit Cron Jobs

`bash

Edit current user's cron jobs

crontab -e

Edit specific user's cron jobs (as root)

crontab -e -u username `

#### Example Cron Schedules

| Schedule | Cron Expression | Description | |----------|----------------|-------------| | Every hour | 0 | At minute 0 of every hour | | Daily at 2 AM | 0 2 * | Every day at 2:00 AM | | Weekly on Sunday | 0 2 0 | Every Sunday at 2:00 AM | | Monthly on 1st | 0 2 1 | 1st day of every month at 2:00 AM | | Every 15 minutes | /15 * | Every 15 minutes | | Workdays at 6 PM | 0 18 1-5 | Monday through Friday at 6:00 PM | | Twice daily | 0 6,18 * | Every day at 6:00 AM and 6:00 PM |

#### Setting Up Automated Backups

Add to crontab (crontab -e):

`bash

Daily backup at 2 AM

0 2 * /usr/local/bin/backup-local.sh

Incremental backup every 6 hours

0 /6 /usr/local/bin/backup-incremental.sh

Weekly full backup on Sunday at 1 AM

0 1 0 /usr/local/bin/backup-full.sh

Hourly sync of critical data

0 /usr/local/bin/sync-critical.sh `

Backup Strategies

Types of Backups

| Backup Type | Description | Advantages | Disadvantages | |-------------|-------------|------------|---------------| | Full Backup | Complete copy of all data | Simple to restore, complete | Time-consuming, storage-intensive | | Incremental | Only changes since last backup | Fast, efficient storage | Complex restore process | | Differential | Changes since last full backup | Faster restore than incremental | Larger than incremental | | Mirror | Exact replica of source | Real-time sync possible | No versioning |

Implementing Different Strategies

#### Full Backup Strategy

`bash #!/bin/bash

full-backup.sh

SOURCE="/home/user/data" BACKUP_DIR="/backup/full/$(date +%Y-%m-%d)"

mkdir -p "$BACKUP_DIR" rsync -av "$SOURCE/" "$BACKUP_DIR/" `

#### Incremental Backup with Hard Links

`bash #!/bin/bash

incremental-backup.sh

SOURCE="/home/user/data" BACKUP_BASE="/backup/incremental" DATE=$(date +%Y-%m-%d_%H-%M) CURRENT="$BACKUP_BASE/$DATE" LATEST="$BACKUP_BASE/latest"

mkdir -p "$CURRENT"

if [ -d "$LATEST" ]; then rsync -av --link-dest="$LATEST" "$SOURCE/" "$CURRENT/" else rsync -av "$SOURCE/" "$CURRENT/" fi

rm -f "$LATEST" ln -s "$CURRENT" "$LATEST" `

#### Grandfather-Father-Son Rotation

`bash #!/bin/bash

gfs-backup.sh

SOURCE="/home/user/data" BACKUP_BASE="/backup/gfs" DOW=$(date +%u) # Day of week (1-7) DOM=$(date +%d) # Day of month (01-31) MOY=$(date +%m) # Month of year (01-12)

Determine backup type

if [ "$DOM" = "01" ]; then # Monthly backup (Grandfather) BACKUP_DIR="$BACKUP_BASE/monthly/$(date +%Y-%m)" elif [ "$DOW" = "7" ]; then # Weekly backup (Father) BACKUP_DIR="$BACKUP_BASE/weekly/$(date +%Y-W%V)" else # Daily backup (Son) BACKUP_DIR="$BACKUP_BASE/daily/$(date +%Y-%m-%d)" fi

mkdir -p "$BACKUP_DIR" rsync -av --delete "$SOURCE/" "$BACKUP_DIR/" `

Remote Backups

SSH Key Setup

For automated remote backups, set up SSH key authentication:

`bash

Generate SSH key pair

ssh-keygen -t rsa -b 4096 -f ~/.ssh/backup_key

Copy public key to remote server

ssh-copy-id -i ~/.ssh/backup_key.pub user@remote-server

Test connection

ssh -i ~/.ssh/backup_key user@remote-server `

Remote Backup Examples

#### Basic Remote Backup

`bash

Backup to remote server

rsync -avz -e "ssh -i ~/.ssh/backup_key" \ /home/user/data/ \ user@remote-server:/backup/data/

Backup from remote server

rsync -avz -e "ssh -i ~/.ssh/backup_key" \ user@remote-server:/home/user/data/ \ /local/backup/data/ `

#### Remote Backup Script

`bash #!/bin/bash

remote-backup.sh

Configuration

LOCAL_DIR="/home/user/documents" REMOTE_USER="backup" REMOTE_HOST="backup-server.example.com" REMOTE_DIR="/backup/$(hostname)/documents" SSH_KEY="/home/user/.ssh/backup_key" LOG_FILE="/var/log/remote-backup.log"

Function to log messages

log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE }

Test remote connection

log_message "Testing connection to $REMOTE_HOST" ssh -i "$SSH_KEY" -o ConnectTimeout=10 "$REMOTE_USER@$REMOTE_HOST" exit if [ $? -ne 0 ]; then log_message "ERROR: Cannot connect to remote host" exit 1 fi

Create remote directory

ssh -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" "mkdir -p $REMOTE_DIR"

Perform backup

log_message "Starting backup to $REMOTE_HOST:$REMOTE_DIR" rsync -avz --delete --partial --progress \ -e "ssh -i $SSH_KEY" \ --exclude '*.tmp' \ --exclude '.cache/' \ "$LOCAL_DIR/" \ "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" >> $LOG_FILE 2>&1

if [ $? -eq 0 ]; then log_message "Backup completed successfully" else log_message "Backup failed with errors" exit 1 fi `

Using rsync Daemon

#### Server Configuration

Create /etc/rsyncd.conf:

`

Global settings

uid = backup gid = backup use chroot = yes max connections = 4 pid file = /var/run/rsyncd.pid log file = /var/log/rsyncd.log

Backup module

[backup] path = /backup comment = Backup directory read only = no auth users = backupuser secrets file = /etc/rsyncd.secrets hosts allow = 192.168.1.0/24 `

Create secrets file /etc/rsyncd.secrets:

` backupuser:secretpassword `

Set permissions:

`bash chmod 600 /etc/rsyncd.secrets `

Start rsync daemon:

`bash rsync --daemon `

#### Client Usage

`bash

Set password in environment variable

export RSYNC_PASSWORD=secretpassword

Backup to rsync daemon

rsync -av /home/user/data/ backupuser@backup-server::backup/data/ `

Monitoring and Logging

Comprehensive Logging

#### Enhanced Logging Script

`bash #!/bin/bash

backup-with-logging.sh

Configuration

SOURCE_DIR="/home/user/documents" BACKUP_DIR="/backup/documents" LOG_DIR="/var/log/backup" LOG_FILE="$LOG_DIR/backup-$(date +%Y-%m).log" STATS_FILE="$LOG_DIR/backup-stats-$(date +%Y-%m-%d).log" EMAIL="admin@example.com"

Ensure log directory exists

mkdir -p "$LOG_DIR"

Function to log with timestamp

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" }

Function to calculate directory size

get_size() { du -sh "$1" 2>/dev/null | cut -f1 }

Start backup process

START_TIME=$(date +%s) log "=== BACKUP STARTED ===" log "Source: $SOURCE_DIR" log "Destination: $BACKUP_DIR" log "Source size: $(get_size "$SOURCE_DIR")"

Perform backup with detailed statistics

rsync -av --delete --stats \ --exclude '*.tmp' \ --exclude '.cache/' \ "$SOURCE_DIR/" "$BACKUP_DIR/" > "$STATS_FILE" 2>&1

RSYNC_EXIT_CODE=$? END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME))

Log results

if [ $RSYNC_EXIT_CODE -eq 0 ]; then log "Backup completed successfully" STATUS="SUCCESS" else log "Backup failed with exit code: $RSYNC_EXIT_CODE" STATUS="FAILED" fi

log "Duration: ${DURATION} seconds" log "Destination size: $(get_size "$BACKUP_DIR")" log "=== BACKUP FINISHED ==="

Extract and log statistics

if [ -f "$STATS_FILE" ]; then FILES_TRANSFERRED=$(grep "Number of files transferred:" "$STATS_FILE" | cut -d: -f2 | tr -d ' ') TOTAL_SIZE=$(grep "Total file size:" "$STATS_FILE" | cut -d: -f2 | tr -d ' ') TRANSFERRED_SIZE=$(grep "Total transferred file size:" "$STATS_FILE" | cut -d: -f2 | tr -d ' ') log "Files transferred: $FILES_TRANSFERRED" log "Total size: $TOTAL_SIZE bytes" log "Transferred: $TRANSFERRED_SIZE bytes" fi

Send email notification if configured

if [ -n "$EMAIL" ] && command -v mail >/dev/null; then SUBJECT="Backup $STATUS - $(hostname) - $(date '+%Y-%m-%d %H:%M')" tail -20 "$LOG_FILE" | mail -s "$SUBJECT" "$EMAIL" fi

exit $RSYNC_EXIT_CODE `

Log Rotation

Create /etc/logrotate.d/backup:

` /var/log/backup/*.log { monthly rotate 12 compress delaycompress missingok notifempty create 644 root root } `

Monitoring Script

`bash #!/bin/bash

backup-monitor.sh

LOG_FILE="/var/log/backup/backup-$(date +%Y-%m).log" ALERT_EMAIL="admin@example.com" MAX_AGE_HOURS=25 # Alert if last backup is older than 25 hours

Check if log file exists

if [ ! -f "$LOG_FILE" ]; then echo "WARNING: Backup log file not found: $LOG_FILE" exit 1 fi

Get last backup timestamp

LAST_BACKUP=$(grep "BACKUP STARTED" "$LOG_FILE" | tail -1 | cut -d']' -f1 | tr -d '[')

if [ -z "$LAST_BACKUP" ]; then echo "ERROR: No backup entries found in log" exit 1 fi

Convert to epoch time

LAST_BACKUP_EPOCH=$(date -d "$LAST_BACKUP" +%s 2>/dev/null) CURRENT_EPOCH=$(date +%s) AGE_HOURS=$(( (CURRENT_EPOCH - LAST_BACKUP_EPOCH) / 3600 ))

Check backup age

if [ $AGE_HOURS -gt $MAX_AGE_HOURS ]; then MESSAGE="WARNING: Last backup is $AGE_HOURS hours old (threshold: $MAX_AGE_HOURS hours)" echo "$MESSAGE" if [ -n "$ALERT_EMAIL" ] && command -v mail >/dev/null; then echo "$MESSAGE" | mail -s "Backup Alert - $(hostname)" "$ALERT_EMAIL" fi exit 1 else echo "OK: Last backup was $AGE_HOURS hours ago" exit 0 fi `

Troubleshooting

Common rsync Error Codes

| Exit Code | Description | Common Causes | |-----------|-------------|---------------| | 0 | Success | No errors | | 1 | Syntax or usage error | Invalid command line options | | 2 | Protocol incompatibility | Version mismatch | | 3 | Errors selecting input/output files | Permission issues, missing files | | 4 | Requested action not supported | Unsupported feature | | 5 | Error starting client-server protocol | Connection issues | | 10 | Error in socket I/O | Network problems | | 11 | Error in file I/O | Disk issues, permission problems | | 12 | Error in rsync protocol data stream | Corruption, interruption | | 20 | Received SIGUSR1 or SIGINT | Interrupted by signal | | 23 | Partial transfer due to error | Some files failed to transfer | | 24 | Partial transfer due to vanished source files | Files deleted during transfer | | 25 | The --max-delete limit stopped deletions | Too many deletions prevented |

Debugging rsync Issues

#### Verbose Output

`bash

Increase verbosity

rsync -avvv /source/ /dest/

Show progress

rsync -av --progress /source/ /dest/

Dry run to test

rsync -av --dry-run /source/ /dest/ `

#### Network Debugging

`bash

Test SSH connection

ssh -v user@remote-host

Use specific SSH options

rsync -av -e "ssh -v -o ConnectTimeout=10" /source/ user@remote:/dest/

Check bandwidth

rsync -av --progress --bwlimit=1000 /source/ user@remote:/dest/ `

Common Issues and Solutions

#### Permission Denied Errors

`bash

Check file permissions

ls -la /source/problematic-file

Run with appropriate user

sudo rsync -av /source/ /dest/

Preserve permissions

rsync -av --perms --owner --group /source/ /dest/ `

#### Disk Space Issues

`bash

Check available space

df -h /dest/

Monitor space during transfer

watch df -h /dest/

Use partial transfer

rsync -av --partial --partial-dir=/tmp/rsync-partial /source/ /dest/ `

#### Network Timeouts

`bash

Increase timeout values

rsync -av --timeout=300 --contimeout=60 /source/ user@remote:/dest/

Use compression for slow links

rsync -avz --compress-level=6 /source/ user@remote:/dest/ `

Cron Troubleshooting

#### Common Cron Issues

| Issue | Cause | Solution | |-------|-------|----------| | Script doesn't run | Incorrect path | Use full paths in scripts | | Permission denied | Wrong ownership/permissions | Check script permissions | | Command not found | Limited PATH in cron | Set PATH in script or use full paths | | No output/logging | Output not redirected | Redirect output to log files | | Environment differences | Different environment in cron | Set required environment variables |

#### Debugging Cron Jobs

`bash

Check cron service status

systemctl status crond # or cron on some systems

Check cron logs

tail -f /var/log/cron

Test script manually

/usr/local/bin/backup-script.sh

Run with same environment as cron

env -i /bin/bash --login -c '/usr/local/bin/backup-script.sh' `

Best Practices

Security Best Practices

#### File Permissions

`bash

Secure backup scripts

chmod 750 /usr/local/bin/backup-*.sh chown root:backup /usr/local/bin/backup-*.sh

Secure SSH keys

chmod 600 ~/.ssh/backup_key chmod 644 ~/.ssh/backup_key.pub

Secure log files

chmod 640 /var/log/backup/*.log chown root:backup /var/log/backup/*.log `

#### SSH Configuration

Create ~/.ssh/config:

` Host backup-server HostName backup-server.example.com User backup IdentityFile ~/.ssh/backup_key IdentitiesOnly yes ServerAliveInterval 60 ServerAliveCountMax 3 ConnectTimeout 10 `

Performance Optimization

#### Rsync Performance Tips

| Optimization | Command Example | Benefit | |--------------|----------------|---------| | Use compression | rsync -avz | Reduces network usage | | Limit bandwidth | rsync -av --bwlimit=1000 | Prevents network saturation | | Use partial transfers | rsync -av --partial | Resume interrupted transfers | | Exclude unnecessary files | rsync -av --exclude '*.tmp' | Reduces transfer time | | Use appropriate block size | rsync -av --block-size=8192 | Optimizes for network/disk |

#### System Optimization

`bash

Increase file descriptor limits

echo "* soft nofile 65536" >> /etc/security/limits.conf echo "* hard nofile 65536" >> /etc/security/limits.conf

Optimize network buffers for large transfers

echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf `

Backup Verification

#### Checksum Verification Script

`bash #!/bin/bash

verify-backup.sh

SOURCE_DIR="/home/user/documents" BACKUP_DIR="/backup/documents" TEMP_DIR="/tmp/backup-verify" LOG_FILE="/var/log/backup-verify.log"

mkdir -p "$TEMP_DIR"

Generate checksums for source

find "$SOURCE_DIR" -type f -exec md5sum {} \; | sort > "$TEMP_DIR/source.md5"

Generate checksums for backup

find "$BACKUP_DIR" -type f -exec md5sum {} \; | \ sed "s|$BACKUP_DIR|$SOURCE_DIR|g" | sort > "$TEMP_DIR/backup.md5"

Compare checksums

if diff "$TEMP_DIR/source.md5" "$TEMP_DIR/backup.md5" > "$TEMP_DIR/diff.log"; then echo "[$(date)] Backup verification PASSED" >> "$LOG_FILE" exit 0 else echo "[$(date)] Backup verification FAILED" >> "$LOG_FILE" cat "$TEMP_DIR/diff.log" >> "$LOG_FILE" exit 1 fi `

Maintenance Tasks

#### Cleanup Old Backups

`bash #!/bin/bash

cleanup-backups.sh

BACKUP_DIR="/backup" KEEP_DAYS=30

Remove backups older than KEEP_DAYS

find "$BACKUP_DIR" -type d -name "20" -mtime +$KEEP_DAYS -exec rm -rf {} \;

Log cleanup activity

echo "[$(date)] Cleaned up backups older than $KEEP_DAYS days" >> /var/log/backup-cleanup.log `

#### Health Check Script

`bash #!/bin/bash

backup-health-check.sh

Check disk space

BACKUP_PARTITION="/backup" USAGE=$(df "$BACKUP_PARTITION" | awk 'NR==2 {print $5}' | sed 's/%//')

if [ $USAGE -gt 90 ]; then echo "WARNING: Backup partition is ${USAGE}% full" exit 1 fi

Check last backup age

LAST_BACKUP=$(find /backup -name "$(date +%Y-%m-%d)" -type d | head -1) if [ -z "$LAST_BACKUP" ]; then echo "ERROR: No backup found for today" exit 1 fi

Check backup size consistency

TODAY_SIZE=$(du -s /backup/$(date +%Y-%m-%d) 2>/dev/null | awk '{print $1}') YESTERDAY_SIZE=$(du -s /backup/$(date -d yesterday +%Y-%m-%d) 2>/dev/null | awk '{print $1}')

if [ -n "$TODAY_SIZE" ] && [ -n "$YESTERDAY_SIZE" ]; then DIFF_PERCENT=$(( (TODAY_SIZE - YESTERDAY_SIZE) * 100 / YESTERDAY_SIZE )) if [ $DIFF_PERCENT -gt 50 ] || [ $DIFF_PERCENT -lt -50 ]; then echo "WARNING: Backup size changed by ${DIFF_PERCENT}%" fi fi

echo "Backup health check passed" exit 0 `

This comprehensive guide covers the essential aspects of automating backups with rsync and cron, from basic concepts to advanced implementation strategies. The combination of these tools provides a robust, efficient, and reliable backup solution suitable for various environments and requirements.

Tags

  • Linux
  • backup automation
  • cron
  • rsync
  • system-administration

Related Articles

Popular Technical Articles & Tutorials

Explore our comprehensive collection of technical articles, programming tutorials, and IT guides written by industry experts:

Browse all 8+ technical articles | Read our IT blog

Automating Backups with rsync and cron: Complete Guide