Sao lưu chỉ có giá trị khi nó chạy đều đặn, nằm ngoài máy chủ và khôi phục được. Bài này giúp bạn dựng một hệ thống sao lưu đơn giản cho VPS: xuất database, nén mã nguồn website, giữ các bản cũ trong số ngày nhất định, rồi đẩy lên lưu trữ đám mây bằng rclone. Mọi thứ chạy tự động bằng cron. Cuối bài có cách thử khôi phục.
Bạn cần chuẩn bị:
- VPS Ubuntu có user sudo, website tại
/var/www/example.com, database MariaDB hoặc MySQL. - Một nơi lưu trữ ngoài mà rclone hỗ trợ: dịch vụ lưu trữ đối tượng tương thích S3, Google Drive, một VPS khác qua SFTP…
- Dung lượng trống trên VPS đủ chứa vài bản sao lưu nén.
Bước 1: Tạo thư mục và user database chỉ để sao lưu
Dùng user database riêng có quyền đọc tối thiểu, tránh để mật khẩu root trong script.
sudo mkdir -p /var/backups/site
sudo chmod 700 /var/backups/site
sudo mariadb
CREATE USER 'backup'@'localhost' IDENTIFIED BY 'MatKhauBackup_2026';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Lưu thông tin đăng nhập vào file chỉ root đọc được, để không lộ mật khẩu trong lệnh:
sudo nano /root/.my.cnf
[client]
user=backup
password=MatKhauBackup_2026
sudo chmod 600 /root/.my.cnf
Bước 2: Thử xuất database thủ công
Trên MariaDB, lệnh mariadb-dump tương đương mysqldump. Cả hai tên đều dùng được.
sudo mysqldump --single-transaction --quick --routines --events wp_example | gzip > /tmp/test.sql.gz
ls -lh /tmp/test.sql.gz
zcat /tmp/test.sql.gz | head -n 20
--single-transaction cho bản dump nhất quán với bảng InnoDB mà không khóa site. --routines và --events lấy cả stored procedure và event nếu có. Muốn sao lưu mọi database, dùng --all-databases.
Bước 3: Cài rclone và cấu hình nơi lưu trữ
Bản rclone trong kho Ubuntu thường cũ. Trang chính thức cung cấp script cài bản mới nhất:
sudo -v ; curl https://rclone.org/install.sh | sudo bash
rclone version
Tạo cấu hình. Vì script chạy bằng root, cấu hình cũng tạo bằng root:
sudo rclone config
Chọn n (New remote), đặt tên ví dụ offsite, chọn loại lưu trữ và nhập khóa truy cập. Với lưu trữ đám mây kiểu Google Drive cần đăng nhập trình duyệt, rclone sẽ hướng dẫn dùng rclone authorize trên máy có trình duyệt. Kiểm tra:
sudo rclone listremotes
sudo rclone mkdir offsite:vps-backup
sudo rclone lsd offsite:
Nên tạo thêm remote kiểu crypt bọc ngoài offsite để mã hóa dữ liệu trước khi tải lên. Ghi lại mật khẩu crypt ở nơi an toàn. Mất mật khẩu là mất luôn bản sao lưu.
Bước 4: Viết script sao lưu
sudo nano /usr/local/bin/backup-site.sh
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F_%H%M)
DEST=/var/backups/site
SITE=/var/www/example.com
DB=wp_example
KEEP_DAYS=7
REMOTE=offsite:vps-backup
mkdir -p "$DEST"
# 1. Database
mysqldump --single-transaction --quick --routines --events "$DB" \
| gzip > "$DEST/db-$DB-$DATE.sql.gz"
# 2. Mã nguồn và file upload (bỏ thư mục cache)
tar --exclude="$SITE/wp-content/cache" -czf "$DEST/files-$DATE.tar.gz" \
-C "$(dirname "$SITE")" "$(basename "$SITE")"
# 3. Cấu hình hệ thống quan trọng
tar -czf "$DEST/etc-$DATE.tar.gz" /etc/nginx /etc/php /etc/letsencrypt 2>/dev/null || true
# 4. Xóa bản cục bộ cũ hơn KEEP_DAYS ngày
find "$DEST" -type f -name '*.gz' -mtime +"$KEEP_DAYS" -delete
# 5. Đẩy lên lưu trữ ngoài
rclone copy "$DEST" "$REMOTE" --transfers 2 --log-level INFO \
--log-file /var/log/backup-rclone.log
echo "Backup OK: $DATE"
sudo chmod 700 /usr/local/bin/backup-site.sh
sudo /usr/local/bin/backup-site.sh
ls -lh /var/backups/site
sudo rclone ls offsite:vps-backup
set -euo pipefail làm script dừng ngay khi một lệnh lỗi, kể cả lỗi trong pipe. Nhờ vậy bạn không đẩy một bản dump rỗng lên mây mà tưởng là thành công.
Bước 5: Xóa bản cũ trên lưu trữ ngoài
Vì dùng rclone copy, bản cũ trên mây không tự mất. Thêm vào cuối script để giữ 30 ngày:
rclone delete "$REMOTE" --min-age 30d
Nhiều dịch vụ lưu trữ đối tượng cũng có lifecycle rule tự xóa file cũ và tính năng khóa phiên bản. Dùng các tính năng này giúp bản sao lưu không bị xóa ngay cả khi VPS bị chiếm quyền.
Bước 6: Lập lịch bằng cron
sudo crontab -e
Thêm dòng sau để chạy lúc 2 giờ 15 sáng mỗi ngày:
15 2 * * * /usr/local/bin/backup-site.sh >> /var/log/backup-site.log 2>&1
Cron chạy với biến môi trường tối giản. Nếu rclone không được tìm thấy, khai báo đường dẫn đầy đủ (/usr/bin/rclone) hoặc thêm dòng PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ở đầu crontab.
Bước 7: Đồng bộ sang máy chủ khác bằng rsync (tùy chọn)
Nếu có VPS thứ hai, bạn có thể đẩy thư mục sao lưu qua SSH:
rsync -az -e "ssh -i /root/.ssh/backup_key" /var/backups/site/ backup@203.0.113.20:/srv/backup/example/
Dùng SSH key riêng, không có passphrase, chỉ cấp cho user backup trên máy đích có quyền ghi vào đúng thư mục đó.
Kiểm tra lại: thử khôi phục
Sao lưu chưa từng khôi phục thử thì chưa chắc dùng được. Định kỳ, hãy khôi phục lên một database tạm:
sudo rclone copy offsite:vps-backup/db-wp_example-2026-10-23_0215.sql.gz /tmp/restore/
sudo mariadb -e "CREATE DATABASE restore_test;"
zcat /tmp/restore/db-wp_example-2026-10-23_0215.sql.gz | sudo mariadb restore_test
sudo mariadb -e "SELECT COUNT(*) FROM restore_test.wp_posts;"
sudo mariadb -e "DROP DATABASE restore_test;"
Với file, giải nén ra thư mục tạm và kiểm tra:
mkdir -p /tmp/restore/files
tar -xzf /tmp/restore/files-2026-10-23_0215.tar.gz -C /tmp/restore/files
ls /tmp/restore/files/example.com/wp-content/uploads
Lỗi thường gặp và cách xử lý
Access denied for user 'backup'@'localhost'
Kiểm tra file /root/.my.cnf có đúng định dạng và quyền 600. Nếu chạy script bằng user khác root, file phải nằm trong thư mục home của user đó. Với MySQL 8, user sao lưu có thể cần thêm quyền PROCESS.
Cron không chạy hoặc chạy nhưng không có file
Xem log cron: grep CRON /var/log/syslog hoặc journalctl -u cron --since today. Đọc /var/log/backup-site.log để thấy lỗi của script.
rclone báo lỗi xác thực sau một thời gian
Token hết hạn hoặc khóa truy cập bị thu hồi. Chạy sudo rclone config reconnect offsite: với remote dùng OAuth, hoặc cập nhật khóa trong sudo rclone config.
Ổ đĩa VPS đầy vì bản sao lưu
Giảm KEEP_DAYS, loại trừ thêm thư mục cache, hoặc xóa bản cục bộ sau khi tải lên thành công. Kiểm tra dung lượng với du -sh /var/backups/site.