Configuring logrotate on Linux VPS to manage log files

A VPS running web servers, databases, and applications continuously generates log files. Without proper log management, these files accumulate and eventually fill your entire disk, causing your website to crash and preventing the database from writing data. Logrotate is the standard Linux utility that automatically rotates, compresses, and deletes old logs on a schedule, ensuring your VPS never runs out of disk space due to logs. This comprehensive guide walks you through setting up logrotate for all common services on your VPS.

Why Log Rotation Matters on a VPS

Log files are essential for monitoring application behavior, diagnosing errors, and tracking security events. However, high-traffic services like Nginx, Apache, and MySQL generate hundreds of megabytes or even gigabytes of log data per week. Without rotation, a single log file can grow to tens of gigabytes in size, consuming SSD space that should be reserved for your website and database files.

When disk space fills to 100%, several catastrophic things can happen:

Logrotate solves this by automatically moving old logs to archives, compressing them to save space, and deleting logs that exceed your retention policy. By implementing logrotate correctly, you ensure your VPS has consistent available disk space and your logs remain available for troubleshooting when needed.

Understanding Logrotate Architecture

Logrotate operates through several key components that work together seamlessly:

Main Configuration Files

/etc/logrotate.conf          # Global default settings for all logs
/etc/logrotate.d/            # Directory for service-specific config files
/var/lib/logrotate/status    # Database tracking which logs were rotated when

The global config file /etc/logrotate.conf sets sensible defaults that apply to all logs. Service-specific configs in /etc/logrotate.d/ override these defaults for particular services. For example, Nginx might rotate logs daily and keep 14 days, while MySQL might keep only 7 days and compress immediately.

The status file is logrotate's memory — it tracks which logs have been rotated and when the last rotation occurred. This prevents the same log from being rotated multiple times on the same day, even if logrotate runs multiple times via cron.

How Logrotate Works

When logrotate runs (typically once daily via cron), it:

  1. Reads all config files from /etc/logrotate.conf and /etc/logrotate.d/
  2. Compares each log file's size and age against rotation conditions (daily, weekly, size threshold)
  3. For logs that need rotation:
    • Renames the active log file (e.g., access.log → access.log.1)
    • Creates a new empty log file with the same name and permissions
    • Optionally compresses old logs to .gz format
    • Deletes old logs that exceed the retention count
    • Runs optional post-rotation scripts (e.g., sending a signal to Nginx to reopen its log)
  4. Updates /var/lib/logrotate/status with the rotation timestamp

This happens silently in the background without requiring manual intervention.

Essential Logrotate Options Explained

Understanding the key configuration options helps you tailor logrotate to each service's needs:

Rotation Frequency

Retention Policy

Compression

File Handling

Service Integration

Configuring Logrotate for Nginx

Nginx is the most common web server on AsiaGB VPS plans. Nginx typically rotates its logs daily and keeps 14 days of history:

sudo nano /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 640 www-data adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

Let's break down this configuration:

After editing, test the configuration with sudo logrotate -d /etc/logrotate.d/nginx to ensure logrotate interprets it correctly before relying on it.

Configuring Logrotate for MySQL and MariaDB

MySQL slow query logs and error logs grow at different rates depending on query complexity and traffic volume. A typical MySQL configuration:

sudo nano /etc/logrotate.d/mysql
/var/log/mysql/error.log
/var/log/mysql/mysql-slow.log {
    daily
    rotate 7
    missingok
    compress
    delaycompress
    notifempty
    create 640 mysql adm
    postrotate
        # Tell MySQL to flush logs and use new files
        mysqladmin -u root -p'YOUR_ROOT_PASSWORD' flush-logs 2>/dev/null || true
    endscript
}

Key differences from Nginx:

Replace YOUR_ROOT_PASSWORD with your actual MySQL root password, or use an option file like ~/.my.cnf if you have one configured for passwordless access.

Configuring Logrotate for Custom Application Logs

If you're running a custom application (Node.js, Python, Java, etc.), you'll need a custom logrotate config:

sudo nano /etc/logrotate.d/myapp
/var/www/myapp/logs/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    su www-data www-data
}

This configuration is appropriate for apps that don't handle log file descriptor changes gracefully:

The key here is copytruncate. If your app doesn't respond well to file descriptor switching (as with nginx's reload), copytruncate is safer because the app never stops writing to the file — it's just truncated.

Advanced: Size-Based Rotation

For high-traffic services, you may want to rotate logs when they exceed a certain size rather than waiting for a daily rotation:

sudo nano /etc/logrotate.d/hightraffic
/var/log/myapp/access.log {
    size 100M
    rotate 5
    compress
    missingok
    copytruncate
}

This configuration rotates access.log whenever it exceeds 100 megabytes, regardless of the time of day. Useful for apps that log heavily and you want to prevent any single log file from growing too large. Keep in mind that size-based rotation ignores the daily/weekly/monthly schedule.

Testing and Debugging Logrotate

Before trusting logrotate with your production logs, always test your configuration:

Dry Run (Debug Mode)

# Test without making changes
sudo logrotate -d /etc/logrotate.conf

# Or test a specific service config
sudo logrotate -d /etc/logrotate.d/nginx

The -d flag shows exactly what logrotate would do without touching any files. Study the output carefully for any errors or unexpected behavior.

Verbose Run

# Execute with detailed output
sudo logrotate -v /etc/logrotate.conf

Force Rotation

# Force rotation immediately (useful for testing)
sudo logrotate -f /etc/logrotate.d/nginx

View Rotation History

# Check which logs were rotated when
sudo cat /var/lib/logrotate/status

Output shows each log file and the date it was last rotated. This helps confirm that logrotate is running on schedule.

Managing systemd Journal Logs

Modern Ubuntu and Debian systems use systemd's journal service, which also accumulates log data over time. If your VPS is running systemd (most do), monitor and manage journal logs separately from traditional /var/log logs:

Check Journal Disk Usage

journalctl --disk-usage

This shows how much space the journal is consuming. Large systems might find 500MB–2GB of journal logs.

Clean Up Journal Logs

# Vacuum logs older than 30 days
sudo journalctl --vacuum-time=30d

# Vacuum to keep only 500MB
sudo journalctl --vacuum-size=500M

# Vacuum to keep logs from the last 7 days
sudo journalctl --vacuum-time=7d

Permanent Journal Limits

Set permanent limits in the systemd journald configuration so the journal never grows beyond a threshold:

sudo nano /etc/systemd/journald.conf

Add or uncomment these lines:

SystemMaxUse=500M
MaxRetentionSec=30day
ForwardToSyslog=yes

Then restart the journal service:

sudo systemctl restart systemd-journald

SystemMaxUse=500M caps the total journal size at 500 megabytes. MaxRetentionSec=30day deletes entries older than 30 days. Adjust these values based on your VPS disk size and retention requirements.

Finding What's Filling Your Disk

Sometimes log rotation isn't catching a particular runaway log file. Use these commands to find the largest files and directories:

See Overall Disk Usage

df -h

Shows used/available space on all mounted filesystems. If any partition is above 85% full, investigate immediately.

Find Large Directories

# Show top 20 directories consuming the most space
du -sh /var/log/* | sort -rh | head -20

This quickly identifies which service is logging the most data.

Find Large Individual Files

# Find all files larger than 100MB in /var/log
find /var/log -type f -size +100M -exec ls -lh {} \;

Use this to spot any log files that haven't been rotated yet.

Best Practices and Troubleshooting

Always Dry-Run Before Deploying

Before relying on a new logrotate config in production, test it:

sudo logrotate -d /etc/logrotate.d/yourservice

Review the output for any errors. Common issues include wrong file paths, permission problems, and incorrect script syntax.

Monitor Rotation Actually Happening

After your first deployment, manually check that logrotate is working:

ls -la /var/log/nginx/
# Should show access.log.1.gz, access.log.2.gz, etc.

Avoid Compressing Critical Logs You Access Frequently

If you frequently grep or tail recent logs, consider delaying compression:

compress
delaycompress  # Delay one rotation cycle

This keeps the most recent archive uncompressed and readable while still saving space on older archives.

Use postrotate Scripts Wisely

Postrotate scripts are powerful but can fail silently. Always include error handling:

postrotate
    # Send signal with error checking
    if [ -f /var/run/service.pid ]; then
        kill -USR1 `cat /var/run/service.pid` 2>/dev/null || true
    fi
endscript

Pro Tip: Store custom logrotate configs for all your services in /etc/logrotate.d/ rather than modifying the global /etc/logrotate.conf. This keeps your custom configuration isolated and makes it easier to back up and migrate your VPS.

Automated Disk Health Monitoring

Once logrotate is in place, consider adding a simple monitoring script to alert you if disk usage approaches full:

#!/bin/bash
THRESHOLD=85
USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $USAGE -gt $THRESHOLD ]; then
    echo "WARNING: Disk usage at $USAGE%" | mail -s "VPS Disk Alert" [email protected]
fi

Add this to your crontab to run daily. It sends an email alert if disk usage exceeds 85%, giving you time to investigate before the disk fills completely.

Need a Linux VPS with Full Disk Control?

AsiaGB offers SSD-based VPS hosting on Ubuntu/Debian with full root access — manage logs, cron jobs, and services exactly as you need. Uptime 99%, starting at 500 THB/month with 24-hour support.

View VPS Plans

View all affordable VPS Thailand plans →