
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.
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:
/var/log/journal/. These files cannot be read directly with commands like cat or grep; you must inspect them using the journalctl utility./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.
Here is where to start when diagnosing a log storage issue on your server:
journalctl --disk-usageThe 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/logIf binary storage under /var/log/journal/ accounts for the majority of used disk space, your journald retention configuration needs immediate adjustment.
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 Command | Target Retention Rule | Best Use Case |
|---|---|---|
| journalctl –vacuum-size=500M | Caps total journal storage at 500MB | Immediate emergency cleanup on small VPS instances |
| journalctl –vacuum-time=7d | Deletes binary logs older than 7 days | Routine log pruning for active application servers |
| journalctl –vacuum-files=10 | Retains only the 10 most recent log files | Strict file count management on constrained storage |
| journalctl –verify | Scans and validates binary log file integrity | Checking 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=500MThe 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.
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.confLocate 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=noEach parameter controls a different part of journal behavior in production:
journalctl./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:
sudo systemctl restart systemd-journaldVerify that systemd accepted the configuration without syntax errors by checking service status:
sudo systemctl status systemd-journaldWhile 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.
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/myappAdd 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:
weekly or monthly.daily, this retains two weeks of history.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.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/myappTo force an immediate log rotation test for debugging purposes, run logrotate with the force flag:
sudo logrotate --force /etc/logrotate.d/myappIf 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 dockerNote 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"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
fiMake 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 -Preventing system log disk exhaustion is straightforward when you apply systemd best practices across your infrastructure:
journalctl --disk-usage when diagnosing low disk space alerts on Linux servers.journalctl --vacuum-size or journalctl --vacuum-time rather than raw rm operations.SystemMaxUse=500M and SystemKeepFree=1G in /etc/systemd/journald.conf to enforce permanent storage boundaries./etc/logrotate.d/ with compression enabled.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.