--- title: "How to Monitor Disk Space and Inode Usage on Linux" description: "Learn to check disk space and inode usage with df, du and ncdu, find what fills a filesystem, free space safely and get alerts from a systemd timer on Ubuntu." category: "Storage Management" language: en source: https://cubepath.com/docs/storage-management/disk-space-and-inode-usage-monitoring updated: 2026-09-25 --- # How to Monitor Disk Space and Inode Usage on Linux A Linux filesystem can fail with `No space left on device` for two different reasons: it ran out of data blocks, or it ran out of inodes (the metadata entries that every file and directory needs). In this guide you will check both on Ubuntu 24.04, track down the directories and files responsible, free space safely, and set up a small systemd timer that warns you before a filesystem fills up. ## Prerequisites - A server running Ubuntu 24.04 LTS, such as a CubePath VPS. The commands also work on Debian 12; on Rocky Linux 9 replace `apt` with `dnf`. - A non-root user with `sudo` privileges. ## Step 1 - Checking disk space with df `df` reports how much space each mounted filesystem has. The `-h` flag prints human-readable sizes and `-T` adds the filesystem type. The `-x` flags hide pseudo-filesystems that only live in memory and would clutter the output: ```bash df -hT -x tmpfs -x devtmpfs -x squashfs -x efivarfs ``` ```output Filesystem Type Size Used Avail Use% Mounted on /dev/vda1 ext4 78G 31G 44G 42% / /dev/vda15 vfat 105M 6.1M 99M 6% /boot/efi ``` The `Use%` column is the one to watch. Notice that `Used` plus `Avail` is smaller than `Size`: ext4 reserves 5% of the blocks for root by default, so regular users (and most services) hit "disk full" before `df` reaches 100%. You can see the reserve with `tune2fs`: ```bash sudo tune2fs -l /dev/vda1 | grep -i 'reserved block count' ``` ```output Reserved block count: 1036800 ``` To check a single path, pass it to `df`. It shows the filesystem that contains that path: ```bash df -h /var/lib ``` ## Step 2 - Checking inode usage with df -i Each file, directory and symlink uses one inode. On ext4 the number of inodes is fixed when the filesystem is created, so millions of tiny files (session files, cache entries, mail queues) can exhaust inodes while plenty of space is still free. Check inodes with `-i`: ```bash df -hi -x tmpfs -x devtmpfs -x squashfs -x efivarfs ``` ```output Filesystem Inodes IUsed IFree IUse% Mounted on /dev/vda1 5.0M 312K 4.7M 7% / /dev/vda15 0 0 0 - /boot/efi ``` A `-` in `IUse%` means the filesystem does not use a fixed inode table (vfat, Btrfs). XFS allocates inodes dynamically too, so inode exhaustion is mostly an ext4 problem. If `IUse%` is high while `Use%` is low, skip to Step 4. ## Step 3 - Finding large directories and files Once you know which filesystem is full, find where the space went. `du` summarizes directory sizes. The `-x` flag stays on one filesystem (so `/` does not include `/proc` or other mounts) and `-d 1` limits the output to one level: ```bash sudo du -xh -d 1 / 2>/dev/null | sort -rh | head -n 10 ``` ```output 31G / 18G /var 7.2G /usr 3.9G /home 1.1G /opt ``` Repeat the command on the biggest entry to drill down, for example `sudo du -xh -d 1 /var | sort -rh | head -n 10`. To list individual files larger than 500 MB on the root filesystem: ```bash sudo find / -xdev -type f -size +500M -exec du -h {} + 2>/dev/null | sort -rh | head -n 20 ``` ```output 9.8G /var/lib/mysql/ibdata1 2.1G /var/log/app/debug.log ``` ### Browsing interactively with ncdu For exploring a full disk, `ncdu` is faster than repeating `du` by hand. It scans once and lets you navigate with the arrow keys: ```bash sudo apt update sudo apt install ncdu ``` ```bash sudo ncdu -x / ``` Use the arrow keys and `Enter` to move through directories, `d` to delete the selected item (after confirmation) and `q` to quit. Be careful with `d`: deleting files that belong to a package or a running service can break it. ## Step 4 - Finding directories with too many files When inodes are the problem, you need the directories with the most entries rather than the biggest ones. GNU `du` can count inodes instead of bytes: ```bash sudo du -x --inodes -d 1 / 2>/dev/null | sort -rn | head -n 10 ``` ```output 311904 / 196551 /var 84230 /usr 21480 /home ``` Drill down the same way until you find the culprit: ```bash sudo du -x --inodes -d 1 /var 2>/dev/null | sort -rn | head -n 5 ``` ```output 196551 /var 171220 /var/lib 18702 /var/cache ``` Typical offenders are PHP session directories, application cache directories, and mail queues filled by a misbehaving cron job. Deleting a directory with millions of files is faster with `find` than with `rm -r` on a glob, which can fail with `Argument list too long`: ```bash sudo find /path/to/cache -type f -mtime +7 -delete ``` This removes files not modified in the last seven days. Replace the path with the directory you identified, and check that the application can rebuild those files before you run it. ## Step 5 - Freeing space safely Start with the places that grow on every server and that are safe to trim. Remove packages that are no longer needed and clear the APT package cache: ```bash sudo apt autoremove --purge sudo apt clean ``` Check how much space the systemd journal uses: ```bash journalctl --disk-usage ``` ```output Archived and active journals take up 1.8G in the file system. ``` Shrink it to 500 MB immediately: ```bash sudo journalctl --vacuum-size=500M ``` To keep it at that size permanently, create a drop-in configuration file: ```bash sudo mkdir -p /etc/systemd/journald.conf.d sudo nano /etc/systemd/journald.conf.d/size.conf ``` ```ini [Journal] SystemMaxUse=500M ``` Restart journald to apply it: ```bash sudo systemctl restart systemd-journald ``` If a single application log is huge, fix its log rotation rather than deleting the file. Files under `/var/log` are rotated by `logrotate`, configured in `/etc/logrotate.d/`. You can test a configuration without changing anything with `sudo logrotate -d /etc/logrotate.conf`. > Note: If you run Docker, check `docker system df`. Unused images and build cache often take several gigabytes and can be removed with `docker image prune -a` and `docker builder prune`. ## Step 6 - Getting alerts before a disk fills up Checking by hand only helps when you remember to do it. A short script run by a systemd timer can check every filesystem each hour and log a warning to the journal when block or inode usage crosses a threshold. Create the script: ```bash sudo nano /usr/local/bin/check-disk-usage ``` ```bash #!/usr/bin/env bash # Warn when block or inode usage on any real filesystem reaches the threshold. set -euo pipefail threshold="${1:-85}" status=0 while read -r pcent ipcent target; do used="${pcent%\%}" iused="${ipcent%\%}" [[ "$used" =~ ^[0-9]+$ ]] || used=0 [[ "$iused" =~ ^[0-9]+$ ]] || iused=0 if (( used >= threshold || iused >= threshold )); then logger -t check-disk-usage -p user.warning \ "${target}: space ${used}%, inodes ${iused}% (threshold ${threshold}%)" echo "${target}: space ${used}%, inodes ${iused}%" >&2 status=1 fi done < <(df --output=pcent,ipcent,target -x tmpfs -x devtmpfs -x squashfs -x efivarfs -x overlay | tail -n +2) exit "$status" ``` The script reads `df` output directly, handles filesystems without inodes, and exits with status `1` when any filesystem is over the limit, so the systemd unit is marked as failed and shows up in `systemctl --failed`. Make it executable and test it with a low threshold so that it triggers: ```bash sudo chmod 755 /usr/local/bin/check-disk-usage sudo /usr/local/bin/check-disk-usage 10 ``` ```output /: space 42%, inodes 7% ``` Create a service unit that runs the check: ```bash sudo nano /etc/systemd/system/check-disk-usage.service ``` ```ini [Unit] Description=Check disk space and inode usage [Service] Type=oneshot ExecStart=/usr/local/bin/check-disk-usage 85 ``` Create a timer that runs it every hour: ```bash sudo nano /etc/systemd/system/check-disk-usage.timer ``` ```ini [Unit] Description=Hourly disk space and inode check [Timer] OnCalendar=hourly Persistent=true [Install] WantedBy=timers.target ``` Enable the timer and run the check once to confirm it works: ```bash sudo systemctl daemon-reload sudo systemctl enable --now check-disk-usage.timer sudo systemctl start check-disk-usage.service systemctl list-timers check-disk-usage.timer ``` ```output NEXT LEFT LAST PASSED UNIT ACTIVATES Thu 2026-09-24 15:00:00 UTC 41min - - check-disk-usage.timer check-disk-usage.service ``` Warnings are written to the journal, where you can read them with: ```bash journalctl -t check-disk-usage --since today ``` To get notified by email or chat, add an `OnFailure=` unit to the service, or let your existing monitoring (Netdata, Prometheus node_exporter, Zabbix) alert on the same thresholds. ## Troubleshooting ### df shows the disk is full but du finds much less A process is probably still holding a deleted file open. The space is only released when the process closes it. List deleted-but-open files: ```bash sudo lsof -nP +L1 ``` ```output COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME java 1432 app 5w REG 252,1 8589934592 0 131091 /var/log/app/app.log (deleted) ``` Restart the service that owns the process (`sudo systemctl restart your_service`) to release the space. If `lsof` is not installed, install it with `sudo apt install lsof`. ### Space is hidden under a mount point Files written to a directory before a filesystem was mounted on it are hidden, but still use space. Bind-mount the root filesystem elsewhere to look underneath: ```bash sudo mkdir -p /mnt/rootfs sudo mount --bind / /mnt/rootfs sudo du -xh -d 1 /mnt/rootfs/mnt /mnt/rootfs/var/lib 2>/dev/null sudo umount /mnt/rootfs ``` ### No space left on device, but df -h shows free space The filesystem is out of inodes. Confirm with `df -i` and follow Step 4. ## Conclusion You can now check block and inode usage with `df`, locate the directories and files responsible with `du`, `find` and `ncdu`, free space from the usual sources, and receive a journal warning from a systemd timer before a filesystem fills up. As next steps, configure log rotation for your own applications in `/etc/logrotate.d/`, put fast-growing data such as databases or backups on a separate volume, and feed disk metrics into a monitoring system to see growth trends over time.