Sau khi đã có monitoring bằng Prometheus, node_exporter và Grafana, bạn đã biết server đang có vấn đề ở đâu: CPU cao, RAM thiếu, disk gần đầy, network spike hoặc service down. Nhưng monitoring mới trả lời câu hỏi “có vấn đề không”. Để biết “vì sao có vấn đề”, bạn cần log.
Bài Logging và logrotate trên Ubuntu 24.04: Nginx logs, journalctl 2026 sẽ đi qua cách quản lý log nền cho VPS Ubuntu 24.04 LTS: đọc Nginx access/error log, dùng journalctl để xem log systemd service, cấu hình log format dễ debug, kiểm soát dung lượng journal, tạo logrotate cho app riêng, test rotation an toàn và tránh lỗi disk đầy vì log.
Mục tiêu không phải là gom mọi log vào một hệ thống phức tạp ngay từ đầu. Mục tiêu là làm đúng những thứ cơ bản: biết log nằm ở đâu, biết đọc log theo thời gian, biết lọc lỗi quan trọng, biết log nào cần rotate, biết kiểm tra dung lượng log, và biết giữ log đủ lâu để điều tra mà không làm đầy disk.
1. Hiểu đúng về logging trên VPS Ubuntu 24.04
1.1. Monitoring cho biết “có chuyện gì”, logging cho biết “vì sao”
Monitoring và logging không thay thế nhau. Monitoring giúp thấy xu hướng và trạng thái: CPU tăng, RAM giảm, disk sắp đầy, service down. Logging giúp điều tra chi tiết: request nào gây lỗi 500, PHP-FPM báo gì, MariaDB restart vì lý do nào, SSH có login lạ không, Certbot renew fail ở bước nào.
Ví dụ:
- Grafana cho thấy disk usage tăng nhanh.
- Log giúp biết file nào hoặc service nào đang ghi quá nhiều.
- Grafana cho thấy load average cao.
- Nginx log và PHP-FPM log giúp biết request nào đang chậm.
- Prometheus báo instance down.
journalctlgiúp biết service crash do config sai hay thiếu permission.
Vì vậy, sau khi có monitoring nền, bước tiếp theo tự nhiên là chuẩn hóa logging.
1.2. Log tốt phải vừa đủ, không phải càng nhiều càng tốt
Log quá ít thì không điều tra được. Log quá nhiều thì đầy disk, khó đọc và có thể chứa thông tin nhạy cảm. Một chiến lược logging tốt cần cân bằng ba yếu tố:
- Đủ dữ liệu để debug: có timestamp, status code, request time, upstream time, service name.
- Không lộ thông tin nhạy cảm: không ghi password, token, session, private key, full secret vào log.
- Có retention rõ ràng: log cũ được rotate, nén và xóa theo chính sách.
Đừng chờ đến khi disk đầy 100% mới nghĩ đến logrotate. Với VPS nhỏ, log tăng không kiểm soát là một trong những nguyên nhân rất thực tế làm website sập.
1.3. Các nhóm log quan trọng trên VPS LEMP
Với stack LEMP trong series này, bạn nên quan tâm các nhóm log sau:
- Nginx access log: request nào vào website, status code, user agent, request time.
- Nginx error log: lỗi Nginx, upstream PHP-FPM, permission, file not found, SSL issue.
- PHP-FPM log: service PHP-FPM, fatal error, pool issue, restart.
- MariaDB log/journal: database start/stop, crash, lỗi quyền, disk issue.
- SSH log: login thành công/thất bại, invalid user, brute force.
- Fail2ban log: IP bị ban/unban, jail hoạt động hay lỗi.
- Certbot log: cấp/renew SSL thành công hay thất bại.
- Backup log: backup chạy lúc nào, có fail không, repository có lỗi không.
- System journal: log tổng hợp của các service do systemd quản lý.
2. Kiểm tra log hiện tại trước khi chỉnh
2.1. Kiểm tra dung lượng log tổng quan
df -h
sudo du -sh /var/log
sudo du -h /var/log | sort -h | tail -n 30
Nếu /var/log đang lớn bất thường, đừng xóa file bừa. Hãy xem thư mục nào đang chiếm dung lượng trước.
Kiểm tra systemd journal:
journalctl --disk-usage
Nếu journal chiếm vài GB trên VPS nhỏ, bạn nên đặt giới hạn retention ở mục sau.
2.2. Kiểm tra các file log Nginx
sudo ls -lh /var/log/nginx/
sudo tail -n 50 /var/log/nginx/access.log 2>/dev/null || true
sudo tail -n 50 /var/log/nginx/error.log 2>/dev/null || true
Nếu bạn đã tách log theo domain, có thể thấy:
/var/log/nginx/example.com.access.log
/var/log/nginx/example.com.error.log
Kiểm tra trong Nginx config:
sudo nginx -T | grep -nE 'access_log|error_log|log_format'
2.3. Kiểm tra journal của các service quan trọng
sudo journalctl -u nginx --since "1 hour ago" --no-pager
sudo journalctl -u php8.3-fpm --since "1 hour ago" --no-pager
sudo journalctl -u mariadb --since "1 hour ago" --no-pager
sudo journalctl -u ssh --since "1 hour ago" --no-pager
sudo journalctl -u fail2ban --since "1 hour ago" --no-pager
Nếu service name khác, kiểm tra:
systemctl list-units --type=service | grep -E 'php|mysql|maria|nginx|ssh|fail2ban'
2.4. Kiểm tra logrotate hiện có
ls -lh /etc/logrotate.conf
ls -lh /etc/logrotate.d/
cat /etc/logrotate.conf
ls -1 /etc/logrotate.d/
Ubuntu và nhiều package như Nginx thường đã có cấu hình logrotate riêng. Trước khi tạo rule mới, hãy xem package đã có rule nào để tránh rotate trùng.
Kiểm tra cấu hình Nginx logrotate:
cat /etc/logrotate.d/nginx 2>/dev/null || true
3. Đọc Nginx access log đúng cách
3.1. Access log cho biết request nào đang vào website
Nginx access log thường dùng để trả lời các câu hỏi:
- IP nào đang truy cập nhiều nhất?
- URL nào bị 404 nhiều?
- Request nào trả 500/502/504?
- User agent nào là bot?
- Trang nào chậm?
- Request có đi qua đúng domain không?
Xem nhanh access log:
sudo tail -f /var/log/nginx/example.com.access.log
Xem 100 dòng cuối:
sudo tail -n 100 /var/log/nginx/example.com.access.log
3.2. Lọc status code lỗi
Lọc 4xx và 5xx:
sudo awk '$9 ~ /^[45][0-9][0-9]$/ {print}' /var/log/nginx/example.com.access.log | tail -n 100
Top status code:
sudo awk '{print $9}' /var/log/nginx/example.com.access.log | sort | uniq -c | sort -nr | head
Top URL 404:
sudo awk '$9 == 404 {print $7}' /var/log/nginx/example.com.access.log | sort | uniq -c | sort -nr | head -n 30
Nếu thấy nhiều request đến /wp-login.php, /xmlrpc.php, /.env, /backup.zip, /admin, đó thường là bot scan. Không cần hoảng, nhưng nên có Fail2ban, firewall/CDN rule hoặc hardening app phù hợp.
3.3. Top IP truy cập nhiều nhất
sudo awk '{print $1}' /var/log/nginx/example.com.access.log | sort | uniq -c | sort -nr | head -n 30
Lệnh này hữu ích khi nghi ngờ bị scan hoặc traffic bất thường. Tuy nhiên, nếu website đứng sau Cloudflare/CDN mà Nginx chưa cấu hình real IP, bạn có thể chỉ thấy IP của CDN. Khi đó cần xử lý real client IP trước khi phân tích IP.
3.4. Lọc request theo IP
sudo grep '203.0.113.10' /var/log/nginx/example.com.access.log | tail -n 100
Lệnh này dùng khi bạn muốn biết một IP cụ thể đã truy cập những URL nào, status code ra sao và user agent là gì.
3.5. Theo dõi log realtime khi test deploy
Khi vừa deploy app mới hoặc sửa Nginx config, mở hai terminal:
sudo tail -f /var/log/nginx/example.com.access.log
Terminal khác:
sudo tail -f /var/log/nginx/example.com.error.log
Sau đó chạy test:
curl -I https://example.com
curl -I https://example.com/healthz
Cách này giúp thấy request thật đi qua Nginx thế nào và lỗi xuất hiện ở access log hay error log.
4. Đọc Nginx error log đúng cách
4.1. Error log quan trọng hơn access log khi debug lỗi 502/500
Nginx error log thường là nơi đầu tiên cần xem khi gặp:
- 502 Bad Gateway.
- 504 Gateway Timeout.
- 403 Forbidden.
- 404 dù file tồn tại.
- SSL handshake lỗi.
- Permission denied.
- PHP-FPM socket sai.
Xem nhanh:
sudo tail -n 100 /var/log/nginx/example.com.error.log
Theo dõi realtime:
sudo tail -f /var/log/nginx/example.com.error.log
4.2. Lỗi PHP-FPM socket sai
Nếu thấy lỗi kiểu không kết nối được upstream socket, kiểm tra:
ls -la /run/php/
sudo systemctl status php8.3-fpm --no-pager
sudo nginx -T | grep -n "fastcgi_pass"
Nginx config phải trỏ đúng socket đang tồn tại, ví dụ:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
4.3. Lỗi permission denied
Nếu error log có permission denied, kiểm tra quyền theo từng lớp:
namei -l /srv/apps/example.com/current/public/index.php
ls -la /srv/apps/example.com/
ls -la /srv/apps/example.com/current/
ls -la /srv/apps/example.com/current/public/
Không sửa bằng chmod 777. Hãy kiểm tra owner, group, quyền execute trên thư mục và user mà Nginx/PHP-FPM đang chạy.
4.4. Lỗi upstream timed out
Nếu error log có upstream timed out, vấn đề có thể nằm ở PHP app, database query, external API hoặc worker bị nghẽn.
Kiểm tra song song:
sudo tail -n 100 /var/log/nginx/example.com.error.log
sudo journalctl -u php8.3-fpm --since "30 minutes ago" --no-pager
sudo journalctl -u mariadb --since "30 minutes ago" --no-pager
Đừng tăng timeout ngay lập tức để che lỗi. Trước hết hãy tìm request nào chậm, app đang làm gì và database có vấn đề không.
5. Chuẩn hóa Nginx log format để debug tốt hơn
5.1. Vì sao nên có log format riêng?
Log mặc định đủ cho website nhỏ, nhưng khi debug performance, bạn cần thêm các trường như:
$request_time: tổng thời gian xử lý request.$upstream_response_time: thời gian upstream như PHP-FPM phản hồi.$upstream_status: status từ upstream.$host: domain được request.$request_id: ID để trace request nếu bạn tự thêm.
Bài B7 đã giới thiệu log format timing. Ở bài C5, bạn sẽ chuẩn hóa lại để phục vụ vận hành lâu dài.
5.2. Tạo log format timing
Tạo file:
sudo nano /etc/nginx/conf.d/00-log-format-timing.conf
Nội dung:
log_format timing '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'host="$host" '
'rt=$request_time '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time '
'us=$upstream_status';
Kiểm tra:
sudo nginx -t
5.3. Áp dụng log format cho từng site
Mở server block:
sudo nano /etc/nginx/sites-available/example.com
Đặt log:
access_log /var/log/nginx/example.com.access.log timing;
error_log /var/log/nginx/example.com.error.log warn;
Kiểm tra và reload:
sudo nginx -t
sudo systemctl reload nginx
5.4. Đọc request time và upstream time
Gửi request:
curl -I https://example.com/
curl -I https://example.com/healthz
Xem log:
sudo tail -n 20 /var/log/nginx/example.com.access.log
Bạn có thể thấy trường dạng:
rt=0.045 uct=0.001 uht=0.038 urt=0.038 us=200
Cách đọc nhanh:
rtcao,urtcao: upstream như PHP-FPM/app/database có thể chậm.rtcao nhưngurtthấp hoặc trống: có thể do client/network/static file/disk.us=502hoặcus=504: kiểm tra PHP-FPM hoặc upstream backend.
5.5. Có nên dùng JSON log không?
JSON log rất tốt nếu bạn có hệ thống gom log như Loki, Elasticsearch/OpenSearch hoặc pipeline phân tích log. Nhưng với VPS nhỏ chỉ dùng tail, grep, awk, plain text format dễ đọc hơn.
Quy tắc thực tế:
- VPS nhỏ, đọc log bằng SSH: dùng plain text format có timing.
- Có log collector: cân nhắc JSON log.
- Không đổi log format liên tục nếu đã có script phân tích phụ thuộc format cũ.
6. Dùng journalctl để đọc log systemd
6.1. journalctl là công cụ phải biết trên Ubuntu hiện đại
Nhiều service trên Ubuntu ghi log vào systemd journal. Vì vậy, journalctl là công cụ rất quan trọng khi vận hành VPS.
Xem log boot hiện tại:
journalctl -b --no-pager | tail -n 100
Xem log từ hôm nay:
journalctl --since "today" --no-pager
Xem log trong 30 phút gần đây:
journalctl --since "30 minutes ago" --no-pager
6.2. Xem log theo service
sudo journalctl -u nginx --since "1 hour ago" --no-pager
sudo journalctl -u php8.3-fpm --since "1 hour ago" --no-pager
sudo journalctl -u mariadb --since "1 hour ago" --no-pager
sudo journalctl -u fail2ban --since "1 hour ago" --no-pager
sudo journalctl -u prometheus --since "1 hour ago" --no-pager
sudo journalctl -u grafana-server --since "1 hour ago" --no-pager
Theo dõi realtime:
sudo journalctl -u nginx -f
6.3. Xem log theo priority
Xem lỗi từ mức error trở lên:
journalctl -p err --since "24 hours ago" --no-pager
Xem warning trở lên:
journalctl -p warning --since "24 hours ago" --no-pager
Đây là cách nhanh để tìm lỗi hệ thống mà không phải đọc toàn bộ journal.
6.4. Xem log của lần boot trước
Danh sách boot:
journalctl --list-boots
Xem log boot trước:
journalctl -b -1 --no-pager | tail -n 200
Lệnh này rất hữu ích khi server vừa reboot bất thường. Bạn có thể xem log ngay trước reboot để tìm dấu hiệu OOM, kernel issue, service crash hoặc shutdown từ provider.
6.5. Kiểm tra lỗi OOM
Nếu nghi server bị kill process vì thiếu RAM:
journalctl -k --since "24 hours ago" --no-pager | grep -Ei 'oom|killed process|out of memory' || true
Nếu thấy OOM, hãy kiểm tra RAM, swap, PHP-FPM pool, database memory, cron job và traffic bất thường.
7. Kiểm soát dung lượng systemd journal
7.1. Kiểm tra dung lượng journal
journalctl --disk-usage
Nếu dung lượng journal quá lớn so với VPS, bạn nên đặt giới hạn trong cấu hình journald thay vì thỉnh thoảng xóa thủ công.
7.2. Tạo cấu hình giới hạn journal
Tạo thư mục override:
sudo mkdir -p /etc/systemd/journald.conf.d
Tạo file:
sudo nano /etc/systemd/journald.conf.d/10-devnook-retention.conf
Nội dung gợi ý cho VPS nhỏ:
[Journal]
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=14day
Ý nghĩa:
SystemMaxUse=500M: journal không nên dùng quá khoảng 500MB.SystemKeepFree=1G: cố gắng giữ lại ít nhất 1GB trống cho filesystem.MaxRetentionSec=14day: giữ log tối đa khoảng 14 ngày.
Với VPS disk lớn hơn, có thể tăng lên. Với VPS rất nhỏ, có thể giảm xuống.
7.3. Restart journald và kiểm tra
sudo systemctl restart systemd-journald
journalctl --disk-usage
Kiểm tra config có lỗi không:
sudo journalctl -u systemd-journald --since "10 minutes ago" --no-pager
7.4. Dọn journal thủ công khi cần
Dọn theo thời gian:
sudo journalctl --vacuum-time=14d
Dọn theo dung lượng:
sudo journalctl --vacuum-size=500M
Không nên dùng vacuum như giải pháp dài hạn duy nhất. Hãy đặt retention trong cấu hình journald để server tự kiểm soát.
8. Logrotate: rotate, nén và giữ log đúng cách
8.1. logrotate dùng để làm gì?
logrotate giúp quản lý file log dạng truyền thống trong /var/log. Nó có thể rotate log theo ngày/tuần/tháng hoặc theo dung lượng, nén log cũ, giữ số bản nhất định, xóa log quá cũ và chạy postrotate script để báo service mở file log mới.
Nginx access/error log là ví dụ rất điển hình cần logrotate. Nếu access log của một website có traffic hoặc bot nhiều không được rotate, file có thể tăng đến vài GB.
8.2. Kiểm tra logrotate timer/service
Trên Ubuntu hiện đại, logrotate thường được chạy định kỳ qua systemd timer.
systemctl list-timers | grep logrotate || true
systemctl status logrotate.timer --no-pager || true
systemctl status logrotate.service --no-pager || true
Chạy thử logrotate ở chế độ debug:
sudo logrotate -d /etc/logrotate.conf
Chế độ -d chỉ debug, không rotate thật. Đây là cách an toàn để xem logrotate sẽ làm gì.
8.3. Kiểm tra cấu hình logrotate của Nginx
cat /etc/logrotate.d/nginx 2>/dev/null || true
Cấu hình package có thể khác nhau theo distro/version, nhưng thường sẽ rotate các file:
/var/log/nginx/*.log
Và có postrotate để Nginx mở lại file log mới. Không nên tạo thêm rule Nginx trùng nếu file /etc/logrotate.d/nginx đã xử lý tốt.
8.4. Test logrotate riêng cho Nginx
Debug:
sudo logrotate -d /etc/logrotate.d/nginx
Force rotate để test trên staging hoặc khi bạn hiểu rõ tác động:
sudo logrotate -f /etc/logrotate.d/nginx
Sau khi force rotate, kiểm tra:
sudo ls -lh /var/log/nginx/
sudo systemctl status nginx --no-pager
sudo tail -n 20 /var/log/nginx/example.com.access.log
Nếu Nginx không ghi vào file mới, postrotate có thể chưa chạy đúng hoặc permission log file có vấn đề.
9. Tạo logrotate cho app và script riêng
9.1. Khi nào cần logrotate riêng?
Nếu app hoặc script của bạn ghi log vào file riêng, ví dụ:
/var/log/devnook-backup/restic-2026-05-20.log
/var/log/myapp/app.log
/var/log/myapp/worker.log
Bạn nên tạo rule logrotate riêng. Không để các file này tăng mãi.
9.2. Ví dụ logrotate cho app log
Tạo file:
sudo nano /etc/logrotate.d/devnook-app
Nội dung:
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
copytruncate
create 0640 www-data adm
}
Giải thích:
daily: rotate mỗi ngày.rotate 14: giữ 14 bản rotate.missingok: không lỗi nếu file chưa tồn tại.notifempty: không rotate file rỗng.compress: nén log cũ.delaycompress: trì hoãn nén bản mới rotate một chu kỳ.copytruncate: copy file cũ rồi truncate file gốc, dùng khi app không reopen log tốt.
copytruncate tiện nhưng không hoàn hảo, vì có thể mất vài dòng log trong khoảng rất ngắn giữa copy và truncate. Nếu app hỗ trợ reopen log khi nhận signal, cách tốt hơn là dùng postrotate để báo app mở file mới.
9.3. Ví dụ logrotate cho backup log
Với thư mục backup log ở bài C3:
sudo nano /etc/logrotate.d/devnook-backup
Nội dung:
/var/log/devnook-backup/*.log {
weekly
rotate 8
missingok
notifempty
compress
delaycompress
create 0640 root adm
}
Test debug:
sudo logrotate -d /etc/logrotate.d/devnook-backup
9.4. Khi nào không nên dùng copytruncate?
Không nên dùng copytruncate cho mọi thứ theo thói quen. Với service có thể reopen log sau signal, nên dùng postrotate. Với Nginx, package logrotate thường dùng cơ chế báo Nginx reopen log thay vì copytruncate.
Quy tắc thực tế:
- Script nhỏ ghi log theo từng lần chạy: có thể dùng logrotate đơn giản.
- Service dài hạn tự quản lý log: ưu tiên signal/reopen log nếu hỗ trợ.
- Không rõ service có reopen log không: test trên staging trước.
10. Log của PHP-FPM, MariaDB, Fail2ban, Certbot và Backup
10.1. PHP-FPM log
Xem service PHP-FPM:
sudo journalctl -u php8.3-fpm --since "1 hour ago" --no-pager
sudo systemctl status php8.3-fpm --no-pager
Kiểm tra cấu hình pool nếu cần:
grep -R "error_log\|slowlog\|request_slowlog_timeout" /etc/php/*/fpm/ -n || true
Nếu app PHP chậm, bạn có thể cân nhắc bật slowlog cho PHP-FPM pool. Tuy nhiên, slowlog nên được bật có kiểm soát vì có thể sinh log nhạy cảm hoặc nhiều dữ liệu.
10.2. MariaDB log
sudo journalctl -u mariadb --since "1 hour ago" --no-pager
sudo systemctl status mariadb --no-pager
Kiểm tra log file nếu có:
sudo ls -lh /var/log/mysql/ 2>/dev/null || true
sudo ls -lh /var/log/mariadb/ 2>/dev/null || true
Nếu database lỗi, đừng chỉ nhìn app báo “database connection failed”. Hãy đọc log MariaDB để biết service có crash, disk đầy, permission lỗi hay config sai.
10.3. Fail2ban log
sudo tail -n 100 /var/log/fail2ban.log
sudo grep -E 'Ban|Unban|Found' /var/log/fail2ban.log | tail -n 100
sudo journalctl -u fail2ban --since "1 hour ago" --no-pager
Fail2ban log giúp biết jail nào đang ban IP, có false positive không và service có đọc log đúng không.
10.4. Certbot log
sudo tail -n 120 /var/log/letsencrypt/letsencrypt.log
sudo grep -Ei 'error|fail|renew|certificate' /var/log/letsencrypt/letsencrypt.log | tail -n 100
Khi HTTPS renew fail, log Certbot thường cho biết lỗi nằm ở DNS, HTTP-01 challenge, Nginx config, port 80, rate limit hoặc permission.
10.5. Backup log
Nếu làm theo bài C3, backup log có thể nằm ở:
/var/log/devnook-backup/
Kiểm tra:
sudo ls -lh /var/log/devnook-backup/
sudo tail -n 120 /var/log/devnook-backup/restic-$(date +%F).log 2>/dev/null || true
sudo journalctl -u devnook-restic-backup.service --since "24 hours ago" --no-pager
Backup fail mà không ai biết là một rủi ro lớn. Log backup nên được xem định kỳ hoặc đưa vào monitoring/alert.
11. Tìm nguyên nhân disk đầy vì log
11.1. Tìm file log lớn nhất
sudo find /var/log -type f -printf '%s %p\n' | sort -nr | head -n 30 | awk '{printf "%.2f MB %s\n", $1/1024/1024, $2}'
Lệnh này giúp biết file nào đang chiếm nhiều dung lượng nhất.
11.2. Tìm file log tăng nhanh
Xem kích thước ban đầu:
sudo ls -lh /var/log/nginx/
journalctl --disk-usage
Chờ vài phút rồi kiểm tra lại. Nếu một file tăng rất nhanh, dùng tail -f để xem nội dung:
sudo tail -f /path/to/large.log
Log tăng nhanh thường do bot scan, lỗi app lặp lại, service crash loop, debug mode đang bật hoặc health-check quá dày.
11.3. Xử lý khẩn cấp khi disk sắp đầy
Kiểm tra disk:
df -h
sudo du -sh /var/log
journalctl --disk-usage
Dọn journal theo dung lượng:
sudo journalctl --vacuum-size=500M
Force logrotate Nginx nếu cần:
sudo logrotate -f /etc/logrotate.d/nginx
Không nên xóa file log đang được process mở bằng rm nếu chưa hiểu. Một process có thể vẫn giữ file descriptor cũ, khiến dung lượng chưa được giải phóng cho đến khi service reload/restart.
11.4. Kiểm tra deleted file vẫn bị process giữ
sudo lsof | grep deleted | head -n 50
Nếu thấy file log lớn đã bị xóa nhưng process vẫn giữ, bạn cần reload hoặc restart service tương ứng. Với Nginx:
sudo nginx -t
sudo systemctl reload nginx
Với service khác, cân nhắc restart trong khung giờ an toàn.
12. Bảo mật log
12.1. Không ghi secret vào log
Log có thể chứa dữ liệu nhạy cảm. Không nên ghi:
- Mật khẩu.
- Token API.
- Session ID.
- Private key.
- Full Authorization header.
- Cookie nhạy cảm.
- Database password.
- Nội dung form nhạy cảm.
Nếu app đang bật debug mode và ghi quá nhiều thông tin ra log production, hãy tắt ngay khi không còn cần.
12.2. Kiểm tra quyền file log
ls -lh /var/log/nginx/
ls -lh /var/log/fail2ban.log 2>/dev/null || true
ls -lh /var/log/devnook-backup/ 2>/dev/null || true
Log không nên world-readable nếu chứa thông tin nhạy cảm. Với app log riêng, thường dùng quyền như 0640 và group phù hợp.
12.3. Cẩn thận khi chia sẻ log để nhờ hỗ trợ
Trước khi gửi log cho người khác, hãy che:
- IP public nếu không muốn lộ.
- Domain staging/private.
- Email, username, token.
- Cookie/session.
- Đường dẫn nội bộ nhạy cảm.
Không paste nguyên log chứa secret lên forum, issue public hoặc chat nhóm.
12.4. Có nên backup log không?
Với VPS nhỏ, không nhất thiết backup toàn bộ log dài hạn. Log có thể rất lớn và ít giá trị sau một thời gian. Tuy nhiên, một số log vận hành gần đây có thể hữu ích khi restore hoặc điều tra sự cố.
Quy tắc thực tế:
- Backup cấu hình logrotate và script vận hành.
- Không backup mọi access log dài hạn nếu không có nhu cầu compliance.
- Giữ log gần đây đủ để debug.
- Nếu cần lưu log dài hạn, dùng log collector/storage riêng.
13. Tạo script kiểm tra logging nhanh
13.1. Vì sao nên có script kiểm tra nhanh?
Khi có sự cố, bạn không muốn nhớ lại từng lệnh. Một script nhỏ giúp kiểm tra nhanh dung lượng log, journal, Nginx error, service journal và logrotate status.
13.2. Tạo script log-health
sudo nano /usr/local/sbin/log-health.sh
Nội dung:
#!/usr/bin/env bash
set -euo pipefail
DOMAIN_LOG_PREFIX="${1:-example.com}"
echo "== Disk =="
df -h
echo
echo "== /var/log size =="
du -sh /var/log || true
echo
echo "== Biggest log files =="
find /var/log -type f -printf '%s %p\n' 2>/dev/null \
| sort -nr \
| head -n 20 \
| awk '{printf "%.2f MB %s\n", $1/1024/1024, $2}'
echo
echo "== Journal size =="
journalctl --disk-usage || true
echo
echo "== Nginx recent errors =="
tail -n 80 "/var/log/nginx/${DOMAIN_LOG_PREFIX}.error.log" 2>/dev/null || true
echo
echo "== Recent system errors =="
journalctl -p err --since "24 hours ago" --no-pager || true
echo
echo "== Logrotate timer =="
systemctl list-timers | grep logrotate || true
echo
echo "== Deleted files still opened =="
lsof 2>/dev/null | grep deleted | head -n 30 || true
Cấp quyền:
sudo chmod +x /usr/local/sbin/log-health.sh
Chạy:
sudo log-health.sh example.com
Script này không thay thế monitoring/logging đầy đủ, nhưng rất tiện khi cần kiểm tra nhanh.
14. Lỗi thường gặp khi quản lý logging và rotation
14.1. Không rotate log app riêng
Nginx có thể đã có logrotate, nhưng app/script riêng thì chưa chắc. Nếu backup script, worker hoặc app PHP tự ghi log vào /var/log/myapp, bạn phải tạo rule logrotate riêng.
14.2. Tạo rule logrotate trùng với package
Nếu tạo thêm rule rotate /var/log/nginx/*.log trong khi package Nginx đã có /etc/logrotate.d/nginx, bạn có thể gây rotate trùng hoặc hành vi khó đoán.
Luôn kiểm tra:
grep -R "/var/log/nginx" /etc/logrotate.d/ /etc/logrotate.conf
14.3. Quên postrotate khiến service vẫn ghi vào file cũ
Một số service cần signal hoặc reload để mở file log mới sau rotate. Nếu không, service có thể tiếp tục ghi vào file cũ đã rename hoặc deleted.
Với Nginx, hãy ưu tiên cấu hình logrotate package có postrotate đúng. Nếu tự viết rule cho service riêng, hãy hiểu service đó có cần reload/reopen log không.
14.4. Xóa log bằng rm nhưng disk không giảm
Nếu process vẫn giữ file descriptor, xóa file không giải phóng dung lượng ngay. Kiểm tra:
sudo lsof | grep deleted | head
Sau đó reload/restart service phù hợp.
14.5. Bật debug log trên production quá lâu
Debug log rất hữu ích khi điều tra lỗi, nhưng không nên bật lâu trên production. Nó có thể tăng dung lượng cực nhanh và ghi thông tin nhạy cảm.
14.6. Không giới hạn systemd journal
Nếu không đặt retention, journal có thể chiếm dung lượng đáng kể. Với VPS nhỏ, nên đặt SystemMaxUse, SystemKeepFree và MaxRetentionSec.
14.7. Log format thay đổi làm hỏng script phân tích
Nếu bạn có script dùng awk theo vị trí field, đổi log format có thể làm script sai. Khi thay log format, hãy cập nhật script phân tích hoặc chuyển sang format dễ parse hơn.
15. Checklist logging và rotation
15.1. Checklist Nginx logs
- Mỗi site có access log và error log riêng.
- Access log có format đủ thông tin để debug.
- Error log được kiểm tra khi gặp 502/500/403/404 bất thường.
- Nginx logrotate đang hoạt động.
- Không tắt toàn bộ access log nếu chưa có hệ thống thay thế.
15.2. Checklist journalctl
- Biết xem log theo service bằng
journalctl -u. - Biết xem log theo thời gian bằng
--since. - Biết xem lỗi bằng
-p err. - Biết xem boot trước bằng
-b -1. - Đã giới hạn dung lượng journal phù hợp với VPS.
15.3. Checklist logrotate
- Đã kiểm tra
/etc/logrotate.d/nginx. - App/script riêng có rule logrotate nếu ghi log file.
- Đã test bằng
logrotate -d. - Không có rule rotate trùng nhau.
- Log cũ được nén và xóa theo retention.
15.4. Checklist chống đầy disk vì log
- Theo dõi dung lượng
/var/log. - Theo dõi
journalctl --disk-usage. - Có script kiểm tra log nhanh.
- Biết xử lý file deleted vẫn bị process giữ.
- Không để debug log chạy lâu trên production.
16. FAQ
16.1. Nginx access log và error log khác nhau thế nào?
Access log ghi request đã đi qua Nginx: IP, URL, status code, user agent, thời gian xử lý. Error log ghi lỗi trong quá trình Nginx xử lý request hoặc giao tiếp với upstream như PHP-FPM. Khi debug 502/500, error log thường quan trọng hơn.
16.2. Có nên tắt access log để giảm dung lượng không?
Không nên tắt toàn bộ access log nếu chưa có hệ thống thay thế. Bạn có thể tắt access log cho static asset quá nhiều noise, nhưng nên giữ access log chính của site để debug traffic, status code và request bất thường.
16.3. journalctl log nằm ở đâu?
systemd journal được quản lý bởi journald. Bạn thường không cần đọc file trực tiếp, mà dùng journalctl. Có thể kiểm tra dung lượng bằng journalctl --disk-usage và đặt giới hạn trong /etc/systemd/journald.conf.d/.
16.4. logrotate có tự chạy không?
Trên Ubuntu hiện đại, logrotate thường được chạy định kỳ qua systemd timer. Có thể kiểm tra bằng systemctl list-timers | grep logrotate. Nếu tạo rule mới, hãy test bằng logrotate -d.
16.5. Có nên dùng copytruncate trong logrotate không?
Chỉ nên dùng khi app không hỗ trợ reopen log. copytruncate tiện nhưng có thể mất một lượng log rất nhỏ trong quá trình copy rồi truncate. Với service hỗ trợ signal/reopen, nên dùng postrotate phù hợp.
16.6. Làm gì khi disk đầy vì log?
Đầu tiên, xác định file log lớn nhất bằng find /var/log và kiểm tra journal bằng journalctl --disk-usage. Sau đó vacuum journal, force logrotate nếu cần, và kiểm tra process có giữ file deleted không bằng lsof | grep deleted. Không xóa bừa nếu chưa biết process nào đang ghi log.
16.7. Có nên đưa log vào backup không?
Không cần backup toàn bộ access log dài hạn nếu không có nhu cầu compliance. Nên backup cấu hình logging, logrotate và script vận hành. Nếu cần lưu log dài hạn, hãy dùng hệ thống log storage riêng.
16.8. Sau bài này nên học gì tiếp?
Sau khi monitoring và logging đã ổn, bước tiếp theo là tối ưu hiệu năng hệ thống: CPU, RAM, disk, Nginx, PHP-FPM và database. Lúc đó bạn sẽ tối ưu dựa trên số liệu và log thật, không phải đoán.
17. Kết luận
Logging Ubuntu 24.04 là một phần bắt buộc nếu bạn muốn vận hành VPS nghiêm túc. Monitoring giúp phát hiện vấn đề, còn log giúp điều tra nguyên nhân. Nếu không có Nginx access/error log, journalctl, logrotate và retention rõ ràng, bạn sẽ rất khó debug các lỗi production như 502, disk đầy, service crash, backup fail hoặc bot traffic bất thường.
Trong bài này, bạn đã đi qua workflow thực tế: kiểm tra dung lượng log, đọc Nginx access/error log, chuẩn hóa log format có timing, dùng journalctl theo service/thời gian/priority, giới hạn dung lượng systemd journal, kiểm tra logrotate, tạo rule rotate cho app riêng, xử lý disk đầy vì log và tạo script log-health.sh để kiểm tra nhanh.
Khi logging và rotation đã được thiết kế đúng, VPS của bạn sẽ dễ vận hành hơn rất nhiều. Bạn không còn phải đoán lỗi nằm ở Nginx, PHP-FPM, MariaDB hay hệ thống; bạn có log để kiểm chứng. Đây là nền tảng cần có trước khi bước sang tối ưu hiệu năng và troubleshooting playbook.

