On a systemd host, /var is nearly full and /var/log/journal accounts for several gigabytes. How do you reclaim the space now with journalctl, and how do you cap the journal so it cannot grow that far again?
answer
- measure first, then delete
- the active file is exempt
- rotate before you vacuum
- defaults are proportional, not fixed
- cap in a drop-in, restart journald
basics
~10 sMeasure with journalctl --disk-usage, then run journalctl --rotate followed by --vacuum-size= or --vacuum-time=, because vacuuming only removes archived files. Cap growth permanently with SystemMaxUse= and SystemKeepFree= in journald.conf and restart systemd-journald.
solid answer
~40 sFirst measure: `journalctl --disk-usage` reports what the journal actually occupies and which path it is measuring. Then reclaim: `journalctl --vacuum-size=500M`, `--vacuum-time=7d` or `--vacuum-files=5` delete old journal files, but only **archived** ones — the currently active file is never removed — so I run `journalctl --rotate` first to close it, then vacuum. That is the difference between reclaiming a few hundred megabytes and reclaiming what you expected. Then I stop it recurring by writing a drop-in under `/etc/systemd/journald.conf.d/` with `SystemMaxUse=1G` and, if the filesystem is shared, `SystemKeepFree=`, plus `SystemMaxFileSize=` to keep individual files rotatable, and restart `systemd-journald`. The reason it grew is usually that the defaults are proportional — 10% of the filesystem, capped at 4 GB — which on a large `/var` is a lot of room.
go deeper
Know that journalctl --disk-usage reports the journal's size and that --vacuum-size=/--vacuum-time= reclaim space. Recognise that journald rotates its own files rather than relying on logrotate.
Explain that vacuuming touches only archived files, so --rotate comes first, and name the four System* limits with the fact that the unset defaults are proportional — 10% of the filesystem capped at 4 GB, plus 15% kept free.
Sequence the incident: measure, confirm the journal is really the consumer, rotate and vacuum to buy space, then write a drop-in with explicit caps and restart journald — and finish by identifying the unit that produced the volume rather than stopping at the disk.
Own the tradeoff between disk safety and retention depth: a cap that protects /var also decides how far back an investigation can reach, and on a chatty fleet a single noisy service silently evicts everyone else's history.
## Measure before you delete ```bash journalctl --disk-usage # Archived and active journals take up 3.9G in the file system. du -sh /var/log/journal/* ``` `--disk-usage` counts both archived and active files and names the path, which incidentally tells you whether you are looking at the persistent journal or the runtime one. If it reports megabytes while `du` on `/var` shows gigabytes, the journal is not your problem and you should go look at `/var/lib` instead — a mistake worth ruling out in the first thirty seconds of a full-disk page. ## How journald manages its own files journald is its own rotation manager; `logrotate` has nothing to do with it. It writes to an **active** journal file per journal set, and when that file hits `SystemMaxFileSize=` — or when rotation is requested — it renames it to an archived file (`system@<seq>.journal`) and starts a new active one. Retention is then enforced by deleting whole archived files, oldest first, until the configured limits are satisfied. This is why the limits are approximate: the granularity of deletion is a file, not an entry. ## Reclaiming space now Three vacuum forms, all of which operate on **archived files only**: ```bash journalctl --vacuum-size=500M # keep the journal set under this total journalctl --vacuum-time=7d # drop entries older than this journalctl --vacuum-files=5 # keep at most this many files per set ``` The trap that costs people an outage-minute: because the active file is exempt, a journal that is one enormous active file will barely shrink. Rotate first: ```bash sudo journalctl --rotate sudo journalctl --vacuum-time=2d journalctl --disk-usage ``` `--rotate` closes the active file and archives it, so the subsequent vacuum can consider it. The two can also be given in a single invocation. Note also that vacuum limits are applied per journal set — the system journal and each user journal are separate sets — so `--vacuum-size=500M` is not a global 500 MB budget on a host with busy user journals. Resist deleting files under `/var/log/journal` by hand. It usually works, but the vacuum path lets journald keep its own bookkeeping consistent and refuses to break the active file; `rm` does neither, and a truncated or half-deleted set is a worse morning. ## Capping it permanently The settings live in `/etc/systemd/journald.conf` or, better, a drop-in: ```ini # /etc/systemd/journald.conf.d/limits.conf [Journal] SystemMaxUse=1G SystemKeepFree=2G SystemMaxFileSize=128M SystemMaxFiles=20 ``` - `SystemMaxUse=` — the total the persistent journal may occupy. Unset, it defaults to **10% of the filesystem's size, capped at 4 GB**, which on a 200 GB `/var` means journald was entitled to every one of those gigabytes it took. - `SystemKeepFree=` — the free space journald will leave on that filesystem, defaulting to **15% of it**. This is the one that matters when `/var` is shared with something else that needs room, because journald will delete its own history to honour it. - `SystemMaxFileSize=` — the size at which the active file rotates. Keep it well under `SystemMaxUse=`; a single file that is most of the budget makes retention lumpy, since deleting one file drops a huge slice of history at once. - `SystemMaxFiles=` — a cap on file count per set. Each has a `Runtime*` twin (`RuntimeMaxUse=`, `RuntimeKeepFree=`, …) governing the volatile journal in `/run` — worth setting too, because that one consumes RAM. journald applies whichever limit binds first. Reload with `systemctl restart systemd-journald`, and confirm the effective configuration with `systemd-analyze cat-config systemd/journald.conf`, since a vendor drop-in may already be setting what you think you are setting. ## Then ask why it filled Capping the journal makes the disk safe but throws away the question. A journal that grew to gigabytes in days is usually one unit in a loop — a crash-restart cycle, a stack trace per request, a debug level left on after an investigation. Find it before you walk away: ```bash journalctl --since "1 day ago" -o json --output-fields=_SYSTEMD_UNIT | \ sort | uniq -c | sort -rn | head ``` Or, more cheaply, look at what `systemctl list-units --failed` and the restart counters say. The fix is often in the unit — a `Restart=` policy that hides a crash loop, or a log level — and not in journald at all. Note the second-order effect too: capping `SystemMaxUse=` on a chatty host silently shortens your retention window, so the incident three days ago may no longer be in the journal when you go looking. ## Version note These directive names are stable across current systemd releases; `--vacuum-files=` is the newest of the three vacuum forms and is present on every systemd shipping with a currently supported distribution.
- Why can `journalctl --vacuum-size=200M` leave the journal well above 200 MB?Vacuuming only deletes archived journal files; the currently active file is never removed, so a journal dominated by one large active file barely shrinks. Run `journalctl --rotate` first to archive it, then vacuum. Also remember the limit is per journal set, so busy user journals are counted separately from the system journal.
- If SystemMaxUse= is unset, is the journal unbounded?No. It defaults to 10% of the size of the filesystem holding the journal, capped at 4 GB, and `SystemKeepFree=` independently reserves 15% of the filesystem's free space. Both are proportional to the disk rather than to what you want to retain, which is exactly why a journal on a large `/var` can grow to several gigabytes without anything being misconfigured.
- You capped the journal and the disk is safe. What have you not fixed?Whatever produced gigabytes of entries. A cap converts a disk problem into a retention problem: the noisy unit keeps logging and now evicts everyone else's history faster. Identify the unit — by counting `_SYSTEMD_UNIT` values over the last day, or from failed units and restart counters — and fix the crash loop or log level at the source.
- Should you ever just `rm` files under /var/log/journal?Prefer not to. The vacuum path keeps journald's own bookkeeping consistent and never touches the active file, whereas `rm` can remove a file journald is still writing to and leave a damaged set. If you are desperate on a wedged host, rotate first so the active file is archived, and verify afterwards with `journalctl --verify`.
saying these in an interview costs you the question
- Thinks logrotate rotates the systemd journal
- Vacuums without rotating and expects the active file to go
- Assumes an unset SystemMaxUse means unlimited
- Deletes /var/log/journal files with rm
- Caps the journal and never finds the noisy unit