volllaufende Logs verhindern, bevor sie zum Notfall werden
Unrotierte Logdateien wachsen unbemerkt, bis eine Festplatte vollläuft und ein produktiver Server abstürzt. logrotate begrenzt Logdateien automatisch nach Größe oder Zeit, komprimiert alte Stände und führt Hooks wie Neustarts nach der Rotation aus. Dieser Artikel zeigt eine praxisnahe Konfiguration für eine eigene PHP Anwendung und wie man sie vor dem Einsatz sicher mit dem Debug Modus testet.
Inhaltsverzeichnis
- 1. Warum unrotierte Logs zum Problem werden
- 2. logrotate Grundlagen und Konfigurationsstruktur
- 3. Trigger: Size- und Time-basierte Rotation
- 4. Kompression und Aufbewahrung
- 5. Prerotate- und Postrotate-Hooks
- 6. Praktische Konfiguration für eine PHP-Anwendung
- 7. Sicheres Testen mit logrotate --debug
- 8. Automatisierung, Statusdatei und Deployment
- 9. logrotate im Vergleich: häufige Fehler vs. richtige Konfiguration
- 10. Zusammenfassung
- 11. FAQ
1. Warum unrotierte Logs zum Problem werden
Jede PHP-Anwendung, die Fehler protokolliert, Requests loggt oder eigene Monolog-Handler nutzt, schreibt kontinuierlich in eine oder mehrere Logdateien. Ohne Begrenzung wächst so eine Datei unbemerkt über Wochen und Monate, bis sie mehrere Gigabyte umfasst. Das eigentliche Problem zeigt sich erst, wenn die zugehörige Partition, häufig /var, zu 100 Prozent gefüllt ist: MySQL kann keine Schreiboperationen mehr durchführen, PHP-FPM-Worker sterben mit obskuren Fehlermeldungen, Cronjobs brechen lautlos ab und der Webserver liefert plötzlich 500er-Fehler aus, ohne dass im Code etwas verändert wurde.
In der Praxis trifft dieses Szenario überraschend häufig ein, weil Entwickler beim Deployment einer neuen Anwendung an alles Mögliche denken, nur selten an die Logrotation. Ein einfacher Check mit df -h zeigt die Belegung der Partitionen, du -sh /var/log/* /var/www/*/var/log/* deckt die größten Verursacher auf. logrotate ist auf praktisch jeder Linux-Distribution vorinstalliert und wird standardmäßig täglich über Cron oder einen systemd-Timer ausgeführt. Wer eigene Anwendungslogs nicht in dieses System einbindet, verschiebt das Platzproblem nur auf einen späteren, meist ungünstigeren Zeitpunkt.
2. logrotate Grundlagen und Konfigurationsstruktur
Die globale Konfiguration liegt unter /etc/logrotate.conf und definiert Standardwerte, die für alle nachfolgenden Regeln gelten, sofern sie nicht überschrieben werden. Anwendungsspezifische Regeln gehören nicht in diese zentrale Datei, sondern als eigene Datei nach /etc/logrotate.d/, die per include-Direktive automatisch eingelesen wird. Eine Regel besteht aus dem Pfad zur Logdatei, gefolgt von einem Block in geschweiften Klammern mit den gewünschten Direktiven wie Rotationsintervall, Anzahl der Kopien und Berechtigungen.
Ausgeführt wird logrotate nicht als Dauerprozess, sondern als einmaliger Aufruf, typischerweise über /etc/cron.daily/logrotate oder auf moderneren Systemen über die Timer-Unit logrotate.timer. Damit eine Logdatei nicht mehrfach am selben Tag rotiert wird, führt logrotate unter /var/lib/logrotate/status eine Statusdatei mit dem Zeitpunkt der letzten Rotation je Logpfad. Diese Trennung zwischen globaler Konfiguration, modularen Einzeldateien und einer Statusdatei macht das System übersichtlich, auch wenn Dutzende Anwendungen eigene Logs mitbringen.
# /etc/logrotate.conf - globale Standardwerte
weekly
rotate 4
create
dateext
compress
# Anwendungsspezifische Regeln werden hier eingebunden
include /etc/logrotate.d
# Beispiel: minimaler Regelblock in /etc/logrotate.d/beispiel
/var/log/beispiel/app.log {
daily
rotate 14
compress
missingok
notifempty
}
3. Trigger: Size- und Time-basierte Rotation
Zeitbasierte Rotation mit daily, weekly oder monthly ist der Standardfall und eignet sich gut, wenn das Log-Volumen über die Zeit einigermaßen vorhersehbar ist. Die Direktive rotate N legt fest, wie viele alte Versionen aufbewahrt werden, bevor die älteste gelöscht wird. Für Audit- oder Compliance-Anforderungen, bei denen ein definierter Zeitraum an Logs vorliegen muss, ist die zeitbasierte Rotation fast immer die richtige Wahl, weil sich die Aufbewahrungsdauer direkt aus rotate mal Intervall ableiten lässt.
Bei stark schwankendem Traffic, etwa während einer Rabattaktion oder eines DDoS-Versuchs, kann ein Log innerhalb weniger Stunden anwachsen, weit bevor die nächste tägliche Rotation greift. Hier hilft die Direktive size 100M, die unabhängig vom Zeitintervall rotiert, sobald die Datei die angegebene Größe überschreitet, oder die Kombination aus daily und maxsize 100M, die beide Kriterien gleichzeitig überwacht und bei Erreichen des ersten auslöst. Für produktive PHP-Anwendungen mit unklarem Wachstumsmuster ist diese Kombination aus Zeit- und Größentrigger die robusteste Lösung, weil sie sowohl planbare tägliche Rotation als auch einen Notfallmechanismus gegen plötzliche Log-Flut bietet.
4. Kompression und Aufbewahrung
Die Direktive compress komprimiert rotierte Logdateien standardmäßig mit gzip, was den Speicherbedarf bei typischen Textlogs um 80 bis 95 Prozent reduziert. Ein wichtiges Detail dabei ist delaycompress: Ohne diese Option wird die zuletzt rotierte Datei sofort komprimiert, obwohl der schreibende Prozess unter Umständen noch kurz in das alte, bereits umbenannte Dateihandle schreibt, bevor er es nach dem Hook schließt und neu öffnet. delaycompress verschiebt die Kompression auf den nächsten Rotationszyklus und verhindert so, dass verlorene Schreibvorgänge in einer bereits komprimierten Datei landen und dort unbemerkt bleiben.
Für abweichende Kompressionswerkzeuge lassen sich compresscmd und compressext setzen, etwa um xz statt gzip zu nutzen, wenn Speicherplatz knapper ist als CPU-Zeit. Die Direktive dateext hängt statt einer fortlaufenden Nummer das Rotationsdatum an den Dateinamen an, was die Zuordnung beim manuellen Durchsuchen alter Logs erheblich erleichtert. In Kombination mit dateformat -%Y%m%d lässt sich das Format an die eigenen Konventionen anpassen, etwa um es konsistent mit anderen Backup-Skripten zu halten.
5. Prerotate- und Postrotate-Hooks
Der postrotate-Block enthält Shell-Befehle, die direkt nach der Rotation ausgeführt werden, und ist bei fast jeder Produktionskonfiguration notwendig. Der Grund liegt in der Funktionsweise von logrotate: Standardmäßig wird die alte Datei umbenannt und eine neue, leere Datei mit demselben Namen erzeugt. Der schreibende Prozess hat aber weiterhin das alte, nun umbenannte Dateihandle offen und schreibt munter in die inzwischen unsichtbare, rotierte Datei weiter, statt in die neue. Der postrotate-Hook signalisiert der Anwendung, das Dateihandle neu zu öffnen, etwa per systemctl reload php-fpm oder einem gezielten Signal an den Prozess.
Der prerotate-Block läuft entsprechend vor der Rotation und eignet sich für Vorprüfungen oder das Setzen eines Locks. Wenn eine Konfiguration mehrere Glob-Muster gleichzeitig abdeckt, verhindert sharedscripts, dass der Hook für jede einzelne passende Datei separat läuft, was bei einem Reload-Befehl unnötige Mehrfachausführungen und potenzielle Race Conditions vermeidet. Jeder postrotate- und prerotate-Block muss mit endscript abgeschlossen werden, sonst interpretiert logrotate die folgenden Zeilen fälschlich als weitere Shell-Befehle.
#!/usr/bin/env bash
# Ausschnitt aus einem postrotate-Block: Log-Handle nach Rotation neu öffnen
postrotate
# PHP-FPM neu laden, damit der Master-Prozess die Logdatei neu öffnet
if systemctl is-active --quiet php8.3-fpm; then
systemctl reload php8.3-fpm
fi
# Alternative für Anwendungen mit eigenem Signal-Handler
if [ -f /run/myapp/myapp.pid ]; then
kill -USR1 "$(cat /run/myapp/myapp.pid)" 2>/dev/null || true
fi
endscript
6. Praktische Konfiguration für eine PHP-Anwendung
Eine typische PHP-Anwendung schreibt über Monolog oder eine eigene Logging-Klasse nach /var/www/myapp/var/log/app.log, ausgeführt unter dem Systembenutzer www-data. Für diesen Fall sind missingok und notifempty essenziell: missingok verhindert einen Fehler, falls die Logdatei zwischenzeitlich nicht existiert, etwa nach einem frischen Deployment, und notifempty überspringt die Rotation, wenn seit dem letzten Lauf ohnehin keine neuen Zeilen geschrieben wurden. Die Direktive create 0640 www-data www-data sorgt dafür, dass die neue, leere Logdatei mit den korrekten Berechtigungen entsteht, statt versehentlich mit root als Eigentümer, was sonst dazu führt, dass die Anwendung nach der ersten Rotation nicht mehr schreiben kann.
Bei der Wahl zwischen create und copytruncate gilt: create in Kombination mit einem korrekten postrotate-Hook ist die sauberere Lösung, weil kein Datenverlust zwischen Kopieren und Leeren der Datei entstehen kann. copytruncate kopiert den aktuellen Inhalt und leert anschließend die Originaldatei, ohne das Dateihandle zu wechseln, was für Anwendungen ohne Reload-Mechanismus praktisch ist, aber ein kleines Zeitfenster für verlorene Schreibvorgänge zwischen Kopie und Truncate offenlässt. Für eigene PHP-Anwendungen mit Kontrolle über den Deployment-Prozess ist daher create plus Reload-Hook die empfohlene Standardlösung.
# /etc/logrotate.d/myapp
/var/www/myapp/var/log/app.log {
daily
maxsize 100M
rotate 14
compress
delaycompress
missingok
notifempty
dateext
dateformat -%Y%m%d
create 0640 www-data www-data
sharedscripts
postrotate
systemctl reload php8.3-fpm >/dev/null 2>&1 || true
endscript
}
7. Sicheres Testen mit logrotate --debug
Eine neue logrotate-Konfiguration niemals ungetestet in Produktion laufen lassen: Der Aufruf logrotate -d /etc/logrotate.d/myapp aktiviert den Debug-Modus, der die Konfiguration einliest, Syntaxfehler meldet und ausgibt, welche Datei nach welchem Kriterium rotiert würde, ohne tatsächlich eine Datei umzubenennen, zu komprimieren oder einen Hook auszuführen. Das macht den Debug-Modus ideal, um schnell zu prüfen, ob die Konfiguration überhaupt gefunden und korrekt geparst wird, bevor man sich auf den nächsten Cron-Lauf verlässt.
Reicht der reine Syntax-Check nicht aus, erzwingt logrotate -f /etc/logrotate.d/myapp eine echte Rotation, unabhängig davon, ob das Zeit- oder Größenkriterium erfüllt ist. Das sollte zuerst in einer Staging-Umgebung erfolgen, da hierbei Dateien tatsächlich rotiert, komprimiert und Hooks ausgeführt werden. Nach einem erzwungenen Lauf lohnt es sich, mit ls -la /var/www/myapp/var/log/ die Berechtigungen der neuen Datei zu prüfen und mit systemctl status php8.3-fpm zu bestätigen, dass der Reload-Hook tatsächlich gegriffen hat. Nur wenn beide Tests sauber durchlaufen, gehört die Konfiguration in Produktion.
# Syntax und Trigger prüfen, ohne etwas zu verändern
$ logrotate -d /etc/logrotate.d/myapp
reading config file /etc/logrotate.d/myapp
Allocating hash table for state file, size 15360 B
Handling 1 logs
rotating pattern: /var/www/myapp/var/log/app.log
100M bytes in size OR forced from command line (14 rotations)
empty log files are not rotated, old logs are removed
considering log /var/www/myapp/var/log/app.log
log needs rotating
rotating log /var/www/myapp/var/log/app.log, log->rotateCount is 14
dateext suffix '-20260712'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
renaming /var/www/myapp/var/log/app.log to /var/www/myapp/var/log/app.log-20260712
running postrotate script
compressing log with: /bin/gzip
# Echte Rotation erzwingen (zuerst in Staging testen)
$ logrotate -f /etc/logrotate.d/myapp
$ ls -la /var/www/myapp/var/log/
8. Automatisierung, Statusdatei und Deployment
Auf modernen Distributionen läuft logrotate nicht mehr zwingend über /etc/cron.daily/, sondern über die Timer-Unit logrotate.timer, die sich mit systemctl list-timers | grep logrotate überprüfen lässt. Die Statusdatei /var/lib/logrotate/status hält für jeden Logpfad den Zeitpunkt der letzten Rotation fest, damit ein Log nicht mehrfach am selben Tag rotiert wird, wenn logrotate aus irgendeinem Grund mehrfach aufgerufen wird. Ein häufiger Fehler bei manuellen Tests: Das Löschen dieser Statusdatei zwingt logrotate dazu, beim nächsten Lauf sämtliche konfigurierten Logs auf einmal zu rotieren, was in Produktion unnötige Last erzeugt.
Für Serverflotten mit mehreren gleich aufgebauten Anwendungen lohnt es sich, die logrotate-Konfiguration als Teil des Deployment-Prozesses zu verwalten statt sie manuell auf jedem Server zu pflegen. Ein Konfigurationsmanagement-Werkzeug wie Ansible kann die Datei aus einer Vorlage generieren und direkt im Anschluss mit logrotate -d validieren, bevor sie als gültig markiert wird. So bleibt die Rotation über alle Umgebungen hinweg konsistent, und Änderungen an der Konfiguration lassen sich wie jede andere Codeänderung versionieren und nachvollziehen.
# Ansible-Task: logrotate-Konfiguration deployen und sofort validieren
- name: logrotate Konfiguration für myapp bereitstellen
ansible.builtin.template:
src: templates/logrotate-myapp.j2
dest: /etc/logrotate.d/myapp
owner: root
group: root
mode: "0644"
notify: logrotate config validieren
- name: Handler zur Validierung der Konfiguration
ansible.builtin.command:
cmd: logrotate -d /etc/logrotate.d/myapp
listen: logrotate config validieren
changed_when: false
9. logrotate im Vergleich: häufige Fehler vs. richtige Konfiguration
Die meisten Probleme mit logrotate entstehen nicht durch fehlende Funktionalität, sondern durch unvollständige Konfigurationen, die in der Testphase nicht auffallen und erst Wochen später in Produktion sichtbar werden. Die folgende Übersicht zeigt die häufigsten Fehlerquellen im direkten Vergleich zur empfohlenen Lösung.
| Aufgabe | Häufiger Fehler | Richtige Konfiguration | Vorteil |
|---|---|---|---|
| Rotations-Trigger | nur monthly, kein Größenlimit |
daily + maxsize 100M |
verhindert Log-Flut zwischen Zyklen |
| Dateihandle nach Rotation | kein postrotate-Hook |
Reload/Signal im postrotate-Block |
Platz wird tatsächlich freigegeben |
| Berechtigungen neuer Datei | Standard-create ohne Owner |
create 0640 www-data www-data |
Anwendung kann sofort weiterschreiben |
| Konfiguration testen | direkt deployen, auf Cron warten | logrotate -d vor dem Rollout |
Fehler sofort sichtbar, nicht erst live |
| Aufbewahrung | kein rotate N gesetzt |
rotate 14 + compress |
Speicherverbrauch bleibt begrenzt |
Auffällig ist, dass fast jeder dieser Fehler erst mit Verzögerung sichtbar wird: Ein fehlender postrotate-Hook zeigt sich erst, wenn df -h trotz erfolgter Rotation keinen freien Speicher meldet, weil der alte Prozess weiterhin in die gelöschte, aber noch geöffnete Datei schreibt. Wer die Kombination aus Trigger, Hook und Testphase konsequent einhält, vermeidet genau diese Klasse von schwer reproduzierbaren Produktionsproblemen.
Mironsoft
Server-Administration, Log-Management und Deployment-Automatisierung
Logdateien, die eurem Server nicht gefährlich werden?
Wir prüfen bestehende Logrotation, richten robuste logrotate-Konfigurationen mit Size-/Time-Triggern und sauberen postrotate-Hooks ein und testen sie kontrolliert, bevor sie in Produktion laufen.
Log-Audit
Bestehende Logpfade, Wachstum und Risiken auf allen Servern erfassen
Konfiguration
Passende logrotate-Regeln mit Kompression und Reload-Hooks einrichten
Deployment
Logrotation als versioniertes Konfigurationsmanagement ausrollen
10. Zusammenfassung
Log-Rotation mit logrotate löst ein Problem, das in produktiven Umgebungen unterschätzt wird: Ohne Begrenzung wachsen Logdateien, bis eine Partition vollläuft und Dienste wie MySQL oder PHP-FPM nicht mehr schreiben können. Die Kombination aus zeit- und größenbasiertem Trigger, etwa daily zusammen mit maxsize 100M, deckt sowohl planbares als auch plötzliches Log-Wachstum ab. Kompression mit compress und delaycompress reduziert den Speicherbedarf drastisch, ohne Schreibvorgänge während des Rotationsfensters zu gefährden.
Der entscheidende Baustein für eine funktionierende Konfiguration ist der postrotate-Hook, der die Anwendung nach der Rotation zum Neuöffnen des Dateihandles bewegt, weil sonst kein Speicherplatz freigegeben wird, obwohl die Rotation formal erfolgreich lief. Vor jedem Rollout gehört ein Test mit logrotate -d zur Pflicht, um Syntaxfehler und falsche Trigger sofort zu erkennen, statt sie erst Tage später in Produktion zu entdecken.
Log-Rotation mit logrotate, das Wichtigste auf einen Blick
Trigger kombinieren
daily + maxsize 100M deckt planbares und plötzliches Log-Wachstum gleichzeitig ab.
Hooks für Log-Handles
postrotate mit Reload oder Signal, sonst wird kein Speicherplatz tatsächlich frei.
Sichere Berechtigungen
create 0640 www-data www-data verhindert Schreibfehler direkt nach der Rotation.
Testen vor Rollout
logrotate -d prüft Syntax und Trigger, ohne Dateien anzufassen oder Hooks auszuführen.