
Automatic Backups on a Linux Server With Cron and Bash Scripts
Build a real backup routine on a Linux VDS: bash scripts, database dumps, incremental rsync, cron scheduling, offsite copies and restore verification.
Automatic Backups on a Linux Server
Data loss is the risk that ends projects. Hardware failures, software bugs and plain human error all threaten your data, and the only defence that works reliably is an automated backup system you never have to remember. This guide covers building one on a Linux VDS.
Backup Strategy
The 3-2-1 Rule
The industry standard is worth following:
- 3 copies: the original plus two backups
- 2 different media: local disk plus a remote server
- 1 copy offsite: in a different physical location
💡 White Bilişim includes free daily automatic backups on every VDS plan. We still recommend running your own backup routine on top of that, because a backup you control is a backup you can test.
Method 1: A Simple Bash Script
Basic Backup Script
#!/bin/bash
# backup.sh - basic backup script
# Settings
BACKUP_DIR="/backup"
SOURCE_DIRS="/var/www /etc /home"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/backup_$DATE.tar.gz"
LOG_FILE="$BACKUP_DIR/backup.log"
RETENTION_DAYS=7
# Create the backup directory
mkdir -p $BACKUP_DIR
# Start the backup
echo "[$DATE] Backup started..." >> $LOG_FILE
tar -czf $BACKUP_FILE $SOURCE_DIRS 2>> $LOG_FILE
if [ $? -eq 0 ]; then
FILESIZE=$(du -h $BACKUP_FILE | cut -f1)
echo "[$DATE] Backup succeeded: $BACKUP_FILE ($FILESIZE)" >> $LOG_FILE
else
echo "[$DATE] ERROR: backup failed!" >> $LOG_FILE
fi
# Clean up old backups
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "[$DATE] Backups older than $RETENTION_DAYS days removed." >> $LOG_FILE# Make the script executable
chmod +x /root/backup.sh
# Test it
./backup.shMethod 2: Database Backups
MySQL and MariaDB
#!/bin/bash
# db_backup.sh - database backup
BACKUP_DIR="/backup/db"
DATE=$(date +%Y%m%d_%H%M%S)
DB_USER="root"
DB_PASS="database_password"
mkdir -p $BACKUP_DIR
# Dump every database
mysqldump -u$DB_USER -p$DB_PASS --all-databases --single-transaction | gzip > "$BACKUP_DIR/all_db_$DATE.sql.gz"
# Dump a single database
mysqldump -u$DB_USER -p$DB_PASS fivem_db --single-transaction | gzip > "$BACKUP_DIR/fivem_db_$DATE.sql.gz"
# Remove dumps older than 14 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +14 -deletePostgreSQL
#!/bin/bash
# pg_backup.sh
BACKUP_DIR="/backup/pgsql"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Dump every database
sudo -u postgres pg_dumpall | gzip > "$BACKUP_DIR/pg_all_$DATE.sql.gz"Method 3: Incremental Backups With rsync
rsync only copies what changed, which makes frequent backups cheap:
#!/bin/bash
# rsync_backup.sh - incremental backup
SOURCE="/var/www"
DEST="/backup/rsync"
LOG="/var/log/rsync_backup.log"
mkdir -p $DEST
rsync -avz --delete \
--exclude='*.log' \
--exclude='node_modules/' \
--exclude='.git/' \
$SOURCE $DEST \
>> $LOG 2>&1
echo "[$(date)] rsync backup finished." >> $LOGSending Backups to a Remote Server
# Push backups to another server
rsync -avz -e "ssh -p 22" /backup/ backup_user@REMOTE_SERVER_IP:/remote-backup/Scheduling With Cron
Cron Syntax
# ┌───────── Minute (0-59)
# │ ┌─────── Hour (0-23)
# │ │ ┌───── Day of month (1-31)
# │ │ │ ┌─── Month (1-12)
# │ │ │ │ ┌─ Day of week (0-7, 0 and 7 are Sunday)
# │ │ │ │ │
# * * * * * command
Adding Cron Jobs
# Open the cron editor
crontab -e
# Full backup every night at 03:00
0 3 * * * /root/backup.sh
# Database backup every 6 hours
0 */6 * * * /root/db_backup.sh
# rsync every hour
0 * * * * /root/rsync_backup.sh
# Weekly full backup every Sunday at 02:00
0 2 * * 0 /root/weekly_backup.shListing Cron Jobs
# Show the current user's cron jobs
crontab -l
# Show root's cron jobs
sudo crontab -lVerifying Your Backups
An untested backup is a guess. Check them on a schedule:
# List the backup files
ls -lh /backup/
# Verify the integrity of a tar archive
tar -tzf /backup/backup_20260408_030000.tar.gz > /dev/null && echo "Backup is intact" || echo "Backup is corrupt!"
# Test a database dump by restoring it into a scratch database
zcat /backup/db/all_db_20260408.sql.gz | mysql -u root -p test_restore_dbEmail Notifications
#!/bin/bash
# backup_with_notification.sh
# Run the backup
/root/backup.sh
# Report the result by email
if [ $? -eq 0 ]; then
echo "Backup succeeded - $(date)" | mail -s "✅ Server backup succeeded" admin@yoursite.com
else
echo "ERROR: backup failed! - $(date)" | mail -s "❌ Server backup FAILED" admin@yoursite.com
fiGame Server Backup Examples
Backing Up a FiveM Server
#!/bin/bash
# fivem_backup.sh
FIVEM_DIR="/home/fivem-server"
BACKUP_DIR="/backup/fivem"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Back up the database
mysqldump -u root -p fivem_db | gzip > "$BACKUP_DIR/fivem_db_$DATE.sql.gz"
# Back up the server files
tar -czf "$BACKUP_DIR/fivem_files_$DATE.tar.gz" \
$FIVEM_DIR/server.cfg \
$FIVEM_DIR/resources/ \
--exclude="$FIVEM_DIR/resources/[system]"
find $BACKUP_DIR -mtime +7 -deleteBacking Up a Minecraft World
#!/bin/bash
# minecraft_backup.sh
MC_DIR="/home/minecraft"
BACKUP_DIR="/backup/minecraft"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Back up the world
tar -czf "$BACKUP_DIR/world_$DATE.tar.gz" $MC_DIR/world/
find $BACKUP_DIR -name "world_*.tar.gz" -mtime +14 -deleteWhich Plan for Backup Workloads
| Need | Recommended plan | Specs |
|---|---|---|
| Simple backups | ENT-2 | 2 Core, 4 GB RAM, 40 GB SSD |
| Frequent backups | ENT-5 | 8 Core, 10 GB RAM, 100 GB SSD |
| Large data sets | PRO-4 | 8 Core Ryzen, 10 GB RAM, 100 GB SSD |
Conclusion
Automated backups are the single most important habit in server administration. Cron jobs and a few short scripts remove the human element entirely. We include free daily backups on every VDS plan, but building your own routine on top of that is still strongly recommended.
👉 To keep backups on separate hardware, see our backup server plans, and Xeon Enterprise VDS or Ryzen Premium VDS for the production side.