Phục Hồi VPS Sau Khi Bị Hack: Chuyện Thật Của Tôi & Quy Trình Cứu Server Từng Bước
2h Sáng, Tin Nhắn "Anh Ơi Web Chết Rồi"
Tháng 5/2024, 2h sáng. Tôi đang ngủ thì điện thoại rung liên hồi. Client nhắn: "Anh ơi web chết rồi, vào toàn thấy blank page." Tôi mở laptop, thử SSH — không vào được. Ping thì VPS vẫn sống. Mở browser gõ URL → redirect sang một trang web cờ bạc Trung Quốc.
Tim tôi đập thình thịch. Đây không phải lần đầu tôi thấy dấu hiệu VPS bị hack, nhưng là lần đầu nó xảy ra với production server có khách hàng thật.
Mất 5 phút để bình tĩnh. Rồi tôi làm theo đúng quy trình mình đã chuẩn bị sẵn (may là có chuẩn bị). Sau 4 tiếng, server hoạt động trở lại. Sau 48 tiếng, mọi thứ như cũ.
Đây là toàn bộ quy trình — 15 bước tôi đã làm, từ phát hiện đến khôi phục hoàn toàn.
Giai Đoạn 1: Phát Hiện & Đánh Giá Thiệt Hại (30 Phút Đầu)
Bước 1: Đừng Hoảng — Đây Là Lúc Cần Tỉnh Táo Nhất
Nghe sáo rỗng nhưng thật. Khi bị hack, não bạn sẽ chạy đua: "Xóa hết đi cài lại ngay!" — đừng làm thế. Xóa vội vàng là mất hết bằng chứng, không biết hacker vào bằng cách nào, và có thể lỗ hổng vẫn còn sau khi cài lại.
Bước 2: Cô Lập Server — Cắt Kết Nối Mạng Nhưng ĐỪNG Tắt Nguồn
Việc đầu tiên: vào control panel của provider, block tất cả network ra/vào server. Đừng tắt nguồn — nếu tắt, bạn mất toàn bộ dữ liệu trong RAM (process list, network connections, bash history của hacker).
# Trên control panel provider (Netihot/Tino/TrumVPS):
# Networking → Firewall → Block ALL inbound + outbound
# HOẶC: tạm thời detach public IP
# Nếu vẫn SSH được (qua console VNC của provider), làm nhanh:
# 1. Chặn tất cả input/output
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# 2. Chỉ cho phép loopback (process nội bộ)
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
Bước 3: Thu Thập Bằng Chứng Trước Khi Động Vào Gì
Đây là bước quan trọng nhất. Bạn cần biết hacker đã làm gì, vào bằng cách nào, và có để lại backdoor không.
# === FORENSICS CHECKLIST ===
# 1. Ai đang login?
w
last -20
lastb -20 # failed login attempts
# 2. Process nào đang chạy? Có gì lạ không?
ps auxf
# Tìm process ẩn: ps auxf | grep -v "\[" | grep -v grep
# 3. Network connections — hacker đang kết nối đến đâu?
ss -tunap
netstat -tunap 2>/dev/null
# 4. Lịch sử command — hacker đã chạy lệnh gì?
cat /root/.bash_history | tail -100
cat /home/*/.bash_history | tail -100
# Kiểm tra history đã bị xóa chưa:
ls -la /root/.bash_history # size = 0 nếu bị xóa
# 5. File mới tạo trong 24h qua?
find / -type f -mtime -1 -ls 2>/dev/null | head -50
# Tập trung vào: /tmp, /var/tmp, /dev/shm, /root
# 6. Cron job lạ?
crontab -l
cat /etc/crontab
ls -la /etc/cron.*/
# Hacker hay giấu backdoor trong cron
# 7. SSH key lạ?
cat /root/.ssh/authorized_keys
cat /home/*/.ssh/authorized_keys 2>/dev/null
# 8. User mới được tạo?
cat /etc/passwd | grep -v nologin | grep -v false
lastlog
# 9. Web shell / file uploads suspicious?
find /var/www -name "*.php" -mtime -7 -ls 2>/dev/null
find /var/www -name "*.jsp" -o -name "*.war" -o -name "*.cgi" 2>/dev/null
Kết quả forensics trên server của tôi:
- Nguyên nhân: Port 22 mở ra internet, root password bị brute-force (6,043 lần thử failed trong /var/log/auth.log)
- Thời gian xâm nhập: 1:47 AM — hacker brute-force thành công sau ~2 tiếng
- Những gì hacker đã làm: Sửa file .htaccess redirect traffic, cài web shell trong /var/www/html/wp-content/uploads/shell.php, thêm SSH key vào /root/.ssh/authorized_keys, tạo cron job gửi data ra ngoài mỗi 6 tiếng
- Dữ liệu bị ảnh hưởng: Web app frontend bị redirect, database còn nguyên (hacker chưa kịp dump)
Giai Đoạn 2: Backup Dữ Liệu An Toàn (1-2 Tiếng)
Trước khi làm gì khác, backup mọi thứ ra ngoài server. Tuyệt đối không backup vào chính server đó — hacker có thể có script giám sát và xóa backup của bạn.
Bước 4: Backup Database
# MySQL/MariaDB
mysqldump --all-databases --single-transaction --quick \
> /tmp/full-backup-$(date +%Y%m%d).sql
# PostgreSQL
pg_dumpall -U postgres > /tmp/full-backup-$(date +%Y%m%d).sql
# Copy ra máy local (mở tạm output cho IP của bạn)
# Trên control panel: allow outbound to your IP
scp root@vps:/tmp/full-backup-*.sql ~/backups/
Bước 5: Backup Source Code & Config
# Backup toàn bộ /etc (config files quan trọng)
tar czf /tmp/etc-backup-$(date +%Y%m%d).tar.gz /etc
# Backup web root
tar czf /tmp/www-backup-$(date +%Y%m%d).tar.gz /var/www
# Backup home directories
tar czf /tmp/home-backup-$(date +%Y%m%d).tar.gz /home
# Copy tất cả ra máy local
scp root@vps:/tmp/*-backup-*.{sql,tar.gz} ~/backups/
Giai Đoạn 3: Cài Lại OS & Hardening (2-3 Tiếng)
Bước 6: Format VPS — Cài OS Mới Từ ISO Gốc Của Provider
Đây không phải lúc để "dọn dẹp". Format hoàn toàn, cài OS mới. Hacker chuyên nghiệp có thể giấu rootkit trong kernel, kernel module, thậm chí BIOS/firmware. Cách duy nhất để chắc chắn sạch là cài lại từ đầu.
# Trên control panel provider:
# VPS → Reinstall → Chọn OS (Ubuntu 22.04/24.04 LTS)
# ⚠️ CHỌN "Clean Install" — KHÔNG giữ data
# Sau khi cài xong, login qua VNC console của provider
# ĐỪNG mở SSH ra internet vội!
Bước 7: Hardening Bảo Mật — KHÔNG Lặp Lại Lỗi Cũ
Đây là bước quan trọng nhất. Nếu bạn cài lại OS rồi mở port 22 như cũ, hacker sẽ brute-force lại trong vài giờ.
#!/bin/bash
# === VPS HARDENING SCRIPT ===
# Chạy NGAY SAU KHI cài OS mới
echo "=== BƯỚC 1: Update system ==="
apt update && apt upgrade -y
apt install -y ufw fail2ban unattended-upgrades
echo "=== BƯỚC 2: Tạo user thường, KHÓA root login ==="
useradd -m -s /bin/bash deploy
mkdir -p /home/deploy/.ssh
# Copy public key của bạn vào
echo "ssh-ed25519 AAAAC3..." > /home/deploy/.ssh/authorized_keys
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
echo "=== BƯỚC 3: Cấu hình SSH cứng ==="
cat > /etc/ssh/sshd_config.d/99-hardening.conf << 'SSHCONF'
# KHÔNG cho root login
PermitRootLogin no
# CHỈ cho phép SSH key (không password)
PasswordAuthentication no
PubkeyAuthentication yes
# Đổi port mặc định
Port 2222
# Giới hạn user được SSH
AllowUsers deploy
# Timeout idle
ClientAliveInterval 300
ClientAliveCountMax 0
# Không cho phép empty password
PermitEmptyPasswords no
# Giới hạn số lần thử auth
MaxAuthTries 3
MaxSessions 2
SSHCONF
systemctl restart sshd
echo "=== BƯỚC 4: Firewall — chỉ mở port cần thiết ==="
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp # SSH port mới
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
# KHÔNG mở port database ra ngoài!
ufw --force enable
echo "=== BƯỚC 5: Fail2ban chống brute-force ==="
cat > /etc/fail2ban/jail.local << 'F2BCONF'
[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 3600
findtime = 600
F2BCONF
systemctl enable --now fail2ban
echo "=== BƯỚC 6: Auto security updates ==="
cat > /etc/apt/apt.conf.d/20auto-upgrades << 'APTUP'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
APTUP
echo "=== BƯỚC 7: Audit cuối cùng ==="
# Kiểm tra port đang mở
ss -tlnp
# Kiểm tra SSH config
sshd -t
# Kiểm tra fail2ban
fail2ban-client status sshd
echo "=== ✅ HARDENING HOÀN TẤT ==="
Bước 8: Audit Source Code Trước Khi Deploy Lại
Đây là bước tôi suýt bỏ qua, và nếu bỏ qua thì đã bị hack lại. Hacker đã nhúng backdoor PHP vào 3 file trong theme WordPress. Tôi phải audit từng file một.
# Tìm backdoor PHP phổ biến
# Trong thư mục source code đã backup:
# 1. Tìm eval/base64/gzinflate (obfuscation phổ biến)
grep -r "eval(" . --include="*.php" | grep -v vendor
grep -r "base64_decode" . --include="*.php" | grep -v vendor
grep -r "gzinflate" . --include="*.php" | grep -v vendor
# 2. Tìm hàm system execution
grep -rE "(exec|shell_exec|system|passthru)\s*\(" . --include="*.php" | grep -v vendor
# 3. Tìm file mới/chỉnh sửa gần đây (từ ngày bị hack)
find . -name "*.php" -newer ./wp-config.php -ls
# 4. Tìm file ẩn (bắt đầu bằng dấu chấm)
find . -name ".*" -type f -ls
# 5. So sánh với bản sạch (nếu dùng WordPress)
# Download WordPress cùng version, diff từng file
diff -rq ./wp-admin /tmp/wordpress-clean/wp-admin
Giai Đoạn 4: Khôi Phục Dịch Vụ (1-2 Tiếng)
Bước 9: Deploy Lại Từng Service Một — Test Từng Cái
Đừng vội vàng deploy hết một lần. Làm từng service, test từng cái:
- Database trước — restore DB, check integrity, đổi toàn bộ password
- Web server — cài nginx/apache, test static page trước
- Application — deploy code đã audit, test từng endpoint
- Cron jobs — chỉ restore cron bạn nhận ra, bỏ hết cron lạ
- SSL — cài cert mới (đừng copy cert cũ từ server bị hack)
# Kiểm tra database integrity trước khi import
mysqlcheck -u root -p --all-databases --check --auto-repair
# Sau khi restore, ĐỔI TOÀN BỘ PASSWORD
# Database users
ALTER USER 'wp_user'@'localhost' IDENTIFIED BY 'new-strong-password-here';
# Application secrets
# Regenerate: wp-config.php salts, .env keys, JWT secrets, API keys
# FLUSH PRIVILEGES;
Bước 10: Setup Monitoring — Phát Hiện Sớm Lần Sau
# Cài đặt monitoring cơ bản (15 phút)
# 1. Uptime Kuma — theo dõi uptime + SSL expiry
docker run -d --name uptime-kuma \
-p 3001:3001 \
-v uptime-kuma:/app/data \
--restart unless-stopped \
louislam/uptime-kuma
# 2. Netdata — real-time system monitoring
bash <(curl -Ss https://my-netdata.io/kickstart.sh) \
--disable-telemetry
# 3. Logwatch — daily security report qua email
apt install logwatch -y
# Sẽ gửi email hàng ngày tóm tắt: failed logins, sudo usage, disk, etc.
# 4. Teleport alert cho suspicious activity
# File: /root/security-alert.sh
#!/bin/bash
# Gửi Telegram alert nếu có login SSH thành công
tail -f /var/log/auth.log | grep --line-buffered "Accepted publickey" | while read line; do
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
-d "text=🔑 SSH Login: $line"
done
Giai Đoạn 5: Hậu Kiểm & Bài Học (Sau 48h)
Bước 11: Đổi Toàn Bộ Mật Khẩu & Key Liên Quan
Không chỉ password trên VPS đó — đổi hết:
- Password control panel của provider
- API keys (nếu lưu trên server bị hack)
- Database passwords (tất cả database)
- SSH keys (generate cặp mới)
- Cloudflare API token (nếu có)
- GitHub/GitLab deploy keys
- Email password nếu config SMTP trên server
Bước 12: Báo Cáo Sự Cố Cho Các Bên Liên Quan
Nếu bạn có khách hàng trên server đó:
- Thông báo downtime, nguyên nhân, và biện pháp đã thực hiện
- Reset password tất cả user accounts
- Khuyến nghị họ bật 2FA nếu có
- Nếu có dữ liệu cá nhân bị truy cập → tuân thủ luật bảo vệ dữ liệu (Nghị định 13/2023/NĐ-CP tại VN)
Checklist 15 Bước Cứu VPS Bị Hack
In ra dán lên tường — khi bị hack bạn sẽ cần nó:
- ☐ Bình tĩnh — đừng xóa gì vội
- ☐ Cô lập server (block network, không tắt nguồn)
- ☐ Forensics: process list, network connections, auth logs, bash history, cron
- ☐ Xác định nguyên nhân + thời gian xâm nhập
- ☐ Backup database ra ngoài server
- ☐ Backup source code + config ra ngoài server
- ☐ Format VPS, cài OS mới từ ISO gốc
- ☐ Hardening: SSH key-only, non-root user, đổi port, fail2ban, ufw
- ☐ Audit source code: tìm backdoor, web shell
- ☐ Restore database + đổi toàn bộ password
- ☐ Deploy app từ code đã audit
- ☐ Setup monitoring (Uptime Kuma + Telegram alert)
- ☐ Đổi toàn bộ password/keys liên quan
- ☐ Báo cáo cho stakeholders
- ☐ Viết post-mortem: nguyên nhân, timeline, bài học, action items
Chi Phí Thực Tế Của Một Vụ Hack
Nhiều người nghĩ "VPS rẻ mà, cùng lắm cài lại". Nhưng chi phí thật không chỉ là tiền VPS:
| Loại Thiệt Hại | Trường Hợp Của Tôi | Ước Tính |
|---|---|---|
| Downtime (4 tiếng) | Khách hàng báo cáo, SEO bị ảnh hưởng | ~1.5 triệu (thiệt hại gián tiếp) |
| Mất dữ liệu | 3 ngày dữ liệu (backup daily nên mất ít) | ~500K (thời gian nhập lại) |
| Thời gian phục hồi | 12 tiếng làm việc (2 ngày) | ~2 triệu (nếu tính công 200K/h) |
| Uy tín | 1 khách hủy hợp đồng | ~1 triệu/tháng mất đi |
| Tổng thiệt hại ước tính | ~5 triệu |
So với chi phí hardening ban đầu (2-3 tiếng làm + dùng VPS có backup snapshot tự động như Tino Group ~200K/tháng), bài học quá rõ ràng.
Phòng Chống: Những Gì Tôi Làm Khác Sau Vụ Hack
1. Không Bao Giờ Dùng Password Cho SSH Nữa
SSH key-only. Ed25519, không RSA. Passphrase cho private key. Không có ngoại lệ.
2. Port 22 Không Bao Giờ Mở Ra Internet
Hoặc đổi port (2222, 22222), hoặc dùng Cloudflare Tunnel, hoặc whitelist IP tĩnh của bạn. Tôi chọn giải pháp: Cloudflare Tunnel — không cần mở port nào ra internet, SSH qua tunnel.
# Cloudflare Tunnel cho SSH
# Cài cloudflared
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
# Tạo tunnel
cloudflared tunnel login
cloudflared tunnel create my-vps
# Config file: ~/.cloudflared/config.yml
# tunnel: <tunnel-id>
# credentials-file: /root/.cloudflared/<tunnel-id>.json
# ingress:
# - hostname: ssh.mydomain.com
# service: ssh://localhost:22
# - service: http_status:404
cloudflared tunnel run my-vps
# Giờ SSH qua: ssh user@ssh.mydomain.com (qua Cloudflare)
3. Backup Tự Động Hàng Ngày — Không Khoan Nhượng
Tôi setup cron backup database + source code ra Cloudflare R2 (10GB free) mỗi đêm. Mất 30 phút setup, cứu tôi khỏi mất dữ liệu hoàn toàn.
Xem thêm: Backup VPS tự động với Restic + Backblaze B2 và Cài Cloudflare Tunnel cho VPS.
4. Dùng VPS Có Snapshot Tự Động
Nếu provider bạn hỗ trợ snapshot (như Tino Group), bật auto-snapshot hàng ngày. Khi bị hack, bạn rollback về snapshot sạch trong 5 phút thay vì cài lại toàn bộ.
5. Security Audit Định Kỳ
Mỗi tháng 1 lần, tôi chạy script audit toàn bộ VPS:
#!/bin/bash
# security-audit.sh — chạy monthly
echo "=== OPEN PORTS ===" && ss -tlnp
echo "=== FAILED LOGINS (30d) ===" && lastb -s -30days | wc -l
echo "=== USERS WITH SHELL ===" && grep -v nologin /etc/passwd | grep -v false
echo "=== CRON JOBS ===" && for u in $(cut -f1 -d: /etc/passwd); do crontab -u $u -l 2>/dev/null; done
echo "=== LISTENING SERVICES ===" && systemctl list-units --type=service --state=running
echo "=== DISK USAGE ===" && df -h
echo "=== UPDATES AVAILABLE ===" && apt list --upgradable 2>/dev/null | wc -l
echo "=== FAIL2BAN STATUS ===" && fail2ban-client status
Tổng Kết
Bị hack không phải là "nếu" mà là "khi nào". Sớm hay muộn, VPS của bạn cũng sẽ bị quét. Điều khác biệt là bạn có chuẩn bị trước hay không.
Ba điều quan trọng nhất tôi rút ra sau vụ hack:
- Backup là thứ duy nhất cứu bạn. Không backup = mất trắng. Backup daily ra ngoài server.
- SSH key-only, không password, không root. 90% VPS bị hack là qua SSH brute-force. Tắt password auth đi.
- Monitoring để biết sớm. Nếu tôi có Telegram alert khi có SSH login lạ, tôi đã phát hiện vụ hack trong 5 phút đầu thay vì 3 tiếng sau khi client báo.
VPS rẻ nhất hiện nay có giá từ 47K/tháng với NAT VPS (Netihot), 150K/tháng cho VPS IP riêng có snapshot (Tino Group). So với thiệt hại 5 triệu cho một vụ hack, vài trăm nghìn mỗi tháng cho backup + monitoring là khoản đầu tư rẻ nhất bạn từng bỏ ra.
Đọc thêm: Bảo mật VPS cho người mới, Cài Fail2ban chống brute-force, Bảo mật VPS toàn tập.
🛡️ VPS Bảo Mật, Backup Tự Động
VPS có snapshot tự động, backup daily, hỗ trợ 24/7. Từ 47K/tháng cho NAT VPS, 150K/tháng cho VPS IP riêng.
Netihot — VPS Giá Rẻ Nhất Tino Group — Snapshot AutoBài viết dựa trên sự cố thực tế tháng 5/2024. Một số chi tiết đã được thay đổi để bảo vệ thông tin khách hàng. Các script và cấu hình đã được test trên Ubuntu 22.04/24.04 LTS.