❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.
Qua những bài trước, mình đã cùng bạn xây dựng nhiều lớp bảo mật cho VPS Linux: SSH tăng cường bảo mật, firewall, tự động cập nhật, bảo vệ kernel, Docker, web server, database, monitoring, v.v. Nhưng dù làm tốt đến mấy, luôn có khả năng mọi thứ sụp đổ. Server bị hack, ổ cứng hỏng, nhà cung cấp gặp sự cố, hoặc đơn giản là ai đó chạy nhầm lệnh rm -rf /.

Lúc đó, backup là thứ duy nhất cứu bạn. Bài cuối cùng của serie bảo mật VPS Linux này sẽ tập trung vào mảng mà ít người chú ý đúng mức: bảo mật backup, phục hồi sự cố plan, và xử lý sự cố. Nếu bạn đã biết cách backup cơ bản (rsync, cron, tar), bài này sẽ đưa bạn lên một tầm khác.
Backup trong bối cảnh bảo mật
Backup truyền thống thường chỉ nghĩ đến chuyện phòng hỏng phần cứng hoặc xóa nhầm file. Nhưng trong bảo mật, backup có vai trò khác: đó là lớp phòng thủ cuối cùng.
Kịch bản thực tế: attacker chiếm được root trên VPS của bạn, cài ransomware mã hóa toàn bộ dữ liệu, rồi đòi tiền chuộc. Nếu backup của bạn nằm ngay trên server đó (hoặc trên server khác nhưng dùng chung credential), attacker xóa luôn backup. Lúc này bạn mất sạch.
Vậy nên backup cho bảo mật cần thỏa mãn mấy điều kiện mà backup thông thường không quan tâm:
- Mã hóa (encrypted): Dữ liệu backup phải được encrypt, dù ai lấy được file backup cũng không đọc được.
- Bất biến (immutable): Backup phải được bảo vệ sao cho attacker không thể xóa hoặc sửa, kể cả khi đã chiếm server chính.
- Tách biệt (isolated): Credential truy cập backup phải khác hoàn toàn với credential trên server. Mất server không đồng nghĩa mất backup.
- Offsite: Backup phải ở một nơi hoàn toàn khác, khác provider nếu có thể.
- Đã test: Backup chưa test restore thì coi như chưa có backup.
⚠️ Sai lầm phổ biến nhất: backup nằm trên cùng server hoặc cùng account cloud. Attacker chiếm server là xóa được cả backup. Luôn tách credential và vị trí lưu trữ.
Encrypted backup với restic
restic là công cụ backup hiện đại, mã hóa mặc định (AES-256), hỗ trợ deduplication, và làm việc được với nhiều loại storage (local, SFTP, S3, B2, v.v.). So với việc tự tar rồi gpg encrypt, restic tiện hơn rất nhiều vì nó xử lý cả incremental backup lẫn encryption trong một bước.
Cài đặt restic
Ubuntu/Debian:
sudo apt update
sudo apt install -y restic
AlmaLinux/Rocky Linux:
sudo dnf install -y epel-release
sudo dnf install -y restic
💡 Phiên bản restic trong repo distro đôi khi cũ. Nếu cần bản mới nhất, tải binary trực tiếp từ GitHub releases rồi đặt vào /usr/local/bin/.
Khởi tạo repository và backup
Với restic, bạn cần khởi tạo một repository (nơi lưu backup) trước. Ví dụ backup qua SFTP tới server khác:
# Đặt password cho repository — restic dùng password này để encrypt toàn bộ data
export RESTIC_PASSWORD="your-strong-backup-password"
# Khởi tạo repository trên backup server qua SFTP
restic init -r sftp:backup-user@backup-server:/data/restic-repo
# Backup thư mục web và database
restic backup -r sftp:backup-user@backup-server:/data/restic-repo \
/var/www /var/lib/mysql /etc/nginx /etc/letsencrypt
# Xem danh sách snapshot
restic snapshots -r sftp:backup-user@backup-server:/data/restic-repo
Mỗi lần chạy backup, restic chỉ upload phần thay đổi (deduplication), nên lần 2 trở đi sẽ rất nhanh. Toàn bộ dữ liệu được encrypt bằng AES-256 với password bạn cung cấp, kể cả metadata.
Restore từ restic
# Restore snapshot mới nhất vào thư mục /tmp/restore
restic restore latest -r sftp:backup-user@backup-server:/data/restic-repo \
--target /tmp/restore
# Restore một snapshot cụ thể (dùng ID từ lệnh snapshots)
restic restore abc12345 -r sftp:backup-user@backup-server:/data/restic-repo \
--target /tmp/restore
# Chỉ restore 1 thư mục cụ thể
restic restore latest -r sftp:backup-user@backup-server:/data/restic-repo \
--target /tmp/restore --include /var/www
Dọn dẹp snapshot cũ
Giữ quá nhiều snapshot tốn dung lượng. Dùng policy để tự động dọn:
# Giữ 7 bản daily, 4 bản weekly, 6 bản monthly
restic forget -r sftp:backup-user@backup-server:/data/restic-repo \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
Backup thủ công với GPG (phương án thay thế)
Nếu bạn muốn giữ cách làm đơn giản với tar, thêm lớp GPG encryption để bảo vệ file backup:
# Tạo backup tar rồi encrypt bằng GPG symmetric
tar czf - /var/www /etc/nginx | gpg --symmetric --cipher-algo AES256 \
--batch --passphrase-file /root/.backup-passphrase \
-o /tmp/backup-$(date +%F).tar.gz.gpg
# Decrypt khi cần restore
gpg --decrypt --batch --passphrase-file /root/.backup-passphrase \
/tmp/backup-2025-03-16.tar.gz.gpg | tar xzf - -C /tmp/restore/
ℹ️ File passphrase (/root/.backup-passphrase) phải được bảo vệ riêng. Đừng để nó trên cùng server với backup. Lưu một bản ở nơi an toàn khác (password manager, USB offline).
Immutable backup: Backup mà attacker không xóa được
Mã hoá giúp attacker không đọc được backup, nhưng vẫn xóa được nếu có quyền truy cập. Immutable backup giải quyết vấn đề này: một khi dữ liệu đã ghi vào, không ai có thể xóa hay sửa trong khoảng thời gian nhất định.
Tách credential backup khỏi server chính
Nguyên tắc quan trọng nhất: server chính chỉ có quyền ghi backup, không có quyền xóa. Làm thế nào?
- Trên backup server: Tạo user riêng cho backup, chỉ cho phép ghi vào thư mục backup, không cho phép xóa file cũ.
- SSH key riêng: Server chính dùng một SSH key chỉ để backup, key này bị giới hạn quyền bằng
authorized_keystrên backup server. - Credential xóa backup: Chỉ lưu ở nơi an toàn (password manager, không trên bất kỳ server nào trong hệ thống).
Append-only mode với restic
restic hỗ trợ append-only mode qua REST server. Với mode này, client chỉ có thể tạo snapshot mới, không thể xóa snapshot cũ hay chạy prune.
Trên backup server, chạy restic REST server:
# Cài restic REST server
wget https://github.com/restic/rest-server/releases/download/v0.13.0/rest-server_0.13.0_linux_amd64.gz
gunzip rest-server_0.13.0_linux_amd64.gz
chmod +x rest-server_0.13.0_linux_amd64
sudo mv rest-server_0.13.0_linux_amd64 /usr/local/bin/rest-server
# Chạy với append-only mode
rest-server --path /data/restic-repo --append-only --listen :8000
Trên VPS chính, backup như bình thường nhưng trỏ vào REST server:
export RESTIC_PASSWORD="your-strong-backup-password"
# Init và backup qua REST server
restic init -r rest:http://backup-server:8000/
restic backup -r rest:http://backup-server:8000/ /var/www /etc/nginx
Client có thể tạo snapshot mới bình thường, nhưng không thể chạy restic forget hoặc restic prune qua REST server. Việc dọn dẹp snapshot cũ phải thực hiện trực tiếp trên backup server, nơi mà attacker không có quyền truy cập.
Object Lock trên S3-compatible storage
Nếu bạn dùng object storage (AWS S3, Backblaze B2, Wasabi), bật Object Lock (WORM: Write Once Read Many). Khi đã set retention period, kể cả root account cũng không xóa được object trong thời gian đó.
# Ví dụ tạo bucket S3 với Object Lock
aws s3api create-bucket --bucket my-backup-bucket \
--object-lock-enabled-for-bucket \
--region ap-southeast-1 \
--create-bucket-configuration LocationConstraint=ap-southeast-1
# Set default retention 30 ngày (Governance mode)
aws s3api put-object-lock-configuration --bucket my-backup-bucket \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 30
}
}
}'
ℹ️ Governance mode cho phép user có quyền đặc biệt bypass lock. Compliance mode thì không ai bypass được, kể cả root account. Chọn Compliance nếu bạn cần bảo vệ tuyệt đối, nhưng cẩn thận vì bạn cũng không xóa được nếu cần.
Bảo mật kết nối backup (Offsite Security)
Backup offsite nghĩa là dữ liệu phải di chuyển qua mạng. Đoạn đường này cần bảo vệ kỹ.
SSH key riêng cho backup
Tạo SSH key pair riêng, chỉ dùng cho backup. Trên backup server, giới hạn key này chỉ chạy được rrsync (restricted rsync):
# Trên VPS chính: tạo key riêng cho backup
ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N "" -C "backup-only-key"
# Trên backup server: thêm vào authorized_keys với giới hạn
# File: /home/backup-user/.ssh/authorized_keys
command="/usr/bin/rrsync -wo /data/backups/",restrict ssh-ed25519 AAAA...key... backup-only-key
Với cấu hình trên, SSH key backup chỉ có thể ghi file vào /data/backups/. Không thể login shell, không thể đọc file khác, không thể chạy lệnh tùy ý. Kể cả attacker lấy được key này cũng chỉ ghi được vào thư mục backup, không làm gì thêm.
💡 rrsync thường đi kèm gói rsync. Trên Ubuntu/Debian kiểm tra tại /usr/bin/rrsync, trên AlmaLinux/Rocky có thể ở /usr/share/doc/rsync/support/rrsync (cần copy ra và chmod +x).
Firewall trên backup server
Backup server chỉ cần mở SSH port cho IP của VPS chính, đóng hết phần còn lại:
# UFW (Ubuntu/Debian)
sudo ufw default deny incoming
sudo ufw allow from 203.0.113.10 to any port 22 # IP của VPS chính
sudo ufw enable
# firewalld (AlmaLinux/Rocky)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="22" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-service=ssh # Bỏ SSH mở toàn bộ
sudo firewall-cmd --reload
⚠️ Trước khi áp firewall rule, đảm bảo bạn có cách truy cập backup server khác (console từ provider, IP phụ) phòng trường hợp tự khóa chính mình.
Kế hoạch phục hồi sự cố (DRP)
Có backup mà không có kế hoạch phục hồi thì lúc gặp sự cố sẽ loay hoay không biết bắt đầu từ đâu. DRP (Disaster Recovery Plan – Kế hoạch khôi phục thảm hoạ) giúp bạn biết chính xác phải làm gì, theo thứ tự nào, ai chịu trách nhiệm gì.
RTO và RPO
Hai khái niệm cốt lõi trong DRP:
- RTO (Recovery Time Objective): Bao lâu để hệ thống hoạt động trở lại sau sự cố? Ví dụ: RTO = 2 giờ nghĩa là sau 2 giờ website phải online lại.
- RPO (Recovery Point Objective): Bạn chấp nhận mất tối đa bao nhiêu dữ liệu? Ví dụ: RPO = 24 giờ nghĩa là mất tối đa 1 ngày data (backup hàng ngày). RPO = 1 giờ thì cần backup mỗi giờ.
RTO và RPO quyết định bạn cần đầu tư bao nhiêu cho hạ tầng backup. RPO nhỏ (ít mất data) đòi hỏi backup thường xuyên hơn, tốn tài nguyên hơn. RTO nhỏ (phục hồi nhanh) cần quy trình rõ ràng, có thể cần server dự phòng sẵn.
Bảng DRP mẫu cho VPS web server
Đây là bảng DRP mẫu cho một VPS chạy web server (Nginx + PHP + MySQL/MariaDB). Bạn cần điều chỉnh theo hệ thống thực tế:
| Thành phần | RPO | RTO | Phương pháp backup | Vị trí backup |
|---|---|---|---|---|
| Database (MySQL/MariaDB) | 1 giờ | 30 phút | mysqldump mỗi giờ + restic | Backup server (SFTP) |
| Web files (/var/www) | 24 giờ | 1 giờ | restic daily | Backup server + S3 |
| Config (Nginx, PHP, SSL) | Khi thay đổi | 30 phút | Git repo + restic | Git remote + Backup server |
| SSL certificates | Khi renew | 15 phút | restic + certbot re-issue | Backup server |
| Toàn bộ server | 1 tuần | 2 giờ | VPS snapshot (provider) | Provider infrastructure |
💡 Config server (Nginx, PHP, crontab, v.v.) nên được quản lý bằng Git. Khi cần rebuild server mới, clone repo về và chạy script setup là xong. Nhanh hơn nhiều so với restore từ backup rồi sửa tay.
Script backup tự động theo DRP
Dựa trên bảng DRP ở trên, đây là ví dụ cron schedule:
# /etc/cron.d/backup-drp
# Database: mỗi giờ
0 * * * * root /opt/scripts/backup-db.sh >> /var/log/backup-db.log 2>&1
# Web files + config: mỗi ngày lúc 3:00
0 3 * * * root /opt/scripts/backup-files.sh >> /var/log/backup-files.log 2>&1
# Dọn snapshot cũ: mỗi Chủ nhật lúc 5:00
0 5 * * 0 root /opt/scripts/backup-prune.sh >> /var/log/backup-prune.log 2>&1
Và script backup database:
#!/bin/bash
# /opt/scripts/backup-db.sh
export RESTIC_PASSWORD_FILE="/root/.restic-password"
REPO="sftp:backup-user@backup-server:/data/restic-repo"
DUMP_DIR="/tmp/db-dumps"
mkdir -p "$DUMP_DIR"
# Dump tất cả database
mysqldump --all-databases --single-transaction --routines --triggers \
> "$DUMP_DIR/all-databases.sql"
# Backup bằng restic
restic backup -r "$REPO" "$DUMP_DIR" --tag database --tag hourly
# Cleanup
rm -rf "$DUMP_DIR"
echo "[$(date)] Database backup completed"
Xử lý sự cố: Xử lý khi bị hack
Phát hiện server bị hack là lúc dễ hoảng nhất. Nhiều người phản ứng đầu tiên là xóa sạch rồi cài lại. Nhưng nếu không có quy trình rõ ràng, bạn có thể xóa mất bằng chứng (evidence), không biết attacker vào bằng cách nào, và để lỗ hổng mở cho lần sau.
Quy trình 7 bước
Khi phát hiện (hoặc nghi ngờ) server bị xâm nhập, làm theo thứ tự:
Bước 1: Isolate (Cách ly ngay)
Ngắt server khỏi mạng để attacker không tiếp tục thao tác và không dùng server bạn tấn công nơi khác.
# Cách nhanh nhất: drop toàn bộ traffic ra vào
sudo iptables -P INPUT DROP
sudo iptables -P OUTPUT DROP
sudo iptables -P FORWARD DROP
# Cho phép chỉ IP quản trị của bạn
sudo iptables -I INPUT -s YOUR_ADMIN_IP -j ACCEPT
sudo iptables -I OUTPUT -d YOUR_ADMIN_IP -j ACCEPT
⚠️ Nếu đang SSH vào server, thêm rule cho phép IP của mình TRƯỚC khi drop all. Nếu không, bạn sẽ bị đá ra ngay lập tức.
Bước 2: Snapshot hiện trạng
Giữ nguyên hiện trạng để phân tích sau. Tạo snapshot qua VPS provider nếu có thể, hoặc dump những thông tin quan trọng:
# Tạo thư mục lưu evidence
mkdir -p /tmp/incident-$(date +%F)
cd /tmp/incident-$(date +%F)
# Lưu process đang chạy
ps auxwwf > processes.txt
# Lưu network connections
ss -tulnp > network-connections.txt
ss -anp > all-sockets.txt
# Lưu user đang login
w > logged-in-users.txt
last -50 > recent-logins.txt
# Lưu crontab của tất cả user
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u "$user" -l 2>/dev/null > "crontab-$user.txt"
done
# Lưu file mới bị thay đổi (7 ngày gần đây)
find / -mtime -7 -type f -not -path '/proc/*' -not -path '/sys/*' \
2>/dev/null > recently-modified-files.txt
# Lưu history
cp /root/.bash_history root-bash-history.txt 2>/dev/null
# Kiểm tra authorized_keys bất thường
find / -name "authorized_keys" -exec echo "=== {} ===" \; -exec cat {} \; \
> all-authorized-keys.txt 2>/dev/null
Bước 3: Đánh giá mức độ
Xem xét evidence để hiểu: attacker vào bằng đường nào, đã ở trong bao lâu, có quyền gì, đã làm những gì. Mấy câu hỏi cần trả lời:
- Có process lạ nào đang chạy không? (crypto miner, reverse shell, v.v.)
- Có file mới xuất hiện ở
/tmp,/dev/shm,/var/tmpkhông? - Authorized keys có key lạ nào được thêm vào không?
- Crontab có job lạ nào không?
- Log SSH, web server có dấu vết gì bất thường?
Bước 4: Quyết định Rebuild hay Clean
Đây là quyết định quan trọng nhất:
| Tình huống | Nên chọn | Lý do |
|---|---|---|
| Attacker có quyền root | Rebuild | Không thể tin bất kỳ file nào trên server. Có thể đã cài rootkit, sửa binary hệ thống. |
| Chỉ web app bị exploit (upload shell, SQL injection) | Clean có thể được | Phạm vi hạn chế, chỉ cần dọn web shell, patch lỗ hổng, đổi credential. |
| Không xác định được phạm vi | Rebuild | Nếu không chắc chắn mức độ xâm nhập, cách an toàn nhất là rebuild. |
| Crypto miner chạy trên server | Rebuild | Miner thường đi kèm persistence mechanism, khó dọn sạch. |
🚨 Quy tắc vàng: Nếu attacker đã có root, luôn rebuild. Không có cách nào đảm bảo 100% đã dọn sạch rootkit hoặc backdoor ẩn trong binary hệ thống.
Bước 5: Rebuild / Clean server
Nếu rebuild: Cài lại OS từ đầu, cấu hình lại theo DRP (đây là lúc Git repo chứa config phát huy tác dụng). Nếu clean: Xóa file độc hại, patch lỗ hổng, đổi tất cả credential.
Bước 6: Harden
Trước khi đưa server lên lại, áp dụng tăng cường bảo mật để chặn hướng tấn công đã dùng. Review lại toàn bộ các bài trong serie này. Đặc biệt chú ý đến điểm yếu mà attacker đã khai thác.
Bước 7: Restore data
Restore dữ liệu từ backup, nhưng cẩn thận: chỉ restore data (database, uploaded files), không restore binary hay config từ backup vì có thể đã bị nhiễm. Config nên lấy từ Git repo (phiên bản clean).
# Restore database từ backup (chọn snapshot TRƯỚC thời điểm bị hack)
restic restore SNAPSHOT_ID -r sftp:backup-user@backup-server:/data/restic-repo \
--target /tmp/restore --include /tmp/db-dumps
# Import database
mysql < /tmp/restore/tmp/db-dumps/all-databases.sql
# Restore web content (chỉ uploaded files, không lấy code)
restic restore SNAPSHOT_ID -r sftp:backup-user@backup-server:/data/restic-repo \
--target /tmp/restore --include /var/www/html/wp-content/uploads
Test restore: Backup chưa test thì chưa phải backup
Mình từng thấy nhiều trường hợp backup chạy đều đặn mỗi ngày suốt cả năm, đến lúc cần restore mới phát hiện: file backup bị corrupt, password encrypt bị quên, hoặc backup thiếu thư mục quan trọng. Lúc đó thì đã muộn.
Monthly restore drill
Mỗi tháng, bỏ ra 1-2 giờ để test restore. Quy trình gợi ý:
- Tạo một VPS tạm (hoặc dùng container Docker trên máy local)
- Restore backup mới nhất vào VPS tạm
- Kiểm tra database import thành công, query được data mới nhất
- Kiểm tra web files đầy đủ, website load được
- Ghi lại thời gian restore thực tế (so sánh với RTO)
- Ghi lại data mới nhất trong backup (so sánh với RPO)
- Xóa VPS tạm sau khi test xong
Script automated restore test
Tự động hóa việc test restore bằng script chạy hàng tháng. Script này restore backup, kiểm tra vài điều kiện cơ bản, rồi gửi alert kết quả:
#!/bin/bash
# /opt/scripts/test-restore.sh
# Chạy monthly: 0 4 1 * * root /opt/scripts/test-restore.sh
export RESTIC_PASSWORD_FILE="/root/.restic-password"
REPO="sftp:backup-user@backup-server:/data/restic-repo"
RESTORE_DIR="/tmp/restore-test-$(date +%F)"
REPORT="/tmp/restore-report-$(date +%F).txt"
ERRORS=0
echo "=== Restore Test Report $(date) ===" > "$REPORT"
# 1. Restore
echo "Restoring latest snapshot..." >> "$REPORT"
restic restore latest -r "$REPO" --target "$RESTORE_DIR" >> "$REPORT" 2>&1
if [ $? -ne 0 ]; then
echo "FAIL: Restore failed!" >> "$REPORT"
ERRORS=$((ERRORS + 1))
fi
# 2. Kiểm tra database dump tồn tại
if [ -f "$RESTORE_DIR/tmp/db-dumps/all-databases.sql" ]; then
SIZE=$(stat -c%s "$RESTORE_DIR/tmp/db-dumps/all-databases.sql")
echo "OK: Database dump found, size: $SIZE bytes" >> "$REPORT"
if [ "$SIZE" -lt 1000 ]; then
echo "WARN: Database dump suspiciously small!" >> "$REPORT"
ERRORS=$((ERRORS + 1))
fi
else
echo "FAIL: Database dump not found!" >> "$REPORT"
ERRORS=$((ERRORS + 1))
fi
# 3. Kiểm tra web files
if [ -d "$RESTORE_DIR/var/www" ]; then
FILE_COUNT=$(find "$RESTORE_DIR/var/www" -type f | wc -l)
echo "OK: Web files found, $FILE_COUNT files" >> "$REPORT"
else
echo "FAIL: Web files not found!" >> "$REPORT"
ERRORS=$((ERRORS + 1))
fi
# 4. Kiểm tra config
for cfg in etc/nginx etc/letsencrypt; do
if [ -d "$RESTORE_DIR/$cfg" ]; then
echo "OK: $cfg found" >> "$REPORT"
else
echo "WARN: $cfg not found" >> "$REPORT"
fi
done
# Tổng kết
echo "" >> "$REPORT"
if [ "$ERRORS" -eq 0 ]; then
echo "RESULT: ALL PASSED ✓" >> "$REPORT"
else
echo "RESULT: $ERRORS ERROR(S) FOUND ✗" >> "$REPORT"
fi
# Cleanup
rm -rf "$RESTORE_DIR"
# Gửi report (thay bằng cách notify phù hợp)
cat "$REPORT"
# Ví dụ gửi qua Telegram:
# curl -s "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
# -d chat_id="$CHAT_ID" -d text="$(cat $REPORT)"
Backup monitoring: Phát hiện sớm khi backup fail
Backup âm thầm fail là tình huống nguy hiểm nhất. Cron job lỗi, disk full, network timeout... tất cả đều có thể làm backup ngừng chạy mà bạn không hay biết. Script monitoring đơn giản sau sẽ kiểm tra backup có tồn tại, có mới, và kích thước có hợp lý hay không:
#!/bin/bash
# /opt/scripts/check-backup.sh
# Chạy mỗi ngày: 0 8 * * * root /opt/scripts/check-backup.sh
export RESTIC_PASSWORD_FILE="/root/.restic-password"
REPO="sftp:backup-user@backup-server:/data/restic-repo"
MAX_AGE_HOURS=26 # Alert nếu snapshot mới nhất > 26 giờ
ALERT_CMD="echo" # Thay bằng lệnh gửi notification thực tế
# Lấy thời gian snapshot mới nhất
LATEST=$(restic snapshots -r "$REPO" --json --latest 1 2>/dev/null)
if [ -z "$LATEST" ] || [ "$LATEST" = "[]" ]; then
$ALERT_CMD "🚨 BACKUP ALERT: No snapshots found in repository!"
exit 1
fi
# Parse thời gian snapshot
SNAPSHOT_TIME=$(echo "$LATEST" | python3 -c "
import json, sys
from datetime import datetime, timezone
data = json.load(sys.stdin)
if data:
t = data[0]['time'][:19]
print(t)
")
# Tính tuổi snapshot (giờ)
SNAPSHOT_EPOCH=$(date -d "$SNAPSHOT_TIME" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
AGE_HOURS=$(( (NOW_EPOCH - SNAPSHOT_EPOCH) / 3600 ))
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
$ALERT_CMD "🚨 BACKUP ALERT: Latest snapshot is ${AGE_HOURS}h old (threshold: ${MAX_AGE_HOURS}h). Last backup: $SNAPSHOT_TIME"
exit 1
fi
# Kiểm tra integrity nhanh (không download data, chỉ check metadata)
restic check -r "$REPO" --read-data-subset=1/100 > /dev/null 2>&1
if [ $? -ne 0 ]; then
$ALERT_CMD "🚨 BACKUP ALERT: Repository integrity check failed!"
exit 1
fi
echo "[$(date)] Backup check OK. Latest snapshot: ${AGE_HOURS}h ago"
💡 Phần ALERT_CMD bạn thay bằng cách gửi notification phù hợp: Telegram bot, email qua msmtp, hoặc webhook tới Slack/Discord. Quan trọng là phải gửi được alert khi backup fail, chứ log file thì chẳng ai đọc hàng ngày.
VPS provider snapshots
Hầu hết VPS provider (DigitalOcean, Vultr, Linode, Hetzner, AZDIGI...) đều cung cấp tính năng snapshot. Đây là bản chụp nguyên trạng toàn bộ VPS tại một thời điểm, bao gồm cả OS, config, data.
Khi nào nên dùng snapshot của provider?
- Trước khi update/upgrade lớn: Upgrade OS, update kernel, thay đổi config hệ thống. Snapshot trước, nếu hỏng thì rollback nhanh.
- Trước khi thử nghiệm: Test config mới, cài phần mềm mới. Snapshot để có đường lùi.
- Backup định kỳ nhanh: Tuần một lần snapshot để có bản full backup dự phòng.
Hạn chế cần biết
- Không phải offsite backup: Snapshot nằm trên hạ tầng của provider. Nếu provider gặp sự cố lớn (datacenter cháy, sập), snapshot cũng mất.
- Không encrypt: Provider có thể truy cập data trong snapshot. Nếu bạn có dữ liệu nhạy cảm, đây là vấn đề.
- Tốn dung lượng và tiền: Mỗi snapshot chiếm dung lượng bằng disk VPS. Giữ nhiều snapshot sẽ tốn phí.
- Restore chậm với data lớn: Restore snapshot 100GB mất thời gian đáng kể.
- Không granular: Không thể restore riêng 1 file hay 1 database. Phải restore nguyên VPS.
ℹ️ Snapshot của provider là bổ sung tốt, nhưng không thay thế được backup offsite tự quản lý. Dùng snapshot cho tiện lợi ngắn hạn (rollback nhanh), dùng restic/rsync cho backup dài hạn đáng tin cậy.
Tổng kết serie bảo mật VPS Linux
Qua 12 bài viết, mình đã cùng bạn đi qua toàn bộ các lớp bảo mật cho VPS Linux, từ nền tảng đến nâng cao. Cùng nhìn lại:
- Tổng quan bảo mật VPS: Hiểu mô hình phòng thủ nhiều lớp, tư duy bảo mật cơ bản.
- SSH Tăng cường bảo mật: Tắt password auth, đổi port, dùng key, giới hạn user.
- User và Permission: Nguyên tắc least privilege, sudo config, umask.
- Firewall: UFW/firewalld, chỉ mở port cần thiết, giới hạn tần suất.
- CrowdSec/Fail2ban: Tự động phát hiện và chặn dò mật khẩu, scan.
- Tự động cập nhật: unattended-upgrades, dnf-automatic, giảm thời gian lộ lỗ hổng.
- Bảo mật Kernel: Sysctl tăng cường bảo mật, disable module không dùng, ASLR.
- Docker Security: Daemon, image, runtime, giới hạn quyền container.
- Web Server Tăng cường bảo mật: Nginx/Apache security headers, TLS config, giới hạn request.
- Database Security: MySQL/MariaDB tăng cường bảo mật, user privileges, encrypt connections.
- Monitoring và Audit: Log tập trung, audit trail, phát hiện bất thường.
- Backup và Phục hồi sự cố (bài này): Encrypted backup, immutable backup, DRP, xử lý sự cố.
Checklist tổng hợp bảo mật VPS
Đây là checklist rút gọn để bạn review nhanh server mình đã cover được những gì:
| Hạng mục | Kiểm tra | Bài |
|---|---|---|
| SSH | Key-only auth, port đổi, root login disabled | #2 |
| Users | Không dùng root trực tiếp, sudo có log | #3 |
| Firewall | Chỉ mở port cần thiết, default deny | #4 |
| IDS/IPS | CrowdSec hoặc Fail2ban đang chạy, ban list active | #5 |
| Updates | Auto update security patches bật, kernel update định kỳ | #6 |
| Kernel | Sysctl hardened, ASLR on, module không dùng disabled | #7 |
| Docker | Rootless hoặc giới hạn quyền, image scan, no privileged | #8 |
| Web Server | Security headers, TLS 1.2+, giới hạn tần suất | #9 |
| Database | Không remote root, user riêng per-app, SSL connections | #10 |
| Monitoring | Log centralized, audit rules, alert on anomaly | #11 |
| Backup | Encrypted, offsite, immutable, tested monthly | #12 |
ℹ️ Không có server nào an toàn 100%. Bảo mật là quá trình liên tục: review, update, test, cải thiện. Checklist này là điểm khởi đầu tốt, nhưng bạn cần quay lại kiểm tra định kỳ vì các mối đe dọa luôn thay đổi.
Nếu bạn đã đi hết 12 bài trong serie này, VPS của bạn đang ở trạng thái bảo mật tốt hơn phần lớn server ngoài kia. Bước tiếp theo là duy trì: đọc CVE mới, update thường xuyên, test backup hàng tháng, và review log định kỳ. Bảo mật không phải đích đến mà là hành trình.
Có thể bạn cần xem thêm
- Backup VPS Linux - rsync, tar và chiến lược sao lưu toàn diện
- Troubleshooting VPS Linux - Cách xủ lý sự cố VPS phổ biến
- Backup & Restore dữ liệu Docker Volume
- Bảo vệ SSH toàn diện trên Linux VPS
- Logging, Monitoring và IDS trên Linux VPS - auditd, AIDE và Wazuh
- Quyền file và thư mục trên Linux - chmod, chown và rwx
Về tác giả
Trần Thắng
Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.