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.