Disk-Space-Analyse mit du und df
$
/etc
Linux · Systemadministration · Disk Space · PHP-Server
Disk-Space-Analyse mit du und df
Versteckte Speicherfresser in Sekunden finden

Eine Platte, die plötzlich voll läuft, legt Deployments und Datenbanken lahm, oft ohne Vorwarnung. Mit df findet ihr sofort, welches Dateisystem betroffen ist, mit du -sh sortiert nach Größe den genauen Verursacher, und mit dem passenden Handwerkszeug räumt ihr Logs, Caches und alte Releases zuverlässig auf, bevor der Server ausfällt.

14 Min. Lesezeit du · df · lsof · logrotate Ubuntu · Debian · PHP-FPM · Magento

1. Warum df und du zusammengehören

df und du beantworten zwei unterschiedliche Fragen, die auf den ersten Blick wie dieselbe klingen. df (disk free) liest die Belegungsstatistik direkt aus dem Superblock eines gemounteten Dateisystems aus und beantwortet die Frage: Wie voll ist diese Partition insgesamt? du (disk usage) dagegen durchläuft rekursiv einen Verzeichnisbaum und summiert die Größe jeder einzelnen Datei, um die Frage zu beantworten: Was innerhalb dieses Baums belegt den Platz? Der eine Befehl liefert eine Kennzahl pro Dateisystem, der andere eine Aufschlüsselung pro Verzeichnis.

Daraus ergibt sich in der Praxis ein fester Workflow: Zuerst df -h ausführen, um festzustellen, welche Partition kritisch voll ist, zum Beispiel /var oder /. Danach mit du gezielt in diese Partition hineingehen und Verzeichnis für Verzeichnis eingrenzen, bis der eigentliche Verursacher gefunden ist. Wer nur eines der beiden Werkzeuge kennt, verliert bei einem akuten Speicherplatzproblem wertvolle Zeit, weil entweder der Überblick oder die Detailtiefe fehlt.

2. df: Speicherplatz auf Dateisystem-Ebene messen

df -h liefert eine für Menschen lesbare Übersicht aller gemounteten Dateisystem mit Gesamtgröße, belegtem Platz, freiem Platz und Prozentangabe. Wichtig ist, gezielt nach der Zeile mit dem betroffenen Mountpoint zu suchen, etwa / oder /var/www, statt sich nur die erste Zeile anzusehen. Auf Servern mit separaten Partitionen für /var/log oder /tmp kann eine dieser kleineren Partitionen voll sein, während die Root-Partition noch reichlich Platz hat, das Symptom im Log ist dann oft ein „No space left on device“, obwohl df -h / harmlos aussieht.

Ein zweiter, oft übersehener Engpass sind Inodes statt Blöcken: df -ih zeigt die Auslastung der Inode-Tabelle. Wenn ein Verzeichnis Millionen kleiner Dateien enthält, zum Beispiel PHP-Session-Dateien oder Cache-Fragmente, kann die Inode-Tabelle voll laufen, obwohl auf dem Datenträger selbst noch Platz frei ist. In diesem Fall meldet das System ebenfalls „No space left on device“, aber df -h zeigt fälschlich freien Speicherplatz, nur df -ih deckt das eigentliche Problem auf. df -hT ergänzt zusätzlich den Dateisystemtyp, was bei gemischten Setups mit ext4, xfs und tmpfs-Mounts für Overlay-Container hilfreich ist.


# Human-readable overview of all mounted filesystems
df -h

# Example output
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda1        40G   38G  1.2G  97% /
# /dev/sdb1        20G  4.1G   15G  22% /var/log
# tmpfs           2.0G     0  2.0G   0% /dev/shm

# Check inode usage when "No space left" occurs despite free disk space
df -ih

# Example output
# Filesystem      Inodes  IUsed  IFree IUse% Mounted on
# /dev/sda1         2.6M   2.6M    412 100% /

# Also show filesystem type (ext4, xfs, tmpfs, overlay)
df -hT /var/www

# Check a specific partition only, ideal for monitoring scripts
df -h --output=pcent,target /var | tail -n1

3. du: den Verursacher im Verzeichnisbaum finden

Sobald df die betroffene Partition identifiziert hat, übernimmt du die Detailarbeit. Der klassische Einstieg ist du -sh * | sort -rh | head -20 im vermuteten Wurzelverzeichnis, zum Beispiel /var/www oder /var. Das Flag -s summiert jeden Eintrag zu einer einzigen Zeile statt jede Unterdatei einzeln aufzulisten, -h formatiert die Größen menschenlesbar, und sort -rh sortiert absteigend nach Größe unter Berücksichtigung der Einheiten. So erscheint der größte Verzeichnis-Eintrag sofort ganz oben, ohne dass man die Ausgabe manuell durchsuchen muss.

Für eine schrittweise Eingrenzung eignet sich du -h --max-depth=1 /var | sort -rh, das nur eine Ebene tief geht und die Verzeichnisse einer Ebene direkt vergleichbar macht. Sobald der auffällige Unterordner gefunden ist, wiederholt man denselben Befehl eine Ebene tiefer, bis die konkrete Datei oder Dateigruppe sichtbar wird. Wichtig: du zählt standardmäßig die tatsächlich auf der Platte belegten Blöcke, nicht die logische Dateigröße, bei stark fragmentierten oder sparse Dateien kann das leicht abweichen. Das moderne Tool ncdu bietet dieselbe Information interaktiv mit Tastatursteuerung und ist auf produktiven Servern eine deutliche Zeitersparnis gegenüber wiederholten du-Aufrufen.


# Largest directories in the current path, sorted descending
du -sh * | sort -rh | head -20

# Example output
# 4.2G  vendor
# 2.8G  var
# 1.1G  pub
# 340M  app

# Step-by-step narrowing: only one level deep
du -h --max-depth=1 /var | sort -rh

# Example output
# 2.6G  /var/log
# 1.8G  /var/cache
# 210M  /var/lib

# Check the size of individual log files, including the total
du -csh /var/log/*.log

# Interactive alternative for repeated analysis
ncdu /var/www

4. Wenn df voll zeigt, du aber nicht aufgeht

Ein klassisches und immer wieder verwirrendes Szenario: df -h meldet eine Partition zu 98 % voll, aber du -sh /* summiert am Ende deutlich weniger als die von df gemeldete Belegung. Die Ursache liegt fast immer an gelöschten, aber noch geöffneten Dateien. Löscht man eine Datei mit rm, während ein Prozess sie noch geöffnet hat, entfernt der Kernel lediglich den Verzeichniseintrag, der Speicherplatz auf der Platte wird erst freigegeben, wenn der letzte Prozess den Dateideskriptor schließt. du sieht die Datei nicht mehr, weil sie keinen Namen mehr im Dateisystem hat, df zählt sie aber weiterhin mit, weil die Blöcke physisch belegt bleiben.

Typischer Auslöser auf PHP-Servern: Ein PHP-FPM- oder Nginx-Prozess schreibt in eine Logdatei, ein Administrator löscht diese Logdatei direkt mit rm statt sie über logrotate zu rotieren, der laufende Prozess hält seinen Dateideskriptor aber weiter offen und schreibt munter weiter, ohne dass der Platz je wieder frei wird. Mit lsof +L1 lassen sich genau solche offenen Dateien mit einem Link-Count kleiner eins aufspüren, die Ausgabe zeigt Prozess-ID, Dateigröße und den ursprünglichen Pfad mit dem Zusatz (deleted). Die einzig saubere Lösung ist ein Neustart oder ein gezieltes Signal an den betroffenen Prozess, damit er die Datei neu öffnet, ein einfaches erneutes Löschen bewirkt nichts mehr.


# Confirm the discrepancy: df reports full, du counts less
df -h /
du -csh /* 2>/dev/null | tail -n1

# Find deleted files that are still held open
lsof +L1

# Example output
# COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NLINK    NODE NAME
# php-fpm  4821 www-data   12w  REG    8,1  3.4G       0  918273 /var/log/php-fpm/error.log (deleted)

# Alternative: filter specifically for "deleted"
lsof / 2>/dev/null | grep deleted

# Clean fix: release the file descriptor by reloading the service
systemctl reload php8.3-fpm

# Emergency only: truncate the file without restarting the process
# (careful, this discards any buffered log lines)
: > /proc/4821/fd/12

5. Log-Dateien: der häufigste Speicherfresser

Auf produktiven PHP-Servern sind Logdateien die mit Abstand häufigste Ursache für plötzlich volle Partitionen. Eine ungewöhnlich hohe Fehlerrate in der Anwendung, ein Bug, der bei jedem Request eine Exception wirft, oder ein Debug-Modus, der versehentlich in der Produktion aktiv bleibt, lässt error.log oder Magentos var/log/exception.log innerhalb weniger Stunden auf mehrere Gigabyte anwachsen. Ohne logrotate oder eine vergleichbare Rotation wächst diese Datei unbegrenzt weiter, bis die Partition voll ist und der komplette Server, inklusive Datenbank auf derselben Platte, blockiert.

Die Systemjournale sind ein zweiter, oft vergessener Verursacher. journalctl persistiert standardmäßig unter /var/log/journal und kann ohne Größenlimit ebenfalls beträchtlichen Platz belegen, insbesondere bei Diensten mit hoher Log-Frequenz wie Docker-Containern. journalctl --disk-usage zeigt die aktuelle Belegung, journalctl --vacuum-size=500M begrenzt sie sofort auf einen definierten Wert. Für Anwendungslogs gilt dieselbe Regel wie für Systemlogs: Rotation und Kompression gehören von Anfang an ins Deployment, nicht erst, wenn die Platte bereits voll ist.


# /etc/logrotate.d/magento
# Rotation for Magento and PHP-FPM logs on a production server

/var/www/html/var/log/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0644 www-data www-data
    sharedscripts
    postrotate
        systemctl reload php8.3-fpm > /dev/null 2>&1 || true
    endscript
}

/var/log/nginx/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        systemctl reload nginx > /dev/null 2>&1 || true
    endscript
}

6. Cache- und Session-Verzeichnisse aufräumen

Cache-Verzeichnisse gehören zu den Speicherfressern, die schleichend wachsen und daher selten sofort auffallen. In Magento sammeln sich unter var/cache, var/page_cache und var/view_preprocessed über Wochen hinweg zehntausende kleiner Dateien an, insbesondere wenn der Full Page Cache nicht über Redis oder Varnish, sondern auf dem lokalen Dateisystem läuft. du -sh var/cache var/page_cache var/view_preprocessed liefert schnell einen Überblick, wie viel jeder dieser Ordner tatsächlich belegt, häufig sind es mehrere Gigabyte reiner Cache-Ballast, der jederzeit gefahrlos gelöscht werden kann, weil er beim nächsten Request automatisch neu erzeugt wird.

PHP-Sessions sind der zweite klassische Fall: Der Standardpfad /var/lib/php/sessions sammelt bei fehlendem Session-Garbage-Collector über Monate hinweg abgelaufene Session-Dateien an, oft mit einer Inode-Anzahl im sechsstelligen Bereich, was eher die Inode-Tabelle als den Speicherplatz selbst belastet. find /var/lib/php/sessions -name "sess_*" -mmin +1440 -delete entfernt Sessions, die seit 24 Stunden nicht mehr angefasst wurden, deutlich zuverlässiger als sich auf die eingebaute PHP-Garbage-Collection zu verlassen, die bei hoher Session-Anzahl gerne stehen bleibt. Wer den eingesparten Platz nach dem Aufräumen prüfen will, vergleicht einfach du -sh var/cache var/page_cache var/view_preprocessed und find /var/lib/php/sessions -name "sess_*" | wc -l vor und nach dem Lauf.

7. Alte Releases, vendor-Verzeichnisse und Deployment-Artefakte

Wer mit einem symlink-basierten Deployment arbeitet, bei dem jedes Deployment ein neues Verzeichnis unter releases/ anlegt und der aktive Symlink lediglich umgebogen wird, häuft mit jedem Deploy einen kompletten neuen vendor-Ordner samt Composer-Abhängigkeiten und kompiliertem Frontend-Code an. Ohne eine Begrenzung der aufbewahrten Releases wächst dieses Verzeichnis linear mit der Anzahl der Deployments, ein einzelnes Magento-Release mit vollständigem vendor-Verzeichnis und generierten Static-Files kann leicht mehrere Gigabyte umfassen. Nach hundert Deployments sind das schnell mehrere hundert Gigabyte, die ausschließlich aus nicht mehr benötigten alten Ständen bestehen.

Die gängige Lösung ist eine feste Aufbewahrungsgrenze, üblicherweise die letzten drei bis fünf Releases, alles Ältere wird automatisch nach jedem erfolgreichen Deploy gelöscht. Deployment-Tools wie Deployer oder Capistrano bringen diese Logik bereits eingebaut mit, bei eigenen Skripten reicht ein einfacher find-Befehl, der Releases nach Änderungsdatum sortiert und alles außerhalb der gewünschten Anzahl entfernt. Der Befehl du -sh releases/* | sort -h zeigt vorab, wie groß jedes einzelne Release ist, und ls -1dt releases/*/ | tail -n +6 | xargs -r rm -rf entfernt alles außer den fünf neuesten. Wichtig ist, vor dem Löschen zu prüfen, dass keine der aufzuräumenden Verzeichnisse gerade das Ziel des aktiven Symlinks ist, sonst reißt man sich die laufende Produktion weg.

8. Automatisierte Aufräumroutinen und Monitoring

Manuelle Aufräumaktionen lösen ein akutes Problem, verhindern aber nicht, dass sich dasselbe Muster in vier Wochen wiederholt. Nachhaltig wird die Lösung erst durch Automatisierung: ein wöchentlicher Cron-Job oder systemd-Timer, der Logs rotiert, alte Releases entfernt und abgelaufene Sessions löscht, kombiniert mit einem Monitoring-Check, der frühzeitig warnt, bevor eine Partition kritisch wird. Ein einfacher Schwellenwert-Check über df --output=pcent in einem Monitoring-System wie Prometheus mit node_exporter oder einem simplen Nagios-Check reicht bereits, um bei 85 % Belegung eine Benachrichtigung auszulösen, lange bevor die Platte bei 100 % tatsächlich blockiert.

Für Infrastruktur, die über Ansible verwaltet wird, lässt sich dieselbe Aufräumlogik als wiederverwendbares Playbook definieren, das auf mehreren Servern konsistent läuft und über einen Cron-Trigger oder eine CI-Pipeline regelmäßig ausgeführt wird. Der entscheidende Vorteil gegenüber Ad-hoc-Skripten auf einzelnen Servern: Änderungen an der Aufräumlogik werden zentral versioniert und einheitlich auf die gesamte Flotte ausgerollt, statt dass jeder Server seine eigene, im Laufe der Zeit auseinanderdriftende Variante des Cleanup-Skripts pflegt.


# ansible/playbooks/disk-cleanup.yml
# Reusable playbook for regular disk space maintenance
---
- name: Disk space cleanup on PHP application servers
  hosts: app_servers
  become: true
  vars:
    releases_to_keep: 5
    session_max_age_minutes: 1440

  tasks:
    - name: Check current disk usage before cleanup
      command: df --output=pcent,target /var
      register: disk_before
      changed_when: false

    - name: Remove old Magento releases beyond retention limit
      shell: |
        cd /var/www/releases
        ls -1dt */ | tail -n +{{ releases_to_keep + 1 }} | xargs -r rm -rf
      args:
        executable: /bin/bash

    - name: Clean up expired PHP sessions
      find:
        paths: /var/lib/php/sessions
        patterns: "sess_*"
        age: "{{ session_max_age_minutes }}m"
        recurse: false
      register: old_sessions

    - name: Delete matched session files
      file:
        path: "{{ item.path }}"
        state: absent
      loop: "{{ old_sessions.files }}"

    - name: Alert if disk usage still above threshold
      debug:
        msg: "WARNING: disk usage still critical after cleanup"
      when: disk_before.stdout | regex_search('([0-9]+)%') | int > 85

9. du und df im direkten Vergleich

Beide Werkzeuge messen Speicherplatz, aber auf grundlegend unterschiedlichen Ebenen und mit unterschiedlichen Datenquellen. Wer beide Ebenen kennt, spart bei jeder Speicherplatz-Analyse mehrere Umwege und findet den tatsächlichen Verursacher deutlich schneller.

Frage Falscher Ansatz Richtiges Werkzeug Vorteil
Ist die Partition voll? du -sh / (langsam, rekursiv) df -h Liest Superblock direkt, sofortige Antwort
Welches Verzeichnis belegt den Platz? df -h (nur pro Dateisystem) du -sh * | sort -rh Detailtiefe pro Verzeichnis
df voll, du zählt weniger Erneut rm auf bereits gelöschte Datei lsof +L1 Findet offene, gelöschte Dateideskriptoren
Inode-Tabelle voll? df -h allein (zeigt nur Blöcke) df -ih Zeigt Inode-Auslastung getrennt von Blockauslastung
Wiederholte Analyse auf Produktivserver Mehrfach manuelles du pro Ebene ncdu Interaktiv, ein Durchlauf, sofortige Navigation

In der Praxis ergänzen sich df und du in fast jeder Speicherplatz-Analyse: df liefert die Alarmmeldung, du liefert die Diagnose, und Werkzeuge wie lsof und ncdu schließen die Lücken, die keines der beiden Basiswerkzeuge allein abdeckt. Wer diese Kombination beherrscht, braucht für die allermeisten Speicherplatzprobleme auf einem PHP-Server keine zusätzliche Software.

Mironsoft

Server-Monitoring, Deployment-Automatisierung und Linux-Infrastruktur für Magento-Shops

Server, der zuverlässig nicht vollläuft?

Wir richten Log-Rotation, automatisiertes Release-Cleanup und Disk-Space-Monitoring für eure Magento- und PHP-Server ein, damit eine volle Partition nie wieder zum nächtlichen Notfall wird.

Disk-Space-Audit

Systematische df/du-Analyse und Priorisierung der größten Speicherfresser

Cleanup-Automatisierung

logrotate, Release-Retention und Session-Cleanup als versioniertes Playbook

Monitoring-Setup

Schwellenwert-Alerts für Speicherplatz und Inodes, bevor die Platte vollläuft

10. Zusammenfassung

Die Disk-Space-Analyse mit du und df folgt einem klaren Muster: df -h zeigt zuerst, welches Dateisystem kritisch voll ist, df -ih deckt zusätzlich volle Inode-Tabellen auf, die df -h allein übersieht. du -sh * | sort -rh grenzt anschließend Ebene für Ebene ein, bis der tatsächliche Verursacher sichtbar wird. Wenn df voll meldet, aber du nicht aufgeht, steckt fast immer eine gelöschte, aber noch offene Datei dahinter, aufgespürt mit lsof +L1 und behoben durch einen Neustart des betroffenen Prozesses.

Auf PHP-Servern sind die immer wiederkehrenden Verursacher fast identisch: unrotierte Logs, wachsende Cache- und Session-Verzeichnisse sowie Deployment-Systeme, die alte Releases nie löschen. Wer diese drei Bereiche mit logrotate, regelmäßigem Cache-Cleanup und einer festen Release-Retention automatisiert und zusätzlich einen Schwellenwert-Alert auf df legt, verhindert die meisten akuten Speicherplatzprobleme, bevor sie überhaupt zum nächtlichen Notfall werden.

Disk-Space-Analyse mit du und df, das Wichtigste auf einen Blick

df zuerst

df -h und df -ih zeigen, welches Dateisystem oder welche Inode-Tabelle kritisch belegt ist. Immer der erste Schritt.

du für die Details

du -sh * | sort -rh findet den Verursacher Ebene für Ebene, ncdu beschleunigt wiederholte Analysen.

Gelöschte, offene Dateien

df voll, du zählt weniger: lsof +L1 findet den offenen Dateideskriptor, ein Neustart gibt den Platz frei.

Automatisiertes Cleanup

logrotate, Release-Retention und Session-Cleanup als Cron-Job oder Ansible-Playbook, ergänzt um Schwellenwert-Monitoring.

11. FAQ: Disk-Space-Analyse mit du und df

1Was ist der Unterschied zwischen df und du?
df misst die Belegung eines gesamten Dateisystems aus dem Superblock, du summiert rekursiv die Größe einzelner Dateien in einem Verzeichnisbaum. df zeigt wie voll, du zeigt was.
2Warum zeigt df voll, obwohl du weniger summiert?
Meist gelöschte, aber noch geöffnete Dateien. Der Platz wird erst frei, wenn kein Prozess mehr einen Dateideskriptor hält. lsof +L1 findet diese Dateien zuverlässig.
3Wie finde ich den größten Speicherfresser?
du -sh * | sort -rh | head -20 im vermuteten Wurzelverzeichnis. Für schrittweise Eingrenzung du -h --max-depth=1 kombiniert mit sort -rh.
4df zeigt freien Platz, aber No space left on device?
Wahrscheinlich ist die Inode-Tabelle voll. df -ih zeigt die Inode-Auslastung getrennt von der Blockauslastung, entscheidend bei vielen kleinen Dateien.
5Wie löse ich das Problem gelöschter, offener Dateien?
Mit lsof +L1 den Prozess identifizieren, danach den Dienst neu starten oder reloaden. Ein erneutes rm bewirkt nichts, der Verzeichniseintrag ist bereits weg.
6Welche Verzeichnisse auf einem PHP-Server prüfen?
var/log, PHP-Session-Verzeichnisse, Magento-Cache-Ordner und alte Releases in symlink-basierten Deployments verursachen die meisten akuten Probleme.
7Ist es sicher, Magento-Cache-Verzeichnisse zu löschen?
Ja, sie werden automatisch neu erzeugt. bin/magento cache:flush ist einem manuellen rm -rf vorzuziehen, weil auch Redis-Backends konsistent geleert werden.
8Wie verhindere ich, dass Logdateien die Platte füllen?
logrotate mit täglicher Rotation, Kompression und fester Aufbewahrungsanzahl konfigurieren. journalctl --vacuum-size begrenzt zusätzlich die Systemjournale.
9Wie halte ich Deployment-Releases unter Kontrolle?
Feste Retention von drei bis fünf Releases, automatisches Löschen älterer Releases nach jedem Deploy, vorher prüfen, dass das aktive Release nicht betroffen ist.
10Gibt es eine Alternative zu wiederholten du-Aufrufen?
ncdu liefert dieselbe Information interaktiv mit Tastatursteuerung, ein Durchlauf genügt für die Navigation durch den gesamten Verzeichnisbaum.