Chiến lược backup và restore VPS Linux sau sự cố

Sáng thứ Hai, khách nhắn "web sập". Bạn SSH vào thì thấy ổ đĩa đầy, MySQL không start, còn file thì... không biết bản nào là bản sạch. Đây là lúc chiến lược backup quyết định bạn mất 30 phút hay mất 3 ngày. Bài này đi qua cách phân tầng dữ liệu, dựng backup nhiều lớp, và quan trọng hơn: quy trình restore có kiểm thử trên VPS Linux, để lúc cần bạn không phải đoán.
- Nguyên tắc nền: 3-2-1 - 3 bản dữ liệu, 2 loại phương tiện khác nhau, 1 bản off-site.
- Snapshot không phải backup: nó chống sự cố thao tác sai, không chống mất cả ổ đĩa hay nhà cung cấp.
- Restore không kiểm thử = backup không tồn tại. Mỗi tháng phải dựng lại thử ít nhất một lần.
- Với VPS chạy database, backup logic (dump) luôn phải đi kèm backup vật lý.
Phân tầng dữ liệu trước khi chọn công cụ
Nhiều người cắm rsync cả ổ rồi yên tâm. Đến lúc cần restore mới thấy file rác, cache, log kéo theo làm bản backup nặng gấp ba mà lại thiếu cái quan trọng. Trước khi chọn công cụ, hãy phân loại dữ liệu trên VPS thành ba nhóm rõ ràng.
Nhóm stateless: code, container image, cấu hình Nginx, systemd unit, script. Nhóm này chủ yếu sinh từ git và config, backup chỉ cần vài chục MB, ưu tiên lưu dạng text để diff được. Nhóm stateful: database, upload của user, mail spool, file mà người dùng tạo ra. Đây là thứ không thể dựng lại từ đâu khác, phải backup thật kỹ và phải backup logic. Nhóm tái tạo được: cache, log cũ, /tmp, node_modules. Không cần backup, thậm chí nên loại trừ để bản backup gọn và restore nhanh.
| Nhóm dữ liệu | Ví dụ | Cách backup | Tần suất gợi ý |
|---|---|---|---|
| Stateless | Nginx config, code, systemd unit | git + rsync/text | Khi có thay đổi (CI/CD) |
| Stateful | MySQL, PostgreSQL, upload, mail | dump logic + snapshot | Hàng ngày hoặc realtime |
| Tái tạo được | Cache, log, /tmp | Loại trừ | Không |
Điểm mấu chốt: mỗi nhóm có RPO (mất tối đa bao nhiêu dữ liệu) và RTO (phục hồi trong bao lâu) khác nhau. Database có thể cần RPO 15 phút, còn config site có thể RPO 1 tuần cũng chẳng sao. Viết hai con số này ra giấy trước khi đụng đến công cụ.
Snapshot của nhà cung cấp: dùng đúng chỗ
Hầu hết nhà cung cấp VPS đều có snapshot ở tầng hypervisor. Đây là công cụ hữu ích nhất để chống thao tác sai: cài kernel hỏng, sửa firewalld xong tự khoá SSH, nâng cấp mà không rollback được. Trước mọi thao tác rủi ro, một snapshot là lưới an toàn gần như tức thời.
# Trước khi nâng cấp OS hoặc đổi kernel, tạo snapshot qua panel hoặc CLI của nhà cung cấp.
# Kiểm tra snapshot đã xong TRƯỚC khi thao tác tiếp.
# Ví dụ trên VPS thueVPS dùng panel: mục Snapshot, đặt tên có ngày giờ.
Nhưng đừng nhầm snapshot với backup. Snapshot thường nằm cùng hạ tầng, cùng tài khoản, và không phải nhà cung cấp nào cũng giữ lâu. Nhà cung cấp lỗi, tài khoản bị khoá, ổ đĩa vật lý hỏng lan sang bản snapshot = mất sạch. Quy tắc của mình: snapshot là lớp 1, chỉ giữ 24 đến 72 giờ gần nhất, và mọi thứ quan trọng phải có bản thứ hai tách ra ngoài.
Backup logic với mysqldump và pg_dump
Copy file dữ liệu của MySQL hay PostgreSQL khi service đang chạy là cách nhanh nhất để có một bản backup hỏng. InnoDB ghi trang liên tục, file ibdata1 copy ra có thể không nhất quán, restore vào là báo lỗi hoặc hỏng âm thầm. Với database, hãy dùng dump logic.
# MySQL trên Debian/Ubuntu: dump toàn bộ rồi nén
mysqldump --single-transaction --quick --routines --triggers \
--all-databases | gzip > /var/backups/mysql/all-$(date +%F-%H%M).sql.gz
# PostgreSQL, dùng pg_dumpall cho cụm, hoặc pg_dump từng DB
pg_dumpall -U postgres | gzip > /var/backups/pgsql/all-$(date +%F-%H%M).sql.gz
--single-transaction cho MySQL InnoDB tạo một điểm nhất quán mà không khoá bảng. Với PostgreSQL, pg_dumpall lấy cả role và tablespace, tiện khi dựng lại cụm từ con số 0. Đặt các lệnh này trong cron hoặc systemd timer, và nhớ đưa cron ra ngoài khung giờ cao điểm.
# /etc/cron.d/db-backup
30 2 * * * root /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
Kiểm tra file vừa tạo không rỗng, và quan trọng hơn: thử restore một lần ngay sau khi viết script. Một file .sql.gz 2GB mà giải nén ra lỗi giữa chừng là chuyện xảy ra thường xuyên hơn bạn tưởng.
Sao lưu file bằng rsync, có loại trừ đúng
Với thư mục upload, mail spool, code không nằm trong git, rsync vẫn là lựa chọn gọn, delta nhanh. Chìa khoá là file --exclude sạch, kẻo bạn copy cả cache và ổ log.
# /usr/local/bin/file-backup.sh
#!/usr/bin/env bash
set -euo pipefail
DEST=/var/backups/files
mkdir -p "$DEST"
rsync -aAXH --delete \
--exclude='.cache/' --exclude='*.log' --exclude='node_modules/' \
--exclude='/proc/' --exclude='/sys/' --exclude='/dev/' --exclude='/run/' \
/var/www/ /etc/nginx/ /etc/ssl/ "$DEST/"
Cờ -aAXH giữ quyền, ACL, xattr và hardlink. --delete giữ đích khớp nguồn nhưng cũng là con dao hai lưỡi: nếu nguồn bị xoá do tấn công, đích cũng bị xoá. Vì vậy rsync kiểu này chỉ dùng trong cụm ổ đĩa phụ hoặc kéo về một VPS lưu trữ riêng, không phải bản off-site riêng biệt.
Nếu dùng ZFS hoặc btrfs trên VPS, tận dụng snapshot tức thời, còn với ext4 thì đơn giản là rsync theo lịch. Cái nào cũng được, miễn bạn biết nguồn, biết đích, và biết nó chạy lần cuối lúc nào.
Repo off-site với restic và mã hoá
Đây là lớp quan trọng nhất và cũng hay bị bỏ qua nhất: một bản backup nằm ở nơi khác, đã mã hoá, không phụ thuộc nhà cung cấp VPS. restic làm việc này rất tốt: dedup, mã hoá, upload lên S3 hoặc bất kỳ object storage tương thích, và có thể kiểm tra tính toàn vẹn của repo.
# Cài restic (Debian/Ubuntu)
apt update && apt install -y restic
# Khởi tạo repo trên object storage S3 tương thích
export RESTIC_PASSWORD='mat-khau-manh-o-day'
restic -r s3:s3.example.com/backup-vps init
# Backup database dump + config, loại trừ cache
restic -r s3:s3.example.com/backup-vps backup \
/var/backups/mysql /etc/nginx /var/www \
--exclude='*.log' --exclude='.cache/'
# Kiểm tra repo còn nguyên vẹn (nên chạy hàng tuần)
restic -r s3:s3.example.com/backup-vps check
restic -r s3:s3.example.com/backup-vps snapshots
Đừng quên lưu RESTIC_PASSWORD ở đâu đó ngoài máy chủ. Mất mật khẩu là mất luôn repo, restic không có cơ chế khôi phục. Mình thường để trong password manager và một bản in ở két. Nghe cổ điển nhưng đúng. Cũng nên dùng restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune để dọn dần, tránh repo phình vô hạn.
Quy trình restore: đúng thứ tự mới nhanh
Restore là bài kiểm tra thật của cả hệ thống backup. Nhiều người làm được backup nhưng tới lúc restore lại làm sai thứ tự, kéo dài downtime gấp đôi. Trình tự dưới đây là thứ mình dùng khi dựng lại một VPS Linux sau sự cố.
- Cô lập máy cũ để không ghi thêm dữ liệu, hoặc tắt service ghi.
- Dựng VPS mới cùng distro, cùng phiên bản, cài sẵn LEMP/LEMP tùy tải.
- Restore config trước (Nginx, PHP-FPM, systemd) từ restic hoặc rsync.
- Restore code từ git hoặc bản file backup.
- Restore database bằng dump, import rồi kiểm tra bảng và row count.
- Restore dữ liệu người dùng (upload, mail) sau cùng.
- Đổi DNS hoặc IP khi mọi thứ đã pass smoke test.
Nếu dữ liệu lớn, bạn có thể kéo bản sự cố về một VPS lưu trữ riêng chạy NVMe để làm nơi dàn dựng và kiểm tra trước, rồi mới chuyển. Cách này cũng tiện khi cần một VPS Linux riêng cho môi trường staging restore.
Kiểm thử restore định kỳ và xử lý lỗi thường gặp
Restore chưa test thì chưa phải backup. Đặt lịch mỗi tháng một lần, dựng môi trường tạm, restore từ repo, chạy vài câu kiểm tra. Chỉ cần 30 phút, nhưng nó cho bạn biết script còn chạy không, repo có khoá hay quên rotate mật khẩu không.
# Kiểm tra nhanh sau restore: MySQL đếm bảng, PostgreSQL kiểm tra size
mysql -e "SELECT COUNT(*) AS tbls FROM information_schema.tables;" mysql
psql -U postgres -c "SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database;"
# Xem log dãn cách
journalctl -u cron --since "1 day ago" | grep -i backup
Vài lỗi hay gặp khi restore trên VPS Linux:
- Dump lớn bị timeout khi import. Tách file, tăng
max_allowed_packet, hoặc dùng--compresshợp lý. - restic báo không khớp mật khẩu, thường do biến
RESTIC_PASSWORDkhông được export trong cron, khác shell môi trường. - Sequence trong PostgreSQL bị lệch sau import, cần
setvallại để không lỗi unique key. - File quyền đổi sau rsync vì thiếu
-aAXHhoặc chạy với user khác.
Đặt chiến lược vào một trang giấy
Công cụ chỉ là công cụ. Thứ giúp bạn sống sót sau sự cố là một tài liệu ngắn ghi rõ: dữ liệu nào được backup, ở đâu, tần suất nào, ai giữ mật khẩu, và restore như thế nào. Dán nó vào runbook, kiểm tra mỗi quý.
Với các dự án nhỏ hoặc môi trường staging, bạn không cần cả bộ máy nặng. Một VPS NVMe có snapshot sẵn, một VPS phụ chạy restic hoặc rsync, một bucket S3 tương thích là đã phủ được nguyên tắc 3-2-1. Cần hạ tầng để tự dựng cả hai đầu, có thể tham khảo thuê VPS đặt tại Việt Nam với IPv4 riêng và quyền root đầy đủ. Bài viết giới hạn ở backup; phần kế hoạch phục hồi toàn diện hơn thì kế hoạch khôi phục VPS sau sự cố sẽ bổ sung góc vận hành. Còn nếu bạn cần lưu bản backup dung lượng lớn lâu dài và muốn tự kiểm soát phần cứng, một máy chủ riêng hoặc thuê chỗ đặt máy chủ có thể là bước tiếp theo hợp lý.
Câu hỏi thường gặp
Snapshot có thay thế được backup không?
Không. Snapshot nằm cùng hạ tầng và cùng tài khoản nhà cung cấp, không chống được lỗi nhà cung cấp, khoá tài khoản hay xoá nhầm cả ổ. Nó chỉ là lớp 1 chống thao tác sai. Bản off-site (restic, rsync ra ngoài) mới là bản bạn sống nhờ khi mọi thứ đổ.
VPS chạy database thì backup thế nào cho đúng?
Dùng dump logic (mysqldump --single-transaction cho InnoDB, pg_dumpall cho PostgreSQL), không copy file dữ liệu khi service đang chạy. Dump nén rồi đẩy vào repo restic hoặc off-site. Kiểm tra lại file sau khi tạo, đừng tin vào size trên màn hình.
Bao lâu nên kiểm thử restore một lần?
Với hệ thống nghiêm túc, mỗi tháng một lần. Với dự án nhỏ, tối thiểu mỗi quý. Kiểm thử gồm dựng VPS tạm, restore nguyên bộ, chạy vài câu query đối chiếu row count rồi xoá. Nếu chưa từng test, coi như bạn chưa có backup.
Mất mật khẩu restic thì xử lý sao?
Không. restic mã hoá đầu cuối, mất mật khẩu là mất dữ liệu, không có backdoor. Cách riêng biệt là giữ mật khẩu ở password manager và một bản ngoài máy chủ. Đừng để biến RESTIC_PASSWORD chỉ tồn tại trong cron của VPS đang chạy.
Có nên backup cả log và cache không?
Không. Log và cache thuộc nhóm tái tạo được, backup chỉ làm bản nặng, restore chậm và dễ lỗi. Loại trừ chúng bằng --exclude. Chỉ giữ log nếu bạn thật sự cần để điều tra sự cố, và khi đó dùng log tập trung tách riêng thay vì nhét vào bản backup chính.
Bài viết liên quan
- Kế hoạch khôi phục VPS sau sự cố bảo vệ dữ liệu toàn diện
- Cách backup VPS trước khi nâng cấp an toàn
- Cách tạo snapshot và khôi phục VPS an toàn
- Hướng dẫn backup tự động VPS lên S3 với restic


