On systemd-based distributions, services, the kernel and the system itself log to the journal. journalctl reads it, and its filters make finding the right lines much faster than grepping through text files.

The basics

journalctl                 # everything, oldest first, in a pager
journalctl -r              # newest first
journalctl -n 50           # last 50 lines
journalctl -f              # follow new entries (like tail -f)
journalctl --no-pager      # print without less, for scripts and pipes

Run it with sudo (or as a member of the adm / systemd-journal group) to see all logs; otherwise you see only your own user’s.

Filter by service

journalctl -u nginx
journalctl -u nginx -f
journalctl -u nginx -u php8.3-fpm        # two units interleaved
journalctl -u ssh --since today

-u (unit) is the filter you’ll use most — every service started by systemd logs its stdout and stderr here, even if it also writes its own log files.

Filter by time

journalctl --since "2026-11-04 09:00" --until "2026-11-04 10:00"
journalctl --since "1 hour ago"
journalctl --since yesterday --until today
journalctl -u mysql --since "10 min ago"

Filter by boot

journalctl -b             # current boot
journalctl -b -1          # previous boot
journalctl --list-boots

journalctl -b -1 -e (jump to end of the previous boot) is how you find out why a server crashed or rebooted unexpectedly — if persistent storage is enabled (see below).

Filter by priority

journalctl -p err -b            # errors and worse, this boot
journalctl -p warning --since today

Levels: emerg (0), alert, crit, err, warning, notice, info, debug (7). -p err includes everything from err up to emerg.

Kernel messages

journalctl -k              # like dmesg, but with timestamps and history
journalctl -k -b -1        # kernel messages from the previous boot
journalctl -k | grep -i "out of memory"

The OOM killer, disk errors and network driver problems show up here.

Search the text

journalctl -u nginx -g "upstream timed out"      # grep built in (case-insensitive by default)
journalctl -g "Failed password" --since today

Or pipe to grep: journalctl -u ssh --no-pager | grep "Accepted".

Other useful filters

journalctl _PID=1234
journalctl _UID=1000
journalctl /usr/sbin/sshd             # by executable
journalctl -t CRON                    # by syslog identifier
journalctl -u myapp -o cat            # message only, no metadata
journalctl -u myapp -o json-pretty    # full structured fields
journalctl -u myapp -o short-iso      # ISO timestamps

-o cat is perfect when your app already prints its own timestamps. JSON output exposes every field, useful for shipping logs to other tools.

Is the journal persistent?

On some systems the journal lives only in memory (/run/log/journal) and is lost at reboot. Check:

ls /var/log/journal 2>/dev/null && echo persistent || echo volatile

To make it persistent, edit /etc/systemd/journald.conf:

[Journal]
Storage=persistent
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald

Ubuntu and Debian 12+ generally keep a persistent journal already.

Control disk usage

The journal caps itself (by default at 10% of the filesystem, up to 4 GB), but on a small VPS disk you may want less:

journalctl --disk-usage
sudo journalctl --vacuum-size=500M    # shrink now
sudo journalctl --vacuum-time=14d     # delete entries older than 14 days

Make it permanent in journald.conf:

SystemMaxUse=500M
MaxRetentionSec=1month

Then sudo systemctl restart systemd-journald. If your disk is suddenly full, see disk full troubleshooting.

Journal and traditional log files

Many distributions also run rsyslog, which copies journal entries into text files: /var/log/syslog (Debian/Ubuntu) or /var/log/messages (RHEL family), plus /var/log/auth.log for logins. Both exist side by side; the journal has richer metadata and filtering, the text files are handy for grep and log shippers. Debian 12 and later no longer install rsyslog by default, so on a minimal Debian server the journal may be the only system log.

Applications like Nginx and MySQL still write their own files under /var/log/nginx/ and /var/log/mysql/ — check those too.

Practical recipes

# Why did my service stop?
journalctl -u myapp -n 100 --no-pager

# What happened right before the last crash/reboot?
journalctl -b -1 -n 200 --no-pager

# All errors since boot, newest first
journalctl -p err -b -r

# Successful SSH logins today
journalctl -u ssh --since today -g "Accepted"

# Watch a service while you restart it in another terminal
journalctl -u nginx -f

Quick reference

Goal Command
One service journalctl -u NAME
Follow -f
Last N lines -n N
Time range --since … --until …
This / last boot -b / -b -1
Errors only -p err
Kernel -k
Search -g PATTERN
Disk usage --disk-usage, --vacuum-size=

Pair this with systemctl commands for managing the services themselves. All VPS.DO Linux images use systemd, so these commands work out of the box.

  • Linux
  • systemd
  • Logs