# 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.

Source: https://vpsnine.com/tutorials/read-logs-with-journalctl · Updated: 2026-10-21

Difficulty: beginner · Time: about 15 minutes · Tested on: Ubuntu 24.04 LTS, Debian 13 Stable, AlmaLinux 10

Prerequisites:

- 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](https://vpsnine.com/tutorials/set-timezone-and-ntp-linux)). `--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

- Free disk space when the journal or anything else has grown: [find and free disk space](https://vpsnine.com/tutorials/free-up-disk-space-linux).
- Turn your own app into a service whose output lands here: [write a systemd service](https://vpsnine.com/tutorials/create-a-systemd-service).
- Track down a process that's slowing the server: [troubleshoot high CPU and memory](https://vpsnine.com/tutorials/troubleshoot-high-cpu-and-memory).

## Doing it on VPSNine

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