Configure Linux disk usage monitoring and automated cleanup with systemd timers

Intermediate 25 min Apr 03, 2026 41 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up automated disk monitoring, log cleanup, and email alerts using systemd timers to prevent disk space issues. Configure log rotation, temporary file cleanup, and threshold-based alerting for production systems.

Prerequisites

  • Root or sudo access
  • Basic familiarity with systemd
  • Email server configuration knowledge

What this solves

Running out of disk space can cause system failures, service outages, and data loss in production environments. This tutorial sets up automated disk monitoring with email alerts when thresholds are reached, configures systemd timers for regular cleanup tasks, and implements log rotation to prevent uncontrolled disk usage growth.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure you have the latest system tools and utilities.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install monitoring and mail utilities

Install the necessary packages for disk monitoring, email notifications, and system utilities.

sudo apt install -y mailutils postfix logrotate ncdu tree
sudo dnf install -y mailx postfix logrotate ncdu tree

Create disk monitoring script

Create a script that checks disk usage and sends email alerts when thresholds are exceeded.

sudo mkdir -p /opt/disk-monitor
sudo tee /opt/disk-monitor/disk-check.sh > /dev/null << 'EOF'
#!/bin/bash

Configuration

THRESHOLD_WARNING=80 THRESHOLD_CRITICAL=90 EMAIL_RECIPIENT="admin@example.com" HOSTNAME=$(hostname -f) LOG_FILE="/var/log/disk-monitor.log"

Function to log messages

log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" }

Function to send email alert

send_alert() { local severity=$1 local filesystem=$2 local usage=$3 local available=$4 local subject="[$severity] Disk Space Alert - $HOSTNAME" local body="Disk space alert for $HOSTNAME: Filesystem: $filesystem Usage: $usage% Available: $available Threshold: ${severity,,} at ${THRESHOLD_WARNING}%/${THRESHOLD_CRITICAL}% Please investigate and free up disk space immediately." echo -e "$body" | mail -s "$subject" "$EMAIL_RECIPIENT" log_message "$severity alert sent for $filesystem ($usage% used)" }

Check disk usage for all mounted filesystems

df -h | awk 'NR>1 && !/tmpfs|devtmpfs|udev/ {print $5 " " $6 " " $4}' | while read output; do usage=$(echo $output | awk '{print $1}' | sed 's/%//') filesystem=$(echo $output | awk '{print $2}') available=$(echo $output | awk '{print $3}') if [ $usage -ge $THRESHOLD_CRITICAL ]; then send_alert "CRITICAL" "$filesystem" "$usage" "$available" elif [ $usage -ge $THRESHOLD_WARNING ]; then send_alert "WARNING" "$filesystem" "$usage" "$available" fi done

Log successful completion

log_message "Disk check completed successfully" EOF

Make the monitoring script executable

Set proper permissions on the disk monitoring script to allow execution by the system.

sudo chmod 755 /opt/disk-monitor/disk-check.sh
sudo chown root:root /opt/disk-monitor/disk-check.sh

Create cleanup script for temporary files

Create a script to automatically clean up temporary files, old logs, and cache directories.

sudo tee /opt/disk-monitor/cleanup.sh > /dev/null << 'EOF'
#!/bin/bash

LOG_FILE="/var/log/disk-cleanup.log"
CLEANED_SPACE=0

Function to log messages with space saved

log_cleanup() { local action=$1 local space_before=$2 local space_after=$3 local saved=$((space_before - space_after)) CLEANED_SPACE=$((CLEANED_SPACE + saved)) echo "$(date '+%Y-%m-%d %H:%M:%S') - $action: ${saved}KB freed" >> "$LOG_FILE" }

Function to get directory size in KB

get_size() { du -sk "$1" 2>/dev/null | cut -f1 || echo 0 } echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting cleanup process" >> "$LOG_FILE"

Clean temporary directories

for temp_dir in "/tmp" "/var/tmp"; do if [ -d "$temp_dir" ]; then before=$(get_size "$temp_dir") find "$temp_dir" -type f -atime +7 -delete 2>/dev/null find "$temp_dir" -type d -empty -delete 2>/dev/null after=$(get_size "$temp_dir") log_cleanup "Cleaned $temp_dir" "$before" "$after" fi done

Clean old log files (older than 30 days)

if [ -d "/var/log" ]; then before=$(get_size "/var/log") find /var/log -name ".log..gz" -mtime +30 -delete 2>/dev/null find /var/log -name ".log." -mtime +30 -delete 2>/dev/null after=$(get_size "/var/log") log_cleanup "Cleaned old logs" "$before" "$after" fi

Clean package cache

if command -v apt-get >/dev/null 2>&1; then before=$(get_size "/var/cache/apt") apt-get clean >/dev/null 2>&1 after=$(get_size "/var/cache/apt") log_cleanup "APT cache cleanup" "$before" "$after" elif command -v dnf >/dev/null 2>&1; then before=$(get_size "/var/cache/dnf") dnf clean all >/dev/null 2>&1 after=$(get_size "/var/cache/dnf") log_cleanup "DNF cache cleanup" "$before" "$after" fi

Clean journal logs older than 30 days

before=$(journalctl --disk-usage 2>/dev/null | grep -oE '[0-9.]+[KMGT]B' | head -1 | sed 's/[^0-9.]//g' || echo 0) journalctl --vacuum-time=30d >/dev/null 2>&1 after=$(journalctl --disk-usage 2>/dev/null | grep -oE '[0-9.]+[KMGT]B' | head -1 | sed 's/[^0-9.]//g' || echo 0) log_cleanup "Journal cleanup" "$before" "$after" echo "$(date '+%Y-%m-%d %H:%M:%S') - Cleanup completed. Total space freed: ${CLEANED_SPACE}KB" >> "$LOG_FILE" EOF

Make cleanup script executable

Set proper permissions on the cleanup script and ensure it's owned by root for security.

sudo chmod 755 /opt/disk-monitor/cleanup.sh
sudo chown root:root /opt/disk-monitor/cleanup.sh

Create systemd service for disk monitoring

Create a systemd service unit that will run the disk monitoring script.

[Unit]
Description=Disk Usage Monitor
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/opt/disk-monitor/disk-check.sh
StandardOutput=journal
StandardError=journal

Create systemd service for cleanup

Create a systemd service unit for the automated cleanup tasks.

[Unit]
Description=Disk Cleanup Service
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/opt/disk-monitor/cleanup.sh
StandardOutput=journal
StandardError=journal

Create systemd timers

Create timer units to schedule regular execution of the monitoring and cleanup services.

[Unit]
Description=Run disk monitor every 15 minutes
Requires=disk-monitor.service

[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
Persistent=true

[Install]
WantedBy=timers.target
[Unit]
Description=Run disk cleanup daily at 2 AM
Requires=disk-cleanup.service

[Timer]
OnCalendar=--* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Configure enhanced log rotation

Set up comprehensive log rotation to prevent log files from consuming excessive disk space.

# Disk monitor logs
/var/log/disk-monitor.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    notifempty
    create 644 root root
}

/var/log/disk-cleanup.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    notifempty
    create 644 root root
}

Enhanced system log rotation

/var/log/syslog { daily missingok rotate 14 compress delaycompress notifempty create 644 syslog adm postrotate systemctl reload rsyslog endscript } /var/log/auth.log { weekly missingok rotate 8 compress delaycompress notifempty create 644 syslog adm postrotate systemctl reload rsyslog endscript }

Configure Postfix for email notifications

Set up basic Postfix configuration for sending email alerts. This configuration works for most cloud providers.

sudo debconf-set-selections <<< "postfix postfix/mailname string $(hostname -f)"
sudo debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'"
# Add or modify these settings in /etc/postfix/main.cf
sudo postconf -e "myhostname = $(hostname -f)"
sudo postconf -e "mydestination = \$myhostname, localhost.\$mydomain, localhost"
sudo postconf -e "relayhost = "
sudo postconf -e "mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128"
sudo postconf -e "inet_protocols = ipv4"

Enable and start services

Reload systemd configuration and enable the timer services to start automatically.

sudo systemctl daemon-reload
sudo systemctl enable --now disk-monitor.timer
sudo systemctl enable --now disk-cleanup.timer
sudo systemctl enable --now postfix

Create log directories and initial files

Ensure proper log directories exist with correct permissions for monitoring and cleanup scripts.

sudo touch /var/log/disk-monitor.log /var/log/disk-cleanup.log
sudo chmod 644 /var/log/disk-monitor.log /var/log/disk-cleanup.log
sudo chown root:root /var/log/disk-monitor.log /var/log/disk-cleanup.log

Verify your setup

Check that all timers are active and services are properly configured.

# Check timer status
sudo systemctl status disk-monitor.timer disk-cleanup.timer

List all active timers

sudo systemctl list-timers

Test the monitoring script manually

sudo /opt/disk-monitor/disk-check.sh

Test the cleanup script manually

sudo /opt/disk-monitor/cleanup.sh

Check log files were created

ls -la /var/log/disk-*.log

Verify current disk usage

df -h

Check postfix is running

sudo systemctl status postfix
Note: The first run of monitoring may not send emails if disk usage is below thresholds. You can temporarily lower the threshold values in the script to test email functionality.

Advanced configuration

Add filesystem-specific monitoring

Create custom thresholds for specific filesystems that may need different monitoring levels.

# Custom thresholds per filesystem

Format: filesystem:warning_threshold:critical_threshold

/:85:95 /var:80:90 /home:75:85 /tmp:90:95

Configure logrotate for application logs

Add rotation rules for common application log directories to prevent them from filling the disk.

# Nginx logs
/var/log/nginx/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 www-data adm
    sharedscripts
    postrotate
        systemctl reload nginx
    endscript
}

Apache logs

/var/log/apache2/*.log { weekly missingok rotate 12 compress delaycompress notifempty create 644 www-data adm sharedscripts postrotate systemctl reload apache2 endscript }

Common issues

SymptomCauseFix
Timer not runningService not enabledsudo systemctl enable --now disk-monitor.timer
No email alertsPostfix not configuredCheck sudo systemctl status postfix and mail logs
Script permission deniedIncorrect file permissionssudo chmod 755 /opt/disk-monitor/*.sh
Cleanup not workingInsufficient permissionsEnsure scripts run as root user in service files
Log rotation failsService reload issuesCheck service status and logrotate configuration syntax
High disk usage persistsLarge files not cleanedUse ncdu / to identify large directories manually

Monitoring and maintenance

Regular maintenance tasks to keep your disk monitoring system healthy.

# View recent timer executions
sudo systemctl list-timers --all

Check monitoring logs

sudo tail -f /var/log/disk-monitor.log

Check cleanup logs

sudo tail -f /var/log/disk-cleanup.log

Test logrotate manually

sudo logrotate -d /etc/logrotate.conf

Force logrotate to run

sudo logrotate -f /etc/logrotate.conf

Analyze disk usage with ncdu

sudo ncdu /var/log

Check journal disk usage

journalctl --disk-usage

Next steps

Automated install script

Run this to automate the entire setup

#disk monitoring #systemd timers #automated cleanup #log rotation #email alerts

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer