Why Your VPS Logs Are Eating Disk Space
Server logs grow fast. Apache, Nginx, MySQL, and system logs can consume gigabytes monthly without proper management. When your VPS hosting runs out of space, sites crash and databases lock.
Logrotate solves this by automatically compressing old logs, deleting ancient ones, and keeping your system running smoothly. This tutorial shows you how to set up logrotate properly on Ubuntu VPS servers.
Understanding Logrotate Basics
Logrotate runs daily via cron and processes log files according to rules you define. It can rotate logs based on size, age, or both. When logs rotate, logrotate creates new files and handles old ones according to your retention policy.
Ubuntu ships with logrotate pre-installed and basic configurations for system logs. Web servers, databases, and applications often need custom rules though.
Check if logrotate is running:
sudo systemctl status cron
sudo cat /etc/cron.daily/logrotate
The daily cron job should show logrotate scheduled to run automatically.
Configure Logrotate for Apache Logs
Apache generates access and error logs for each virtual host. Without rotation, these files grow indefinitely.
Create a custom Apache logrotate configuration:
sudo nano /etc/logrotate.d/apache2-custom
Add this configuration:
/var/log/apache2/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 640 www-data adm
sharedscripts
postrotate
if /bin/systemctl status apache2 > /dev/null ; then \
/bin/systemctl reload apache2; \
fi;
endscript
}
This rotates Apache logs daily, keeps 52 weeks of history, compresses old logs, and reloads Apache after rotation. The delaycompress option keeps yesterday's log uncompressed for applications that might still write to it.
Test your Apache configuration:
sudo logrotate -d /etc/logrotate.d/apache2-custom
The -d flag runs in debug mode without actually rotating files, showing what would happen.
Set Up Nginx Log Rotation
Nginx logs need similar treatment but with different reload commands. Create an Nginx-specific configuration:
sudo nano /etc/logrotate.d/nginx-custom
Configure Nginx log rotation:
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi; \
endscript
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
Nginx requires a special signal to reopen log files. The invoke-rc.d nginx rotate command sends the proper USR1 signal to the Nginx master process.
For custom Nginx log locations, add them specifically:
/var/www/*/logs/*.log {
daily
rotate 30
compress
missingok
notifempty
sharedscripts
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}
Configure MySQL and MariaDB Log Rotation
Database logs require careful handling because MySQL and MariaDB need to know when logs rotate.
Create a database-specific configuration:
sudo nano /etc/logrotate.d/mysql-custom
Add MySQL log rotation rules:
/var/log/mysql/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf flush-logs
endscript
}
The flush-logs command tells MySQL to close current log files and open new ones. This ensures clean log rotation without data loss.
For MariaDB systems, the configuration is identical but verify the debian.cnf path:
ls -la /etc/mysql/debian.cnf
If you've configured custom database logs, our MySQL slow query log tutorial shows how to handle performance log rotation properly.
Handle Application-Specific Logs
Applications often create logs in custom locations. PHP applications, Node.js services, and custom scripts need their own rotation rules.
Create application log rotation:
sudo nano /etc/logrotate.d/applications
Configure rotation for common application logs:
# PHP application logs
/var/www/*/logs/*.log {
weekly
rotate 12
compress
missingok
notifempty
create 644 www-data www-data
}
# Custom application logs
/opt/*/logs/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
# System service logs
/var/log/custom/*.log {
daily
rotate 30
compress
missingok
notifempty
create 640 root root
}
The copytruncate option copies the log file and truncates the original instead of moving it. This works well for applications that keep log files open continuously.
Test and Debug Logrotate Configuration
Always test configurations before relying on them in production. Logrotate provides several debugging options to verify your setup.
Test specific configuration files:
sudo logrotate -d /etc/logrotate.d/apache2-custom
sudo logrotate -d /etc/logrotate.d/nginx-custom
sudo logrotate -d /etc/logrotate.conf
Force immediate rotation for testing:
sudo logrotate -f /etc/logrotate.d/apache2-custom
The -f flag forces rotation regardless of file size or age. Use this to verify your configuration works correctly.
Check logrotate status:
sudo cat /var/lib/logrotate/status
This file shows when each log was last rotated, helping you troubleshoot timing issues.
Monitor logrotate execution:
sudo tail -f /var/log/syslog | grep logrotate
Advanced Configuration Options
Beyond basic rotation, logrotate offers advanced features for complex hosting environments. Size-based rotation prevents logs from growing too large between scheduled rotations.
Configure size-based rotation:
/var/log/hightraffic/*.log {
size 100M
rotate 10
compress
missingok
notifempty
create 644 www-data adm
sharedscripts
postrotate
/bin/systemctl reload apache2
endscript
}
Use conditional rotation based on file age and size:
/var/log/mixed/*.log {
daily
size 50M
maxage 90
rotate 30
compress
missingok
notifempty
}
The maxage directive deletes files older than specified days regardless of rotation count.
For email logs that need special handling, our Postfix mail queue management guide covers rotation strategies for mail server logs.
Managing server logs properly requires reliable VPS infrastructure. Hostperl's managed VPS hosting includes pre-configured log rotation and monitoring to keep your servers running smoothly without manual intervention.
Monitor Disk Usage and Log Growth
Set up monitoring to catch log growth issues before they cause problems.
Create a simple script to check log directory sizes:
sudo nano /usr/local/bin/check-log-sizes.sh
Add this monitoring script:
#!/bin/bash
# Check log directory sizes
echo "Log Directory Usage Report - $(date)"
echo "=========================================="
for dir in /var/log/apache2 /var/log/nginx /var/log/mysql /var/www/*/logs; do
if [ -d "$dir" ]; then
size=$(du -sh "$dir" 2>/dev/null | cut -f1)
echo "$dir: $size"
fi
done
echo ""
echo "Largest log files:"
find /var/log /var/www/*/logs -name "*.log" -type f -exec ls -lh {} + 2>/dev/null | sort -k5 -hr | head -10
Make the script executable and run it:
sudo chmod +x /usr/local/bin/check-log-sizes.sh
sudo /usr/local/bin/check-log-sizes.sh
Add this to cron for weekly reports:
sudo crontab -e
Add the cron entry:
0 9 * * 1 /usr/local/bin/check-log-sizes.sh | mail -s "Weekly Log Size Report" admin@yourdomain.com
Troubleshooting Common Issues
When logrotate doesn't work as expected, several issues commonly occur.
Permission problems prevent logrotate from creating new files or accessing log directories. Fix them with:
sudo chown www-data:adm /var/log/apache2/*.log
sudo chmod 640 /var/log/apache2/*.log
Missing log directories cause rotation failures:
sudo mkdir -p /var/log/custom
sudo chown root:adm /var/log/custom
sudo chmod 755 /var/log/custom
Service reload failures happen when services aren't running or can't reload. Check service status before rotation:
sudo systemctl status apache2
sudo systemctl status nginx
sudo systemctl status mysql
Lock file issues prevent logrotate from running. Remove stale lock files:
sudo rm -f /var/lib/logrotate/lock
For hosting environments with custom security configurations, our UFW firewall guide shows how to secure log directories while maintaining proper access.
Frequently Asked Questions
How often should I rotate logs on a production VPS?
Most production servers should rotate logs daily for high-traffic applications and weekly for low-traffic sites. Keep 30-90 days of compressed logs for troubleshooting and compliance requirements.
What happens if logrotate fails during cron execution?
Logrotate logs errors to syslog and continues processing other configurations. Check /var/log/syslog for error messages and use the status file to see which logs were processed successfully.
Can I rotate logs based on file size instead of time?
Yes, use the "size" directive instead of "daily" or "weekly". For example, "size 100M" rotates when files exceed 100 megabytes. You can combine size and time limits for more control.
How do I handle logs for applications that keep files open?
Use the "copytruncate" option for applications that don't handle log rotation signals. This copies the log file and truncates the original, allowing the application to continue writing.
Should I compress rotated logs immediately?
Use "delaycompress" to keep yesterday's log uncompressed. Some applications or monitoring tools may still access recent log files. Older logs get compressed during the next rotation cycle.

