Monitoring VPS production: Log, CPU, RAM, disk và healthcheck
Hướng dẫn monitoring VPS production bằng journalctl, Nginx log, PM2, Docker healthcheck; theo dõi CPU, RAM, disk, uptime và cảnh báo.
Bài viết bởi Phạm Minh Thiện
Front-end Developer, trực tiếp thực hành Next.js, NestJS, Docker, Nginx và VPS Ubuntu.
Bài viết đã được kiểm tra lại ngày 21/7/2026.
Mục lục bài viết

Monitoring VPS production là cách phát hiện website down, API lỗi, RAM cạn, disk đầy hoặc container restart trước khi người dùng báo sự cố. systemctl status hay docker ps chỉ là ảnh chụp tại một thời điểm; hệ thống production cần healthcheck, log có cấu trúc, chỉ số tài nguyên và cảnh báo có hành động rõ ràng.
Bài viết xây dựng bộ monitoring từ đơn giản đến thực tế cho VPS nhỏ: journalctl, Nginx log, PM2, Docker, CPU/load, RAM/swap, disk/inode, PostgreSQL, uptime monitoring bên ngoài và runbook khi website down.
Tóm tắt nhanh: Theo dõi ít nhất availability, errors, latency và saturation; tách liveness/readiness; cảnh báo disk, RAM, restart và chứng chỉ; luôn kiểm tra backup bằng restore thử.

Demo terminal: kiểm tra nhanh khi website chậm hoặc mất kết nối
Runbook tốt bắt đầu từ ngoài vào trong: kiểm tra DNS/HTTPS, health endpoint, Nginx, process/container, tài nguyên và log. Đừng restart mọi thứ trước khi lưu bằng chứng.

curl -sS -o /dev/null -w "status=%{http_code} time=%{time_total}\n" https://api.example.com/health
systemctl --failed
free -h
df -h
df -i
sudo journalctl -p err --since "30 minutes ago"
Lưu ý: Output trong ảnh và ví dụ là demo lab đã ẩn thông tin nhạy cảm. Khi chụp terminal thật, hãy che IP quản trị, username nội bộ, token, private key, mật khẩu và chuỗi kết nối database.
Bốn nhóm tín hiệu cơ bản
Availability
Dịch vụ có truy cập được không?
HTTP 200?
DNS hoạt động?
Port 443 mở?
Errors
HTTP 5xx
Exception
Database timeout
Container crash
Latency
p50
p95
p99
Average có thể che request rất chậm.
Saturation
CPU
RAM
Swap
Disk
Inode
Connection
Queue
Healthcheck là gì?
Healthcheck xác định service có hoạt động không.
GET /health
{
"status": "ok"
}
HTTP:
200 OK
Liveness và readiness
Liveness
Process còn sống và không bị kẹt nghiêm trọng?
Readiness
Service đã sẵn sàng nhận request?
App có thể sống nhưng chưa ready vì database chưa kết nối hoặc migration chưa xong.
Khi cần, tách:
/health/live
/health/ready
Healthcheck không nên
- Chạy query nặng.
- Ghi dữ liệu.
- Gọi quá nhiều service.
- Lộ secret.
- Luôn trả 200 dù dependency chết.
Kiểm tra bằng curl
curl \
--fail \
--silent \
--show-error \
https://api.deployeasy.vn/health
Xem timing:
curl \
-o /dev/null \
-s \
-w 'status=%{http_code} time=%{time_total}\n' \
https://api.deployeasy.vn/health
Systemd service
systemctl status nginx
systemctl status ssh
systemctl status postgresql
systemctl --failed
systemctl dùng để kiểm tra và điều khiển systemd service.
Journalctl
Log service:
sudo journalctl -u nginx
Realtime:
sudo journalctl -u nginx -f
Trong 30 phút:
sudo journalctl -u nginx --since "30 minutes ago"
Chỉ lỗi:
sudo journalctl -p err --since today
Boot hiện tại:
sudo journalctl -b
Boot trước:
sudo journalctl -b -1
Dung lượng:
journalctl --disk-usage
Không xóa log ngay khi sự cố xảy ra.
Nginx log
/var/log/nginx/access.log
/var/log/nginx/error.log
Theo dõi:
sudo tail -f /var/log/nginx/error.log
Lọc 5xx theo log format mặc định:
awk '$9 ~ /^5/' /var/log/nginx/access.log | tail
Field có thể khác nếu log format đã đổi.
Log riêng:
access_log /var/log/nginx/deployeasy.access.log;
error_log /var/log/nginx/deployeasy.error.log;
PM2 monitoring
pm2 list
pm2 monit
pm2 logs
pm2 logs deployeasy-api --lines 200
Theo dõi:
- Status.
- Restart count.
- CPU.
- Memory.
- Uptime.
Restart count tăng liên tục cần điều tra.
Docker monitoring
docker compose ps
docker compose logs -f
docker stats
Health:
docker inspect \
--format='{{json .State.Health}}' \
CONTAINER_NAME | jq
Restart:
docker inspect \
--format='{{.RestartCount}}' \
CONTAINER_NAME
Container running chưa chắc app healthy.
Docker healthcheck
services:
api:
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Command healthcheck phải tồn tại trong image.
CPU và load
uptime
top
htop
nproc
Load average không bằng trực tiếp phần trăm CPU. Cần xem số CPU, I/O wait và process.
RAM và swap
free -h
vmstat 1
Tìm OOM:
sudo journalctl -k | grep -i -E 'out of memory|killed process'
Hoặc:
dmesg --ctime | grep -i -E 'out of memory|killed process'
Exit code 137 thường liên quan SIGKILL; OOM là nguyên nhân phổ biến nhưng không phải duy nhất.
Disk
df -h
du -sh /var/log/*
du -sh /var/lib/docker/*
Tìm thư mục lớn:
sudo du -xhd1 / | sort -h
Tránh quét sâu vào giờ cao điểm nếu I/O hạn chế.
Inode
df -i
Có thể còn GB trống nhưng không tạo file được vì hết inode.
Docker disk
docker system df
Dọn có chọn lọc:
docker image prune
docker builder prune
Không prune toàn bộ production thiếu kiểm soát.
Network và port
sudo ss -tulpn
sudo ss -s
dig deployeasy.vn
curl -Iv https://deployeasy.vn
PostgreSQL
sudo -u postgres psql -c "SELECT now();"
Docker:
docker compose exec database \
pg_isready \
-U deployeasy \
-d deployeasy
Theo dõi:
- Connection.
- Query chậm.
- Lock.
- Disk.
- Backup.
- Autovacuum.
Structured log
Thay vì:
Something failed
Dùng:
{
"level": "error",
"message": "Database connection failed",
"service": "deployeasy-api",
"requestId": "abc123",
"timestamp": "2026-07-10T03:00:00Z"
}
Không log:
- Password.
- Token.
- Cookie.
- Private key.
- Secret env.
- Dữ liệu cá nhân không cần thiết.
Request ID
X-Request-ID: abc123
Dùng cùng request ID ở Nginx và API để theo dõi request qua hệ thống.
Log level
debug
info
warn
error
fatal
Không bật debug liên tục trên production vì log nhiều và có thể lộ dữ liệu.
Log rotation
Nginx:
ls /etc/logrotate.d/
PM2:
pm2 install pm2-logrotate
Docker:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Journal:
journalctl --disk-usage
Uptime monitoring bên ngoài
Monitoring ngay trên VPS không phát hiện được khi toàn VPS mất mạng.
Dùng một dịch vụ hoặc máy khác kiểm tra:
https://deployeasy.vn/health
Cảnh báo qua email, chat hoặc hệ thống incident.
Dùng retry trước cảnh báo để giảm false alarm.
Alert phải actionable
Tốt:
API production trả 5xx 12% trong 5 phút,
dashboard..., runbook...
Kém:
Something wrong
Mỗi alert cần:
- Service.
- Environment.
- Metric.
- Threshold.
- Thời gian.
- Link log.
- Hành động ban đầu.
Threshold tham khảo
Disk > 80%: warning
Disk > 90%: critical
Healthcheck fail nhiều lần: critical
Certificate < 14 ngày: warning
Backup quá hạn: critical
Restart count tăng: warning
Điều chỉnh theo hệ thống thực tế.
Monitoring chứng chỉ
echo | openssl s_client \
-servername deployeasy.vn \
-connect deployeasy.vn:443 2>/dev/null |
openssl x509 -noout -enddate
Certbot timer vẫn có thể lỗi, nên cần kiểm tra độc lập.
Monitoring backup
Kiểm tra:
- File mới nhất.
- Kích thước.
- Upload offsite.
- Exit code.
- Restore test.
Ví dụ tìm backup trong 25 giờ:
find /var/backups/deployeasy \
-type f \
-name '*.dump' \
-mmin -1500 \
-print
Runbook website down
1. Xác nhận từ mạng ngoài
2. Kiểm tra DNS
3. Kiểm tra HTTPS
4. Kiểm tra Nginx
5. Kiểm tra app/container
6. Kiểm tra database
7. Kiểm tra RAM/disk
8. Xem log đúng thời điểm
9. Rollback nếu do deploy
10. Ghi timeline
Lệnh nhanh:
curl -Iv https://deployeasy.vn
sudo systemctl status nginx
pm2 list
docker compose ps
free -h
df -h
sudo journalctl -p err --since "30 minutes ago"
Chỉ chạy lệnh phù hợp với stack.
Sau sự cố
Postmortem:
Sự cố gì?
Bắt đầu lúc nào?
Phát hiện ra sao?
Ảnh hưởng ai?
Nguyên nhân gốc?
Điều gì kéo dài sự cố?
Khắc phục tạm thời?
Hành động phòng ngừa?
Ai phụ trách?
Không dùng postmortem để đổ lỗi cá nhân.
Stack theo giai đoạn
Ban đầu
Healthcheck
Journal/PM2/Docker logs
Uptime monitor ngoài VPS
Disk/RAM alert
Backup alert
Trung bình
Metrics
Dashboard
Centralized logs
Error tracking
Alert routing
Lớn
Tracing
SLO/SLI
On-call
Incident management
Capacity planning
Không cần cài stack phức tạp chỉ cho một blog tĩnh.
Checklist
[ ] Health endpoint
[ ] External uptime monitor
[ ] Nginx error log
[ ] Structured app log
[ ] Secret được che
[ ] Restart alert
[ ] CPU/RAM/swap
[ ] Disk và inode
[ ] Database readiness
[ ] Certificate expiry
[ ] Backup freshness
[ ] Log rotation
[ ] Alert có runbook
[ ] Rollback procedure
[ ] Postmortem
Câu hỏi thường gặp
Log có phải monitoring không?
Log là một tín hiệu. Monitoring còn có metric, healthcheck và alert.
Container running có nghĩa app tốt không?
Không. App có thể chạy nhưng endpoint lỗi hoặc database down.
Website ít người dùng có cần monitoring không?
Có, nhưng bắt đầu đơn giản với uptime, disk, backup và certificate.
Có nên tự restart khi healthcheck fail?
Có thể, nhưng restart liên tục có thể che lỗi. Cần giới hạn và cảnh báo.
Bài viết liên quan
- Deploy Node.js bằng PM2 và Nginx
- Docker Compose production
- Nginx 502 Bad Gateway
- Cấu hình VPS Ubuntu mới
Kết luận
Monitoring tốt giúp phát hiện sớm, chẩn đoán nhanh và phục hồi có kiểm soát. Bắt đầu từ healthcheck, log, tài nguyên và backup.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
Deploy Node.js lên VPS bằng PM2 và Nginx từ A–Z
Hướng dẫn deploy Node.js lên VPS Ubuntu bằng PM2 và Nginx: build, biến môi trường, reverse proxy, HTTPS, log, healthcheck và rollback.
Đọc bài →Cách trỏ tên miền về VPS bằng DNS, Cloudflare và Nginx
Hướng dẫn trỏ tên miền về VPS bằng A, AAAA, CNAME; kiểm tra DNS propagation, cấu hình Cloudflare, Nginx và xử lý lỗi www.
Đọc bài →Docker Compose production: Node.js, PostgreSQL và backup
Cấu hình Docker Compose production cho Node.js và PostgreSQL với healthcheck, volume, network riêng, secret, log rotation, backup và rollback.
Đọc bài →