T
Trinh Digital
Xây dựng Hệ thống

Hướng dẫn setup auto-backup cho website + database (miễn phí)

Trinh Digital · · 10 phút đọc

Cách backup website tự động là một trong những kỹ năng cơ bản nhưng cực kỳ quan trọng cho bất kỳ ai quản lý website. Bài viết này hướng dẫn từng bước setup hệ thống backup tự động hoàn chỉnh — database + files + sync cloud — miễn phí, chạy tự động mỗi ngày, không cần phần mềm trả phí. Tổng thời gian setup: khoảng 30–45 phút.

Lead magnet: Tải miễn phí Backup Strategy Template cho SME — template lập kế hoạch backup + script mẫu sẵn dùng.

Tổng quan hệ thống backup

Mục tiêu

Yêu cầuGiải pháp
Backup database hàng ngàymysqldump + cron
Backup files hàng ngàytar/rsync + cron
Giữ 30 bản backup localScript cleanup tự động
Sync offsite (cloud)rclone → Google Drive/S3/B2
Alert khi backup lỗiScript gửi Telegram
Chi phí0 VND (tools miễn phí + free cloud storage)

Kiến trúc

[Cron Job - 3:00 AM hàng ngày]
    ├── mysqldump → backup database → gzip → /opt/backup/db/
    ├── tar → backup website files → gzip → /opt/backup/files/
    ├── rclone sync → Google Drive / S3 / Backblaze B2
    ├── Cleanup backup > 30 ngày
    └── Gửi notification → Telegram

Phần 1: Backup Database (MySQL/MariaDB)

Bước 1: Tạo MySQL user cho backup

Không dùng root để backup — tạo user riêng với quyền tối thiểu:

sudo mysql -u root -p
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'BackupStrongPassword!@#2026';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Bước 2: Tạo credential file (không lưu password trong script)

sudo tee /root/.my-backup.cnf > /dev/null <<EOF
[client]
user=backup_user
password=BackupStrongPassword!@#2026
EOF

sudo chmod 600 /root/.my-backup.cnf

Bước 3: Script backup database

sudo tee /opt/scripts/backup-db.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Database Backup Script
# Chạy hàng ngày bằng crontab
#

# Cấu hình
BACKUP_DIR="/opt/backup/db"
MYSQL_CONF="/root/.my-backup.cnf"
DATABASES="website_db"  # Thêm database khác: "db1 db2 db3"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/backup-db.log"

# Tạo thư mục
mkdir -p $BACKUP_DIR

echo "[$DATE] Starting database backup..." >> $LOG_FILE

# Backup từng database
for DB in $DATABASES; do
    BACKUP_FILE="$BACKUP_DIR/${DB}_${DATE}.sql.gz"

    mysqldump --defaults-extra-file=$MYSQL_CONF \
        --single-transaction \
        --quick \
        --lock-tables=false \
        --routines \
        --triggers \
        --events \
        $DB | gzip > $BACKUP_FILE

    if [ $? -eq 0 ]; then
        SIZE=$(du -h $BACKUP_FILE | cut -f1)
        echo "[$DATE] SUCCESS: $DB → $BACKUP_FILE ($SIZE)" >> $LOG_FILE
    else
        echo "[$DATE] ERROR: Failed to backup $DB" >> $LOG_FILE
        # Gửi alert (xem phần Telegram notification)
    fi
done

# Xóa backup cũ hơn 30 ngày
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "[$DATE] Cleaned up backups older than $RETENTION_DAYS days" >> $LOG_FILE

echo "[$DATE] Database backup completed" >> $LOG_FILE
SCRIPT

sudo chmod +x /opt/scripts/backup-db.sh

Bước 4: Test backup

sudo /opt/scripts/backup-db.sh

# Kiểm tra file backup
ls -la /opt/backup/db/

# Kiểm tra backup file hợp lệ
gunzip -t /opt/backup/db/website_db_*.sql.gz
echo $?  # 0 = OK

Bước 5: Test restore

# Tạo test database
mysql -u root -p -e "CREATE DATABASE test_restore;"

# Restore backup vào test database
gunzip -c /opt/backup/db/website_db_LATEST.sql.gz | mysql -u root -p test_restore

# Verify
mysql -u root -p -e "SELECT COUNT(*) FROM test_restore.orders;"

# Cleanup
mysql -u root -p -e "DROP DATABASE test_restore;"

Phần 2: Backup Website Files

Script backup files

sudo tee /opt/scripts/backup-files.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Files Backup Script
#

BACKUP_DIR="/opt/backup/files"
WEB_DIR="/var/www"
RETENTION_DAYS=14  # Files lớn hơn DB, giữ 14 ngày
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/backup-files.log"

mkdir -p $BACKUP_DIR

echo "[$DATE] Starting files backup..." >> $LOG_FILE

# Backup website files
BACKUP_FILE="$BACKUP_DIR/website_${DATE}.tar.gz"

tar czf $BACKUP_FILE \
    --exclude='*.log' \
    --exclude='node_modules' \
    --exclude='.git' \
    --exclude='cache/*' \
    $WEB_DIR

if [ $? -eq 0 ]; then
    SIZE=$(du -h $BACKUP_FILE | cut -f1)
    echo "[$DATE] SUCCESS: Files → $BACKUP_FILE ($SIZE)" >> $LOG_FILE
else
    echo "[$DATE] ERROR: Failed to backup files" >> $LOG_FILE
fi

# Cleanup
find $BACKUP_DIR -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "[$DATE] Files backup completed" >> $LOG_FILE
SCRIPT

sudo chmod +x /opt/scripts/backup-files.sh

Backup config files riêng

Config files quan trọng nhưng ít thay đổi — backup riêng:

sudo tee /opt/scripts/backup-config.sh > /dev/null <<'SCRIPT'
#!/bin/bash

BACKUP_DIR="/opt/backup/config"
DATE=$(date +%Y%m%d)
mkdir -p $BACKUP_DIR

tar czf $BACKUP_DIR/config_${DATE}.tar.gz \
    /etc/nginx/ \
    /etc/php/ \
    /etc/mysql/ \
    /etc/letsencrypt/ \
    /etc/ssh/sshd_config \
    /etc/crontab \
    /opt/scripts/ \
    2>/dev/null

# Giữ 90 ngày (config ít thay đổi)
find $BACKUP_DIR -name "*.tar.gz" -mtime +90 -delete
SCRIPT

sudo chmod +x /opt/scripts/backup-config.sh

Phần 3: Sync lên Cloud (Offsite Backup)

Cài rclone

curl https://rclone.org/install.sh | sudo bash

Cấu hình rclone với Google Drive

rclone config

Theo hướng dẫn:

  1. n — New remote
  2. Name: gdrive
  3. Storage: drive (Google Drive)
  4. Scope: drive (full access)
  5. Theo dõi hướng dẫn OAuth (mở browser, authorize)

Cấu hình rclone với Backblaze B2 (rẻ hơn)

rclone config
  1. n — New remote
  2. Name: b2
  3. Storage: b2 (Backblaze B2)
  4. Account ID: your-account-id
  5. Application Key: your-app-key

Script sync offsite

sudo tee /opt/scripts/backup-sync.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Sync backup to cloud storage
#

BACKUP_DIR="/opt/backup"
REMOTE="gdrive:vps-backup"  # Hoặc "b2:bucket-name/vps-backup"
LOG_FILE="/var/log/backup-sync.log"
DATE=$(date +%Y%m%d_%H%M%S)

echo "[$DATE] Starting cloud sync..." >> $LOG_FILE

rclone sync $BACKUP_DIR $REMOTE \
    --transfers 4 \
    --checkers 8 \
    --log-file=$LOG_FILE \
    --log-level INFO

if [ $? -eq 0 ]; then
    echo "[$DATE] SUCCESS: Synced to cloud" >> $LOG_FILE
else
    echo "[$DATE] ERROR: Cloud sync failed" >> $LOG_FILE
fi

echo "[$DATE] Cloud sync completed" >> $LOG_FILE
SCRIPT

sudo chmod +x /opt/scripts/backup-sync.sh

Phần 4: Telegram Notification

Tạo notification script

sudo tee /opt/scripts/backup-notify.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Telegram notification for backup status
#

BOT_TOKEN="YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"

send_telegram() {
    local message=$1
    curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
        -d "chat_id=${CHAT_ID}" \
        -d "text=${message}" \
        -d "parse_mode=HTML" > /dev/null
}

# Kiểm tra kết quả backup
DB_BACKUP=$(ls -t /opt/backup/db/*.sql.gz 2>/dev/null | head -1)
FILES_BACKUP=$(ls -t /opt/backup/files/*.tar.gz 2>/dev/null | head -1)

if [ -n "$DB_BACKUP" ] && [ -n "$FILES_BACKUP" ]; then
    DB_SIZE=$(du -h $DB_BACKUP | cut -f1)
    FILES_SIZE=$(du -h $FILES_BACKUP | cut -f1)
    TOTAL_BACKUPS_DB=$(ls /opt/backup/db/*.sql.gz 2>/dev/null | wc -l)
    TOTAL_BACKUPS_FILES=$(ls /opt/backup/files/*.tar.gz 2>/dev/null | wc -l)
    DISK_USAGE=$(df -h /opt/backup | tail -1 | awk '{print $5}')

    MESSAGE="<b>Backup Report</b>
Server: $(hostname)
Date: $(date '+%Y-%m-%d %H:%M')

DB: $DB_SIZE ($TOTAL_BACKUPS_DB copies)
Files: $FILES_SIZE ($TOTAL_BACKUPS_FILES copies)
Disk: $DISK_USAGE

Status: OK"

    send_telegram "$MESSAGE"
else
    MESSAGE="<b>BACKUP FAILED</b>
Server: $(hostname)
Date: $(date '+%Y-%m-%d %H:%M')

Check /var/log/backup-*.log for details"

    send_telegram "$MESSAGE"
fi
SCRIPT

sudo chmod +x /opt/scripts/backup-notify.sh

Phần 5: Master Backup Script + Crontab

Master script

sudo tee /opt/scripts/backup-master.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Master Backup Script - chạy tất cả backup jobs
#

LOG_FILE="/var/log/backup-master.log"
DATE=$(date +%Y%m%d_%H%M%S)

echo "========================================" >> $LOG_FILE
echo "[$DATE] BACKUP STARTED" >> $LOG_FILE

# 1. Backup database
/opt/scripts/backup-db.sh

# 2. Backup files
/opt/scripts/backup-files.sh

# 3. Backup config (chỉ chạy thứ 2 hàng tuần)
if [ $(date +%u) -eq 1 ]; then
    /opt/scripts/backup-config.sh
fi

# 4. Sync to cloud
/opt/scripts/backup-sync.sh

# 5. Send notification
/opt/scripts/backup-notify.sh

echo "[$DATE] BACKUP COMPLETED" >> $LOG_FILE
echo "========================================" >> $LOG_FILE
SCRIPT

sudo chmod +x /opt/scripts/backup-master.sh

Cấu hình crontab

sudo crontab -e

Thêm:

# Backup hàng ngày lúc 3:00 AM
0 3 * * * /opt/scripts/backup-master.sh >> /var/log/backup-master.log 2>&1

# Rotate log files hàng tháng
0 0 1 * * find /var/log/backup-*.log -size +10M -exec truncate -s 0 {} \;

Phần 6: Verify & Test Restore

Script test restore tự động

sudo tee /opt/scripts/backup-verify.sh > /dev/null <<'SCRIPT'
#!/bin/bash
#
# Verify backup integrity
# Chạy hàng tuần
#

LOG_FILE="/var/log/backup-verify.log"
DATE=$(date +%Y%m%d_%H%M%S)

echo "[$DATE] Starting backup verification..." >> $LOG_FILE

# Test database backup integrity
LATEST_DB=$(ls -t /opt/backup/db/*.sql.gz | head -1)
if gunzip -t $LATEST_DB 2>/dev/null; then
    echo "[$DATE] DB backup integrity: OK" >> $LOG_FILE
else
    echo "[$DATE] DB backup integrity: FAILED!" >> $LOG_FILE
fi

# Test files backup integrity
LATEST_FILES=$(ls -t /opt/backup/files/*.tar.gz | head -1)
if tar tzf $LATEST_FILES > /dev/null 2>&1; then
    echo "[$DATE] Files backup integrity: OK" >> $LOG_FILE
else
    echo "[$DATE] Files backup integrity: FAILED!" >> $LOG_FILE
fi

# Test restore database (tạo temp database)
mysql -u root -e "CREATE DATABASE IF NOT EXISTS backup_verify_test;" 2>/dev/null
gunzip -c $LATEST_DB | mysql -u root backup_verify_test 2>/dev/null
if [ $? -eq 0 ]; then
    TABLES=$(mysql -u root -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='backup_verify_test';")
    echo "[$DATE] DB restore test: OK ($TABLES tables)" >> $LOG_FILE
else
    echo "[$DATE] DB restore test: FAILED!" >> $LOG_FILE
fi
mysql -u root -e "DROP DATABASE IF EXISTS backup_verify_test;" 2>/dev/null

echo "[$DATE] Backup verification completed" >> $LOG_FILE
SCRIPT

sudo chmod +x /opt/scripts/backup-verify.sh

# Chạy hàng tuần (Chủ Nhật 4:00 AM)
(sudo crontab -l; echo "0 4 * * 0 /opt/scripts/backup-verify.sh >> /var/log/backup-verify.log 2>&1") | sudo crontab -

Tổng kết: Checklist setup

#BướcThời gianKiểm tra
1Tạo MySQL backup user5 phút
2Tạo credential file (.my-backup.cnf)2 phút
3Tạo script backup database5 phút
4Tạo script backup files5 phút
5Cài rclone + cấu hình cloud10 phút
6Tạo script cloud sync3 phút
7Setup Telegram notification5 phút
8Tạo master script3 phút
9Cấu hình crontab2 phút
10Test chạy thủ công5 phút
11Test restore10 phút
Tổng~55 phút

FAQ — Câu hỏi thường gặp

Backup nên chạy lúc mấy giờ?

2:00–4:00 AM — traffic thấp nhất, ít ảnh hưởng performance. Tránh chạy lúc 0:00 (nhiều cron job khác cũng chạy). Nếu có nhiều server, stagger thời gian backup (server 1 lúc 2:00, server 2 lúc 2:30).

Backup tốn bao nhiêu dung lượng?

Database 1GB → backup gzip ~200MB/ngày × 30 ngày = ~6GB. Files 5GB → backup gzip ~2GB/tuần × 4 tuần = ~8GB. Tổng ~14GB cho 30 ngày retention. Chi phí lưu trữ cloud: ~2.000 VND/tháng (Backblaze B2).

rclone có an toàn không?

rclone là open source, được sử dụng rộng rãi. Data transfer được encrypt (HTTPS). Có thể thêm encryption cho data at rest: rclone sync --crypt-remote. Credential file nên chmod 600 và chỉ root access.

Kết luận

Setup backup tự động miễn phí mất chưa đến 1 giờ, nhưng bảo vệ dữ liệu trị giá hàng tỉ đồng. Không có lý do để chưa có backup — bắt đầu ngay hôm nay.

Nếu bạn cần hỗ trợ setup backup chuyên nghiệp hoặc dịch vụ xây dựng hệ thống với backup tự động cho doanh nghiệp, hãy liên hệ Trinh Digital.

#website#tự động#database#backup
Chia sẻ: Z

Sẵn sàng chuyển đổi số cùng Trinh Digital?

Liên hệ ngay để nhận tư vấn miễn phí. Đội ngũ chuyên gia sẽ phân tích nhu cầu và đề xuất giải pháp tối ưu.

Zalo