Log Management: journald, logrotate, and Centralized Logging

Track down problems fast with journalctl, keep logrotate from filling your disk, and know when centralized logging is worth it.

When something breaks on a server, logs are your first clue. Modern Ubuntu/Debian systems keep logs in two places: systemd's journald (structured, queryable per service) and the classic text files under /var/log. Knowing how to read them, and how to keep their size in check, is core to running your own VPS.

Reading systemd logs with journalctl

journald collects the output of every systemd-managed service. These are the queries you'll reach for most:

# Logs for one service (-u selects the unit)
journalctl -u nginx

# Follow live (like tail -f) — the go-to for debugging
journalctl -u nginx -f

# Filter by time
journalctl -u nginx --since "2026-07-14 09:00" --until "2026-07-14 10:00"
journalctl --since "1 hour ago"
journalctl --since today

# Errors and above only
journalctl -p err -b

# Everything since the current boot (-b = boot)
journalctl -b

A few handy flags: -n 100 shows only the last 100 lines, -r reverses order (newest first), -o short-iso gives ISO timestamps, and -k limits output to kernel messages. Combine them freely, e.g. journalctl -u ssh -f -p warning.

Classic /var/log and logrotate

Plenty of services (Nginx, your own apps) still write plain text straight to /var/log, such as /var/log/nginx/access.log or /var/log/syslog. Read them the usual way:

tail -f /var/log/nginx/error.log
grep "500" /var/log/nginx/access.log

These files grow forever, and if left alone they can fill the disk and take your service down with it. logrotate handles rotating, compressing, and pruning old logs on a schedule. Drop one file per service into /etc/logrotate.d/:

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

That means: rotate daily, keep 14 generations, gzip old files, don't error if a file is missing, skip empty ones. Test a config before trusting it:

# Dry run — shows what would happen, changes nothing
logrotate -d /etc/logrotate.d/myapp
# Force one rotation right now
sudo logrotate -f /etc/logrotate.d/myapp

> Tip: copytruncate suits programs that don't reopen their log file. If yours supports reload, a postrotate script that signals the process is cleaner.

Capping journald's disk use

journald takes disk space too. Check usage and trim it:

journalctl --disk-usage
sudo journalctl --vacuum-size=500M   # keep at most 500M
sudo journalctl --vacuum-time=14d    # keep the last 14 days

To cap it permanently, edit /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=500M
MaxRetentionSec=2week

Then run sudo systemctl restart systemd-journald to apply.

When you need centralized logging

For a single server, the above is enough. But once you run several machines, want logs to survive reboots and container restarts, or need full-text search and alerting, it's time to look at centralized logging:

  • ELK / Elastic Stack: Elasticsearch for storage, Logstash/Filebeat for shipping, Kibana for dashboards. Powerful, but hungry for resources.
  • Grafana Loki: lightweight, indexes by labels, and fits neatly with the Prometheus/Grafana stack — friendlier for small teams.

Both work the same way: run a shipping agent on each host that pushes logs to central storage you query in one place. A lone VPS rarely needs this; add it once your footprint grows.

Summary

For day-to-day debugging, start with journalctl -u <service> -f and --since. Keep classic text logs from swallowing the disk with logrotate, and cap journald with SystemMaxUse. Only reach for ELK or Loki once you're running multiple hosts or need long-term search. Get comfortable with the single-host toolkit first — it resolves the vast majority of problems right where they happen.