Log-Rotation mit logrotate konfigurieren
$
/etc
Linux · logrotate · Log-Management · Server-Administration
Log-Rotation mit logrotate konfigurieren
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.

16 Min. Lesezeit Size-/Time-Trigger · Kompression · postrotate logrotate · systemd · Debian/Ubuntu · RHEL

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.

11. FAQ: Log-Rotation mit logrotate

1Was ist logrotate und wozu wird es gebraucht?
Standard-Tool unter Linux, das Logdateien nach Zeit oder Größe rotiert, komprimiert und alte Versionen löscht, um volllaufende Partitionen zu verhindern.
2Was passiert, wenn Logs nicht rotiert werden?
Die Partition läuft voll, MySQL und PHP-FPM können nicht mehr schreiben, Cronjobs brechen ab, der Webserver liefert 500er-Fehler ohne Codeänderung.
3Unterschied zwischen size und daily als Kriterium?
daily rotiert nach festem Intervall, size/maxsize nach Erreichen einer Größenschwelle. Die Kombination deckt planbares und plötzliches Wachstum ab.
4Wozu dient delaycompress?
Verschiebt die Kompression um einen Zyklus, weil der Prozess kurz noch ins alte Handle schreiben kann. Verhindert verlorene Schreibvorgänge in bereits komprimierten Dateien.
5Wie funktioniert postrotate, und wann läuft es?
Shell-Befehle direkt nach dem Umbenennen der Logdatei, meist um die Anwendung zum Neuöffnen ihres Dateihandles zu bewegen.
6Reicht ein Signal, oder brauche ich einen Neustart?
Ein Reload oder gezieltes Signal reicht, um das Dateihandle neu zu öffnen, ohne aktive Requests zu unterbrechen. Ein vollständiger Neustart ist nicht nötig.
7Wie teste ich eine Konfiguration sicher?
Mit logrotate -d /etc/logrotate.d/dateiname. Zeigt Syntax und geplante Aktionen, ohne Dateien anzufassen oder Hooks auszuführen.
8Was macht /var/lib/logrotate/status?
Speichert je Log den Zeitpunkt der letzten Rotation. Gelöscht, rotiert logrotate beim nächsten Lauf alle Logs auf einmal.
9Wie oft läuft logrotate, und wie ändere ich das?
Standardmäßig täglich über cron.daily oder logrotate.timer. Für häufigere Prüfung lässt sich ein eigener Cronjob oder Timer anlegen.
10Was ist ein häufiger Konfigurationsfehler?
Fehlender postrotate-Hook, wodurch kein Speicherplatz freigegeben wird. Ebenfalls häufig: fehlende Owner-Angabe bei create, was Schreibfehler verursacht.