DevOps

Logging và logrotate trên Ubuntu 24.04: Nginx logs, journalctl 2026

logging và logrotate trên Ubuntu

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.
  • journalctl giú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:

  • rt cao, urt cao: upstream như PHP-FPM/app/database có thể chậm.
  • rt cao nhưng urt thấp hoặc trống: có thể do client/network/static file/disk.
  • us=502 hoặc us=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, SystemKeepFreeMaxRetentionSec.

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.

Đừng bỏ lỡ

Theo dõi bản tin mới nhất tại đây

Chào bạn 👋
Rất vui được làm quen.

Đăng ký để nhận nội dung hấp dẫn mỗi tháng qua email.

Bằng việc đăng ký, bạn đồng ý với Chính sách bảo mật của DevNook.

Tác giả

Tuấn Lê

Tại DevNook, mình chia sẻ kiến thức thực chiến, kinh nghiệm làm sản phẩm và những công cụ hữu ích giúp bạn làm việc hiệu quả hơn mỗi ngày.