Stop VPS Disk Exhaustion from Systemd Logs

Verdict: Stop VPS Disk Exhaustion Before It Crashes Production

If your Linux VPS keeps running out of disk space every few weeks despite deleting temporary files, systemd journal logs are likely the culprit. Systemd’s logging daemon (systemd-journald) collects stdout and stderr from system services, Docker containers, and cron jobs. By default, systemd allows log files to consume up to 10% of your root filesystem size. On a 40GB VPS, that means 4GB of disk space can disappear silently into binary log files before systemd hits its internal ceiling.

You can solve systemd log accumulation permanently with three core administrative actions: cap binary journal log retention limits in /etc/systemd/journald.conf, clean existing binary log files safely using journalctl, and configure automated log rotation for traditional plain-text application log files using logrotate.

I handle a Linux VPS every few weeks and run df -h before it reaches a critical disk state. Systemd journal logs are the culprit far more often than expected, and I have built this exact cleanup workflow after it silently exhausted a 40GB instance. Here is how to analyze your current log footprint, reclaim server disk space immediately, and establish automated log rotation policies that keep your Linux VPS stable indefinitely.

Understanding How Linux VPS Logging Works

Modern Linux distributions (such as Ubuntu 24.04, Debian 12, Rocky Linux, and AlmaLinux) manage system logs through two distinct logging mechanisms operating side by side, as documented in the official systemd journal reference. Before proceeding with log isolation, ensure you have basic web server configuration in place for standard port management:

  • systemd-journald (Binary Logging): Intercepts messages from kernel events, systemd services, early boot sequences, and standard output streams. It writes structured binary data into files located under /var/log/journal/. These files cannot be read directly with commands like cat or grep; you must inspect them using the journalctl utility.
  • rsyslog / logrotate (Text Logging): Traditional plain-text log handling. Many application daemons write log messages to plain-text files inside /var/log/ (such as /var/log/syslog, /var/log/auth.log, or /var/log/nginx/access.log). The logrotate service compresses, rotates, and deletes these text files on a daily or weekly schedule.

When a server experiences disk space issues, developers often check standard text files in /var/log/ while ignoring binary journal storage inside /var/log/journal/. If an application or background worker enters a crash loop, journald can record thousands of stack traces every minute, expanding system log directories until the server partition runs out of inodes or free space.

Diagnosing Systemd Journal Disk Consumption

Here is where to start when diagnosing a log storage issue on your server:

journalctl --disk-usage

The console output will display the exact storage footprint occupied by active and archived journal logs:

Archived and active journals take up 3.8G in the file system.

To inspect disk usage by individual log directories and confirm whether traditional text logs or systemd binary logs are consuming space, check directory storage totals using du:

sudo du -sh /var/log/journal /var/log

If binary storage under /var/log/journal/ accounts for the majority of used disk space, your journald retention configuration needs immediate adjustment.

Reclaiming Disk Space Safely with journalctl

Do not delete files directly from /var/log/journal/ using rm -rf while the systemd daemon is actively running. Deleting active binary journal files manually can corrupt log indexing and confuse the systemd-journald process. I made that mistake once and ended up restarting the daemon to rebuild the journal index. Instead, use built-in journalctl vacuum directives to delete old log files safely.

Cleanup CommandTarget Retention RuleBest Use Case
journalctl –vacuum-size=500MCaps total journal storage at 500MBImmediate emergency cleanup on small VPS instances
journalctl –vacuum-time=7dDeletes binary logs older than 7 daysRoutine log pruning for active application servers
journalctl –vacuum-files=10Retains only the 10 most recent log filesStrict file count management on constrained storage
journalctl –verifyScans and validates binary log file integrityChecking for corrupted log entries after server crash

To immediately reduce system log storage to 500MB on an active Linux VPS, run the vacuum size command with superuser privileges:

sudo journalctl --vacuum-size=500M

The systemd journal daemon will identify archived binary log segments, verify their status, and safely remove older journal files until total storage falls below your specified limit.

Configuring Permanent Systemd Journal Limits

Running manual cleanup commands provides temporary disk space relief, but binary logs will grow again as services generate new output. To establish permanent storage boundaries, modify the central journald configuration file located at /etc/systemd/journald.conf.

Open the file using your preferred terminal text editor:

sudo nano /etc/systemd/journald.conf

Locate the [Journal] section header. By default, most directive lines are commented out with a leading # character. Uncomment and update the following key configuration parameters to match your server environment:

[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=1G
SystemMaxFileSize=100M
MaxRetentionSec=14day
ForwardToSyslog=no

Each parameter controls a different part of journal behavior in production:

  • SystemMaxUse=500M: Sets the maximum disk space that systemd journal logs are permitted to occupy across all archived and active log files. Once total storage reaches 500MB, systemd automatically deletes the oldest binary log files. For custom background tasks, pair this with a service logging setup so structured output stays manageable.
  • SystemKeepFree=1G: Ensures systemd journal logs never consume storage if free disk space on the root filesystem drops below 1GB. This prevents log generation from causing server disk exhaustion.
  • SystemMaxFileSize=100M: Limits individual binary log files to 100MB before systemd rotates to a new file. Smaller log files improve search performance when querying entries with journalctl.
  • MaxRetentionSec=14day: Sets a maximum age ceiling for stored log messages. Log entries older than 14 days are purged automatically regardless of remaining storage space.
  • ForwardToSyslog=no: Disables forwarding journal messages to rsyslog if you do not rely on traditional /var/log/syslog text logging. This eliminates duplicate log writes across your server disk.

Save your changes and restart the systemd journal service to activate the new storage policy:

Server rack infrastructure for VPS logging and automated log rotation
Systemd log retention rules protect server disk space across cloud VPS instances. (Source: Unsplash)
sudo systemctl restart systemd-journald

Verify that systemd accepted the configuration without syntax errors by checking service status:

sudo systemctl status systemd-journald

Managing Plain-Text Application Logs with logrotate

While systemd journald handles container stdout and system services, third-party software like Nginx, Apache, MySQL, Redis, and custom Python or Node.js background processes often write standard text log files directly to disk. If left unmanaged, a busy web server log like /var/log/nginx/access.log can grow to tens of gigabytes.

Linux systems use the logrotate utility to automate text log compression and deletion, as described in the logrotate man page. The main logrotate configuration file sits at /etc/logrotate.conf, while application-specific rules reside inside /etc/logrotate.d/. If you run long-running agents that generate transcripts, the same rotation pattern applies to automated workflow logs on the same server.

Creating a Custom logrotate Rule for Custom Applications

If you run a custom application or background service that writes plain-text logs to /var/log/myapp/app.log, create a dedicated logrotate configuration file:

sudo nano /etc/logrotate.d/myapp

Add the following production log rotation directives:

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

Understanding logrotate parameters:

  • daily: Rotates target log files once every 24 hours. Alternative options include weekly or monthly.
  • missingok: Prevents logrotate from throwing error messages if a log file is missing or temporarily unreadable.
  • rotate 14: Keeps 14 rotated log archives before deleting the oldest file. Paired with daily, this retains two weeks of history.
  • compress & delaycompress: Compresses rotated log files using gzip to save disk space. delaycompress postpones compression of the most recent rotated file until the next rotation cycle, preventing file write conflicts with active processes.
  • notifempty: Skips rotation if the log file contains zero bytes, preventing empty archive creation.
  • create 0640 www-data www-data: Creates a new empty log file immediately after rotation with explicit Linux file permissions and user ownership.
  • postrotate / endscript: Executes a command or shell script after log rotation completes, such as reloading a web server to ensure it opens a fresh log file handle.

Testing logrotate Configurations

To verify that your custom logrotate rules contain correct syntax without modifying current log files, execute a dry run using the debug flag:

sudo logrotate --debug /etc/logrotate.d/myapp

To force an immediate log rotation test for debugging purposes, run logrotate with the force flag:

sudo logrotate --force /etc/logrotate.d/myapp

Configuring Docker Log Limits on Linux VPS Servers

If you deploy applications on your VPS using Docker containers, Docker default logging settings present a significant hidden disk risk. By default, the standard Docker json-file logging driver stores container stdout and stderr streams in JSON files on your host disk without any file size caps or file count limits, detailed in Docker logging documentation.

A noisy Docker container can easily fill your root partition within hours. You can set global Docker container log caps by creating or editing /etc/docker/daemon.json on your server:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}

This configuration enforces a strict limit across all new Docker containers: no individual container log file can exceed 50MB, and Docker retains a maximum of 3 rotated files (150MB maximum total log storage per container).

When I configure Docker container log limits on fresh VPS deployments, I always verify that existing containers pick up the updated daemon rules after a service restart.

sudo systemctl restart docker

Note that global daemon log limits apply to newly created containers. For existing running containers managed via Docker Compose, specify log limits directly within your docker-compose.yml service definitions:

services:
  web:
    image: nginx:alpine
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "3"

Automating System Disk Health Monitoring

Combining systemd journal retention limits, logrotate rules, and Docker container caps provides a comprehensive defensive logging architecture. For teams also tracking multi-server remote infrastructure, keep a consistent log management standard across all nodes.

Create a basic disk monitoring script at /usr/local/bin/check-disk.sh using a threshold approach supported by cron automation:

#!/bin/bash
THRESHOLD=85
CURRENT=$(df / | grep / | awk '{ print $5 }' | sed 's/%//')

if [ "$CURRENT" -gt "$THRESHOLD" ]; then
    echo "WARNING: Root partition disk usage on $(hostname) is at ${CURRENT}%" | mail -s "Disk Space Alert: $(hostname)" admin@example.com
fi

Make the script executable and schedule it to run daily via cron:

sudo chmod +x /usr/local/bin/check-disk.sh
(crontab -l 2>/dev/null; echo "0 8 * * * /usr/local/bin/check-disk.sh") | crontab -

Key Takeaways for Linux VPS Administrators

Preventing system log disk exhaustion is straightforward when you apply systemd best practices across your infrastructure:

  1. Check Journal Footprint First: Run journalctl --disk-usage when diagnosing low disk space alerts on Linux servers.
  2. Use journalctl Vacuum Directives: Clean binary logs safely using journalctl --vacuum-size or journalctl --vacuum-time rather than raw rm operations.
  3. Cap Journal Limits in journald.conf: Set SystemMaxUse=500M and SystemKeepFree=1G in /etc/systemd/journald.conf to enforce permanent storage boundaries.
  4. Configure logrotate for Text Logs: Maintain rotation policies for plain-text application logs in /etc/logrotate.d/ with compression enabled.
  5. Cap Docker Container Logs: Define max-size and max-file options in /etc/docker/daemon.json to prevent container stdout logs from filling host disks.

By establishing explicit storage boundaries for binary systemd logs, standard text log files, and container logs, your Linux VPS will run reliably without unexpected disk space crashes.

Irfan is a Creative Tech Strategist and the founder of Grafisify. He spends his days testing the latest AI design tools and breaking down complex tech into actionable guides for creators. When he’s not writing, he’s experimenting with generative art or optimizing digital workflows.

Leave a Reply

Your email address will not be published. Required fields are marked *

You might also like
Best AI Documentation Generators for Developers

Best AI Documentation Generators for Developers

Set Up Caddy Web Server with Automatic HTTPS: Server Guide

Set Up Caddy Web Server with Automatic HTTPS: Server Guide

How to Run Private AI on Your Laptop with Ollama

How to Run Private AI on Your Laptop with Ollama

Remove Windows 11 Bloatware and Lock Down Privacy

Remove Windows 11 Bloatware and Lock Down Privacy

Self-Host n8n with Docker Compose: A Real Production Setup

Self-Host n8n with Docker Compose: A Real Production Setup

Faster File Search in the Terminal with fzf and ripgrep

Faster File Search in the Terminal with fzf and ripgrep