Homelab Academy / Modules
Guided practice + break/fix + lab gate.
Module: Linux Foundations
Activity type: Lab (Practice)
Lab risk: low
Objective: Explain the relationship between applications, systemd units, systemd-journald, and journalctl.
Build a Read-Only Journal Evidence Set
Run all commands from a single shell session.
Do not change journal configuration, restart services, rotate journals, or remove journal data.
All files created or changed by this lab must remain under /opt/lab-classroom/class20/.
The journal commands in this lab are read-only; shell redirection creates only the specified evidence files.
1
Confirm that the classroom directory already exists, is the expected path, and is writable. Stop if any check fails.
cd /opt/lab-classroom/class20/ && test "$(pwd -P)" = "/opt/lab-classroom/class20" && test -w . && printf 'Lab directory verified: %s\n' "$(pwd -P)"
2
Set a restrictive file-creation mask for this shell so exported logs are not broadly readable.
umask 077
3
Record the boots known to the local journal.
journalctl --list-boots --no-pager > /opt/lab-classroom/class20/boots.txt
4
Export the latest 100 records from the current boot in an ISO-like timestamp format.
journalctl -b -n 100 --no-pager -o short-iso > /opt/lab-classroom/class20/recent-current-boot.log
5
Export warning-and-higher-priority records from the current boot. An empty file is a valid result when no accessible records match.
journalctl -b -p warning --no-pager -o short-iso > /opt/lab-classroom/class20/warnings-current-boot.log
6
Export records associated with the journal service during the current boot.
journalctl -b -u systemd-journald.service --no-pager -o short-iso > /opt/lab-classroom/class20/journald-unit.log
7
Export up to 20 recent accessible records as newline-delimited JSON for structured inspection.
journalctl -b -n 20 --no-pager -o json > /opt/lab-classroom/class20/recent.jsonl
8
Use Python to count the PRIORITY values present in the JSON export. Malformed or inaccessible input causes the command to fail instead of silently inventing data.
python3 - <<'PY' > /opt/lab-classroom/class20/priority-summary.txt
import collections
import json
from pathlib import Path
source = Path('/opt/lab-classroom/class20/recent.jsonl')
counts = collections.Counter()
records = 0
with source.open('r', encoding='utf-8') as handle:
for line_number, line in enumerate(handle, 1):
if not line.strip():
continue
record = json.loads(line)
records += 1
counts[str(record.get('PRIORITY', 'missing'))] += 1
print(f'records={records}')
for priority in sorted(counts):
print(f'priority_{priority}={counts[priority]}')
PY
9
Capture the journal's reported disk usage as contextual information without changing retention.
journalctl --disk-usage > /opt/lab-classroom/class20/journal-disk-usage.txt
10
Record file names, sizes, and permissions for the evidence set.
find /opt/lab-classroom/class20/ -maxdepth 1 -type f -printf '%f\t%s bytes\t%m\n' | sort > /opt/lab-classroom/class20/evidence-manifest.txt
How many boots are visible to the current account?
Which timestamps bound the current-boot sample?
Are any warning-or-higher records visible, and which units or processes produced them?
Which structured fields appear in the JSON records but not in the short-iso display?
Does the journald unit query return records, and could access restrictions explain an empty result?
Do the manifest permissions prevent access by group and other users?
| Symptom | Likely cause | Fix |
|---|---|---|
| The initial directory verification fails. | The classroom directory is absent, resolves to another path, or is not writable by the learner. | Stop the lab and have the lab administrator provision /opt/lab-classroom/class20/ with appropriate ownership. Do not redirect output to an alternate system path. |
| journalctl reports that no journal files were found. | The host does not use systemd-journald, journal storage is unavailable, or the environment exposes no journal to the learner. | Confirm that the machine is systemd-based and run systemctl status systemd-journald as a read-only check. Use a compatible lab VM if the host does not provide the journal. |
| Only a small number of records are visible. | The account has limited permissions, the host has a quiet current boot, or retention is limited. | Treat the visible subset as the authorized dataset. Ask an administrator to confirm access policy rather than weakening file permissions. |
| boots.txt lists only the current boot. | The journal may be volatile, older records may have been removed by retention policy, or previous boot data may not be accessible. | Document the limitation. Do not change storage or retention settings as part of this lab. |
| warnings-current-boot.log is empty. | No accessible current-boot records match warning or a more severe priority. | Verify that the unfiltered current-boot export contains records. An empty filtered result is valid and must not be treated as a command failure by itself. |
| The journald unit export is empty. | No matching records are retained, the local unit name differs, or the learner cannot access system-level records. | Run systemctl status systemd-journald as a read-only check and inspect accessible unit names with systemctl list-units --type=service --no-pager. |
| Python raises a JSON parsing error. | recent.jsonl is incomplete, was edited, or was not generated with JSON output. | Regenerate only recent.jsonl with the documented journalctl command, then rerun the parser. |
| Evidence files are readable by group or other users. | The restrictive umask was not set in the same shell before the files were created, or existing files retained broader modes. | Remove the affected evidence files using the scoped rollback procedure, set umask 077 in the active shell, and regenerate the files. |
| A query returns many unrelated messages. | The query lacks a boot, time, unit, priority, or field boundary. | Add the narrowest appropriate selector and confirm each selector independently before combining them. |
Journal records may expose usernames, hostnames, network addresses, process arguments, authentication activity, application data, and operational details.
Use the least privilege required to inspect relevant records.
Do not broaden journal or evidence-file permissions merely to avoid an access-control error.
Keep exported evidence inside /opt/lab-classroom/class20/ and use a restrictive umask.
Review evidence before sharing it and redact sensitive values only in a separate copy so the original observation remains intact.
An exported record is a snapshot, not a trusted authorization decision or conclusive proof of causality.
Do not perform journal rotation, vacuuming, retention changes, or service restarts during evidence collection.
Distribution policy determines which journal records an unprivileged user can read. Administrative access may reveal substantially more sensitive data, so it should be used only when required and authorized.
Record the exact query, boot scope, and collection time when preserving evidence. Avoid editing the original exports.
Rollback removes only evidence files created by this lesson and does not alter the system journal.
find /opt/lab-classroom/class20/ -maxdepth 1 -type f ( -name 'boots.txt' -o -name 'recent-current-boot.log' -o -name 'warnings-current-boot.log' -o -name 'journald-unit.log' -o -name 'recent.jsonl' -o -name 'priority-summary.txt' -o -name 'journal-disk-usage.txt' -o -name 'evidence-manifest.txt' ) -delete
find /opt/lab-classroom/class20/ -maxdepth 1 -type f -printf '%f\n' | sort
None of the eight lesson-created evidence file names remain, and no files outside /opt/lab-classroom/class20/ were changed.