Wichtige Linux-Logdateien, die Sie auf RHEL 9 und 10 überwachen müssen
Ein praktischer Leitfaden zu den Logdateien, die auf Red Hat Enterprise Linux 9 und 10 und kompatiblen Systemen (Oracle Linux, AlmaLinux, Rocky Linux) zählen: wo jede liegt, was sie Ihnen sagt, die Befehle, um sie zu lesen, und wie Sie sie aufbewahren und zentral sammeln.

Jedes Problem auf einem Linux-Server hinterlässt irgendwo eine Spur: eine fehlgeschlagene Anmeldung, ein Dienst, der nicht starten wollte, ein Paket-Update, das eine Bibliothek geändert hat, eine Platte, die begonnen hat, Fehler zu melden. Zu wissen, welche Logdatei welche Spur enthält, ist der Unterschied zwischen einer Diagnose in fünf Minuten und einem Nachmittag voller Raten. Dieser Leitfaden behandelt die Logdateien, die auf Red Hat Enterprise Linux 9 und 10 zählen, und auf kompatiblen Systemen wie Oracle Linux, AlmaLinux und Rocky Linux, mit den Befehlen, mit denen wir sie lesen.
Zwei Orte, an denen Logs auf RHEL liegen: das Journal und /var/log
Auf RHEL 9 und 10 wird fast alles zuerst von systemd-journald gesammelt. Das Journal ist ein strukturierter, indizierter Speicher, den Sie mit journalctl lesen. Bei einer Standardinstallation liest rsyslog anschließend das Journal und schreibt die vertrauten Textdateien in /var/log: messages, secure, cron, maillog und boot.log. Einige Dienste führen ohnehin eigene Dateien, insbesondere der Audit-Daemon, die Webserver, die Datenbanken und dnf.
Prüfen Sie, dass rsyslog installiert ist und läuft, bevor Sie sich auf die Textdateien verlassen. Minimal- und Container-Images enthalten es möglicherweise nicht:
rpm -q rsyslog
systemctl status rsyslog
# if it is missing:
dnf install rsyslog
systemctl enable --now rsyslog
Die meisten Dateien in /var/log sind nur für root lesbar, führen Sie die folgenden Befehle also als root oder mit sudo aus.
Das systemd-Journal
Das Journal ist der erste Ort, an dem Sie nachsehen, denn es enthält die Ausgabe jeder systemd-Unit, des Kernels und von allem, was über syslog protokolliert, alles mit präzisen Zeitstempeln und Metadaten, nach denen Sie filtern können.
Befehle, die man sich merken sollte
# everything from one service, newest last
journalctl -u nginx
# follow a service live, like tail -f
journalctl -u sshd -f
# only errors and worse, from the current boot
journalctl -p err -b
# warnings and worse from the previous boot (useful after a crash)
journalctl -p warning -b -1
# a time window
journalctl --since "1 hour ago"
journalctl -u php-fpm --since "2026-10-22 08:00" --until "2026-10-22 09:00"
# kernel messages only (the replacement for reading a dmesg file)
journalctl -k -b
# search message text
journalctl -u sshd -g "Failed password"
# list the boots the journal knows about
journalctl --list-boots
Mehrere -u-Optionen lassen sich kombinieren, was praktisch ist, wenn eine Anfrage mehr als einen Dienst durchläuft: journalctl -u nginx -u php-fpm --since "10 min ago".
Das Journal persistent machen
Bei einer Standardinstallation von RHEL liegt das Journal in /run/log/journal, im Arbeitsspeicher, und ist nach einem Neustart weg. Das ist genau der Moment, in dem Sie es am dringendsten brauchen. Um es auf der Platte zu behalten, legen Sie ein Drop-in an und starten journald neu:
mkdir -p /etc/systemd/journald.conf.d
vi /etc/systemd/journald.conf.d/persistent.conf
[Journal]
Storage=persistent
SystemMaxUse=2G
systemctl restart systemd-journald
journalctl --flush
ls -ld /var/log/journal
journalctl --disk-usage
SystemMaxUse begrenzt den Platz, den das Journal belegen darf. Wählen Sie einen Wert, der zur Platte passt. Nach dem nächsten Neustart zeigt journalctl --list-boots mehr als einen Eintrag, und journalctl -b -1 funktioniert.
/var/log/messages: das allgemeine Systemlog
Das ist die Sammeldatei: Starts und Stopps von Diensten, Kernel-Meldungen, Warnungen zu Hardware und Treibern, Netzwerkänderungen und alles andere, was auf Stufe info oder höher protokolliert wird und nicht in die Kategorien Mail, Authentifizierung oder cron gehört. Sie ist das Textäquivalent eines großen Teils des Journals und bequem für grep und für Werkzeuge, die einfache Dateien erwarten.
tail -f /var/log/messages
grep -iE "error|fail|oom" /var/log/messages | tail -50
grep -i "out of memory" /var/log/messages
Eine Zeile wie Out of memory: Killed process bedeutet, dass der Kernel einen Prozess beendet hat, weil dem Server der RAM ausgegangen ist. Die Antwort ist, der Workload mehr Speicher zu geben oder ihren Verbrauch zu senken (weniger PHP-FPM- oder Datenbank-Worker, ein Cache, das Beheben eines Lecks), nicht, das Symptom zu verstecken.
/var/log/secure: das Linux-Sicherheitslog für Authentifizierung und Privilegien
Jede SSH-Anmeldung, jedes falsche Passwort, jedes sudo und su sowie die PAM-Meldungen landen hier. Auf RHEL, Oracle Linux, AlmaLinux und Rocky Linux ist das die Datei, die Sie für den Zugriff auf den Server im Blick behalten.
# failed SSH passwords and the addresses they came from
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
# successful logins
grep "Accepted" /var/log/secure
# who used sudo, and for what
grep "COMMAND=" /var/log/secure
Zwei verwandte Werkzeuge vervollständigen das Bild. last listet erfolgreiche Anmeldungen aus /var/log/wtmp, und lastb listet fehlgeschlagene aus /var/log/btmp. Wenn Konten nach fehlgeschlagenen Versuchen gesperrt werden, zeigt faillock --user alice die Versuche, und faillock --user alice --reset setzt sie zurück.
/var/log/audit/audit.log: die Prüfspur
Das Audit-System von Linux zeichnet sicherheitsrelevante Ereignisse auf Kernel-Ebene auf: Anmeldungen, Privilegienwechsel, SELinux-Entscheidungen und jede Datei oder jeden Systemaufruf, den Sie überwachen möchten. Es wird von auditd geschrieben und mit ausearch und aureport statt mit grep gelesen, weil diese Werkzeuge sein Format verstehen.
# summary of everything in the log
aureport --summary
# failed logins
aureport --login --failed
# authentication attempts
aureport -au
# today's events, with numeric IDs turned into names
ausearch -ts today -i
# failed login events only
ausearch -m USER_LOGIN -sv no -i
Die Dateien überwachen, die zählen
Mit Audit-Regeln zeichnen Sie jede Änderung an einer sensiblen Datei auf. Legen Sie sie in einer Datei unter /etc/audit/rules.d/ ab, zum Beispiel /etc/audit/rules.d/50-watch.rules:
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
augenrules --load
auditctl -l
ausearch -k sshd_config -i
Der letzte Befehl zeigt, wer die SSH-Konfiguration geändert hat, wann und mit welchem Programm.
SELinux-Verweigerungen
RHEL läuft mit SELinux im Enforcing-Modus, und so sollte es bleiben. Wenn SELinux etwas blockiert, wird die Verweigerung als AVC-Eintrag im Audit-Log festgehalten. Sehen Sie dort nach, bevor Sie irgendetwas anderes ändern:
getenforce
ausearch -m AVC,USER_AVC -ts recent -i
ausearch -m AVC -ts today | audit2why
Für eine Erklärung in Klartext mit Lösungsvorschlägen installieren Sie setroubleshoot und lassen sealert über das Log laufen:
dnf install setroubleshoot-server
sealert -a /var/log/audit/audit.log
Die meisten Verweigerungen haben eine einfache Ursache: eine Datei mit falschem Label (beheben mit restorecon -Rv <path>), Inhalte in einem nicht standardmäßigen Verzeichnis (mit semanage fcontext labeln) oder eine Funktion, die ein eingeschaltetes Boolean braucht (getsebool -a | grep httpd, dann setsebool -P). Arbeiten Sie diese ab, bevor Sie an ein eigenes Policy-Modul denken.
/var/log/cron: geplante Aufgaben
Jeder von crond und anacron gestartete Job wird hier protokolliert, mit Benutzer und Befehl. Wenn ein Backup oder ein Bericht «nicht gelaufen ist», sagt Ihnen diese Datei, ob er überhaupt gestartet wurde.
grep CROND /var/log/cron | tail -20
grep "(root) CMD" /var/log/cron | tail -20
Viele Wartungsaufgaben von RHEL laufen inzwischen als systemd-Timer statt als Cron-Jobs. Listen Sie sie mit systemctl list-timers auf und lesen Sie ihre Ausgabe mit journalctl -u <name>.service, zum Beispiel journalctl -u logrotate.service.
/var/log/maillog: Mailzustellung
Postfix und andere Mailsoftware protokollieren hier jede Nachricht, die sie annehmen, weiterleiten, zurückstellen oder zurückweisen. Wenn eine Webanwendung sagt, sie habe eine E-Mail gesendet, und niemand sie erhalten hat, steht die Antwort meist in dieser Datei.
# the full path of one message, by recipient
grep "user@example.org" /var/log/maillog
# bounces and deferrals
grep -E "status=(bounced|deferred)" /var/log/maillog | tail -20
# what is still waiting in the queue
postqueue -p
Jede Postfix-Nachricht hat eine Queue-ID (zum Beispiel 4F2A81C0B3E). Suchen Sie mit grep nach dieser ID, um jeden Schritt ihrer Zustellung zu sehen, einschließlich der Antwort des empfangenden Servers.
/var/log/dnf.log und dnf history: was sich geändert hat
Wenn nach einer Wartung etwas kaputtgeht, lautet die erste Frage, was sich geändert hat. Auf RHEL 9 und 10 übernimmt dnf die Paketoperationen und schreibt /var/log/dnf.log (der dnf-Lauf selbst), /var/log/dnf.rpm.log (jedes installierte, aktualisierte oder entfernte Paket) und /var/log/dnf.librepo.log (Downloads aus Repositories). Die schnellste Übersicht ist die History-Datenbank:
# every transaction, newest first
dnf history
# exactly what one transaction did
dnf history info last
dnf history info 42
# every transaction that touched a package
dnf history list nginx
# packages changed recently, from the log file
grep -E "Install|Upgrade|Erase" /var/log/dnf.rpm.log | tail -30
# does anything need a restart after updates (dnf-plugins-core)
dnf needs-restarting -r
Muss ein Update zurückgenommen werden, macht dnf history undo <id> eine einzelne Transaktion rückgängig, sofern die älteren Pakete in den Repositories noch verfügbar sind.
/var/log/boot.log und das Boot-Journal
/var/log/boot.log enthält die Statusmeldungen des Systemstarts, die Sie auf der Konsole sehen würden. Für einen schnellen Blick ist es nützlich, aber die vollständige Aufzeichnung eines Boots steht im Journal:
cat /var/log/boot.log
journalctl -b -p err
journalctl -b -1 -p err # previous boot, needs the persistent journal
systemctl --failed # units that did not start
systemd-analyze blame | head # what took longest
Webserver- und PHP-Logs
Jeder Webserver führt seine eigenen Access- und Error-Logs:
- nginx:
/var/log/nginx/access.logund/var/log/nginx/error.log, plus alle Dateien pro Site, die Sie mitaccess_logunderror_logdefinieren. - Apache httpd:
/var/log/httpd/access_log,/var/log/httpd/error_logsowiessl_access_logundssl_error_log, wenn mod_ssl installiert ist. - PHP-FPM:
/var/log/php-fpm/error.logfür den FPM-Master und/var/log/php-fpm/www-error.logfür PHP-Fehler aus dem Standard-Pool. Der Pool kann außerdem ein Slow Log mit einem Stack Trace jeder langsamen Anfrage schreiben, sobaldrequest_slowlog_timeoutgesetzt ist.
# top client addresses (default nginx log format)
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# count of server errors (5xx) by URL
awk '$9 ~ /^5/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# the latest errors
tail -50 /var/log/nginx/error.log
tail -50 /var/log/php-fpm/www-error.log
Eine Häufung von 502- oder 504-Antworten im Access Log, begleitet von «upstream timed out» oder «connect() failed» im Error Log von nginx, deutet auf PHP-FPM: Entweder waren alle Worker beschäftigt, oder ein Skript lief zu lange.
Datenbank-Logs
- MariaDB (die Datenbank in den RHEL-Repositories):
/var/log/mariadb/mariadb.log, gesetzt überlog-errorin/etc/my.cnf.d/mariadb-server.cnf. - MySQL aus den RHEL-Repositories:
/var/log/mysql/mysqld.log. - PostgreSQL:
/var/lib/pgsql/data/log/, standardmäßig eine Datei pro Wochentag.
Das Error Log zeigt Startprobleme, Abstürze, beschädigte Tabellen und Replikationsfehler. Für die Performance aktivieren Sie das Slow Query Log. Für MariaDB ergänzen Sie den Abschnitt [mysqld] in /etc/my.cnf.d/mariadb-server.cnf und starten neu:
slow_query_log = 1
slow_query_log_file = /var/log/mariadb/mariadb-slow.log
long_query_time = 1
Fassen Sie es dann mit mysqldumpslow -s t /var/log/mariadb/mariadb-slow.log | head -40 zusammen, um zu sehen, welche Queries die meiste Gesamtzeit kosten.
Logs mit logrotate unter Kontrolle halten
RHEL rotiert Logdateien mit logrotate, das einmal täglich von einem systemd-Timer (logrotate.timer) ausgeführt wird. Die globalen Vorgaben stehen in /etc/logrotate.conf (wöchentlich, vier Rotationen, datierte Dateinamen wie messages-20261018), und jedes Paket ergänzt eigene Regeln unter /etc/logrotate.d/. Die Systemdateien (messages, secure, cron, maillog) werden von /etc/logrotate.d/rsyslog abgedeckt.
systemctl list-timers logrotate.timer
cat /etc/logrotate.d/nginx
# dry run: show what would happen, change nothing
logrotate -d /etc/logrotate.d/nginx
# force a rotation now, verbosely
logrotate -vf /etc/logrotate.d/nginx
Für Ihre eigene Anwendung legen Sie eine Datei wie /etc/logrotate.d/myapp an:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 myapp myapp
postrotate
/usr/bin/systemctl reload myapp.service >/dev/null 2>&1 || true
endscript
}
Halten Sie Anwendungslogs unter /var/log: Dateien dort bekommen das SELinux-Label, das logrotate verwalten darf. Ist das Logverzeichnis für einen anderen Benutzer als root beschreibbar, ergänzen Sie eine Zeile su myapp myapp, damit logrotate es sicher rotieren kann.
Das Journal rotiert sich selbst innerhalb der Grenze SystemMaxUse. Um es von Hand zu kürzen, verwenden Sie journalctl --vacuum-time=30d oder journalctl --vacuum-size=1G.
Logs zentral sammeln mit rsyslog
Logs, die nur auf dem Server liegen, den sie beschreiben, haben zwei Schwächen: Sie müssen sich auf jeder Maschine anmelden, um sie zu lesen, und ein Angreifer, der root erlangt, kann sie bearbeiten. Die Weiterleitung der Logs jedes Servers an einen zentralen Collector löst beides und lässt Sie während eines Vorfalls an einer Stelle suchen. Der Collector kann ein weiterer RHEL-Server mit rsyslog sein oder eine Log-Plattform wie Graylog.
Auf dem Collector
Legen Sie /etc/rsyslog.d/10-collector.conf an. Er lauscht auf TCP-Port 20514, den die SELinux-Policy bereits als Syslog-Port kennzeichnet (prüfen mit semanage port -l | grep syslogd), und schreibt eine Datei pro Host und Programm:
module(load="imtcp")
template(name="RemotePerHost" type="string"
string="/var/log/remote/%HOSTNAME:::secpath-replace%/%PROGRAMNAME:::secpath-replace%.log")
ruleset(name="remote") {
action(type="omfile" dynaFile="RemotePerHost")
}
input(type="imtcp" port="20514" ruleset="remote")
Öffnen Sie den Port nur für Ihre Server, hier über die firewalld-Zone internal, dann validieren und neu starten:
firewall-cmd --permanent --zone=internal --add-source=10.0.10.0/24
firewall-cmd --permanent --zone=internal --add-port=20514/tcp
firewall-cmd --reload
rsyslogd -N1
systemctl restart rsyslog
ss -tlnp | grep 20514
Wählen Sie einen Port, der noch nicht gelabelt ist, fügen Sie ihn zuerst mit semanage port -a -t syslogd_port_t -p tcp <port> hinzu, auf dem Collector und auf den Sendern. Ergänzen Sie eine logrotate-Regel für /var/log/remote//.log, wie oben gezeigt.
Auf jedem Server
Legen Sie /etc/rsyslog.d/90-central.conf an. TCP mit einer plattengestützten Warteschlange bedeutet, dass ein Neustart des Collectors oder eine Netzwerkunterbrechung Nachrichten verzögert, statt sie zu verlieren:
*.* action(type="omfwd" target="logs.example.net" port="20514" protocol="tcp"
template="RSYSLOG_SyslogProtocol23Format"
queue.type="LinkedList" queue.filename="fwd_central"
queue.maxDiskSpace="1g" queue.saveOnShutdown="on"
action.resumeRetryCount="-1")
rsyslogd -N1
systemctl restart rsyslog
Um auch Audit-Ereignisse zu versenden, setzen Sie active = yes in /etc/audit/plugins.d/syslog.conf und starten auditd mit service auditd restart neu (auditd akzeptiert keinen Neustart über systemctl).
Beweisen, dass es ankommt
Senden Sie eine Testnachricht und finden Sie sie auf dem Collector:
# on the server
logger -t logtest "central logging test from $(hostname)"
# on the collector
tail /var/log/remote/*/logtest.log
Wiederholen Sie den Test nach jeder Änderung am Collector oder an der Firewall, und alarmieren Sie bei Stille: Ein Server, der keine Logs mehr sendet, ist leicht zu übersehen, weil nichts in den Logs Ihnen davon erzählt.
Eine kurze tägliche Checkliste
journalctl -p err -b: etwas Neues auf Fehlerstufe seit dem Boot?aureport --login --failedundlastb | head: ungewöhnliche fehlgeschlagene Anmeldungen?ausearch -m AVC -ts today: SELinux-Verweigerungen?dnf history: hat sich etwas geändert, das Sie nicht geplant hatten?tail /var/log/nginx/error.logund das Error Log der Datenbank: Probleme in der Anwendung?journalctl --disk-usageunddf -h /var/log: Platz, um weiter zu protokollieren?
Das Lesen dieser Punkte dauert ein paar Minuten. Sie zu automatisieren, über einen zentralen Collector und Alarme auf die Muster, die zählen, ist das, was Logs von einem Archiv in eine Frühwarnung verwandelt.
Die Ingenieure von EuroVPS bauen, betreiben und überwachen solche Log-Pipelines für Kunden auf unseren Managed Servern.
Aus dem Blog-Archiv von EuroVPS, erstmals veröffentlicht am 19. April 2020.
Alle Notizen aus der Praxis