How to read logs with journalctl

Find the log lines you need with journalctl, by service, time, priority and boot, keep logs across reboots, and cap how much disk the journal uses.

Tested on Ubuntu 24.04 LTS, Debian 13 Stable, AlmaLinux 10

Before you start

  • A Linux server with systemd
  • Root or a user with sudo (or in the systemd-journal or adm group)

journalctl reads the systemd journal, which collects the logs of every service, the kernel and anything else that writes to syslog. The commands you'll use most are journalctl -u nginx (one service), journalctl -f (follow live), journalctl -p err -b (errors since boot) and journalctl --since "1 hour ago"; you can combine them freely.

This tutorial covers the filters in the order you're likely to need them, then making logs survive a reboot and capping their size. Everything was run on Ubuntu 24.04, Debian 13 and AlmaLinux 10.

The basics

bash
sudo journalctl                # everything, oldest first, in a pager
sudo journalctl -e             # jump to the end
sudo journalctl -n 50          # the last 50 lines
sudo journalctl -f             # follow new lines live (Ctrl+C to stop)
sudo journalctl -r             # newest first

The pager is less: / searches, G goes to the end, q quits. Add --no-pager when you pipe the output to another command or copy it into a ticket.

Without sudo, you only see your own user's logs, unless your user is in the systemd-journal group (or adm on Ubuntu and Debian).

Filter by service

bash
sudo journalctl -u nginx
sudo journalctl -u ssh -u nginx -n 100      # several at once

The SSH service is ssh on Ubuntu and Debian and sshd on AlmaLinux and Rocky Linux. systemctl list-units --type=service shows the names, and journalctl -F _SYSTEMD_UNIT lists every unit that has logged something.

For a script that logs with logger -t myscript "message", filter on the tag:

bash
sudo journalctl -t myscript

Filter by time

bash
sudo journalctl --since "1 hour ago"
sudo journalctl --since today
sudo journalctl --since "2026-10-21 09:00" --until "2026-10-21 10:30"
sudo journalctl -u nginx --since yesterday --until today

Times are in the server's time zone (see set the time zone and NTP). --utc shows them in UTC instead.

Filter by priority

Every line has a priority from 0 (emerg) to 7 (debug). -p shows that level and everything more serious:

bash
sudo journalctl -p err -b              # errors and worse, this boot
sudo journalctl -p warning..err        # a range
Level Name Typical use
0-2 emerg, alert, crit The system or a service is unusable
3 err Something failed
4 warning Something odd that didn't fail
5-6 notice, info Normal operation
7 debug Detail for developers

journalctl -p err -b on a healthy server is short. Reading it after a deploy or an update is a quick way to catch a problem.

Filter by boot, and the kernel

bash
sudo journalctl -b            # this boot
sudo journalctl -b -1         # the boot before
sudo journalctl --list-boots
sudo journalctl -k            # kernel messages (like dmesg), this boot

-b -1 is how you find out why a server rebooted or what it was doing just before it hung. It only works if the journal is kept on disk; see the next section.

The kernel log is where the out-of-memory killer reports itself:

bash
sudo journalctl -k | grep -i -E 'out of memory|oom-kill'

Search and change the output

bash
sudo journalctl -u ssh --grep "Failed password"
sudo journalctl -u nginx -o short-iso        # full ISO timestamps
sudo journalctl -u myapp -o cat              # the messages only, no prefix
sudo journalctl -n 1 -o json-pretty          # every field of an entry

--grep takes a regular expression and is case-insensitive when the pattern is all lower case. json-pretty shows the fields you can filter on directly, such as _PID=1234, _UID=1000 or _COMM=sudo:

bash
sudo journalctl _COMM=sudo --since today     # who used sudo today

Keep logs after a reboot

The journal is kept on disk if /var/log/journal exists, and only in memory (lost at reboot) if it doesn't. That's the Storage=auto default. Check which you have:

bash
journalctl --header | grep -m1 'File path'

A path under /var/log/journal means persistent; /run/log/journal means in memory. On Ubuntu and Debian the directory exists out of the box. On AlmaLinux and Rocky Linux it often doesn't, because rsyslog writes the classic text files in /var/log instead.

To make it persistent everywhere, say so in a drop-in file:

bash
sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/50-storage.conf <<'EOF'
[Journal]
Storage=persistent
EOF
sudo systemctl restart systemd-journald
sudo journalctl --flush

Check it worked

bash
journalctl --header | grep -m1 'File path'

The path now starts with /var/log/journal/. After the next reboot, journalctl --list-boots lists more than one boot.

Limit how much disk the journal uses

bash
journalctl --disk-usage

By default the journal stops growing at 10% of the file system (and at most 4 GB). On a small disk you may want less. Add the limits to the same drop-in file:

ini
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=1month

SystemMaxUse caps the total; MaxRetentionSec drops entries older than that. Apply it with sudo systemctl restart systemd-journald, and check the combined result with:

bash
systemd-analyze cat-config systemd/journald.conf

To free space right now, without changing the settings:

bash
sudo journalctl --vacuum-size=200M
sudo journalctl --vacuum-time=2weeks

Vacuuming removes only archived journal files, never the one being written, so it may free less than you expect until the active file is rotated (sudo journalctl --rotate does that first).

Troubleshooting

-- No entries --. Nothing matched. The unit name may be wrong (ssh vs sshd), or the time window too narrow. Drop the filters one at a time.

Hint: You are currently not seeing messages from other users and the system. You ran it without sudo. Add sudo, or add your user to the systemd-journal group.

Specifying boot ID or boot offset has no effect, no persistent journal was found. The journal is in memory only, so earlier boots are gone. Make it persistent as above; it helps from the next boot on.

Journal file ... is truncated, ignoring file. Usually left from a crash or a full disk. sudo journalctl --verify lists the damaged files; deleting those files from /var/log/journal/ is safe.

Next steps

Doing it on VPSNine

If a VPSNine server won't boot far enough to let you in over SSH, the serial console shows the boot messages as they happen, and rescue mode lets you read the journal files from outside with journalctl -D /mnt/var/log/journal. Available on Ubuntu 24.04, Debian 13, AlmaLinux 10 and every other image, on all plans.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly or yearly, no lock-in
  • 14-day money-back guarantee