Why Docker logs can eat a NAS
A home NAS is usually a single‑disk or a small RAID array.
When you run several containers—media servers, databases, CI runners—each one writes a JSON log file under
/var/lib/docker/containers/<id>/<id>-json.log.
If you leave the default json-file driver untouched, those files grow indefinitely.
On a 1 TB NAS, a handful of containers can fill the drive in weeks, forcing you to delete data or upgrade hardware.
The solution is two‑fold:
- Tell Docker to stop writing forever – use
max‑sizeandmax‑fileoptions. - Let the system clean up old logs – configure
logrotateto compress, delete, and rotate the files.
Below is a step‑by‑step guide that works on any recent distribution (Debian, Ubuntu, Arch, Fedora, etc.) and keeps your NAS from running out of space.
Docker’s built‑in size limits
Docker can limit the size of each log file and the number of rotated files it keeps.
Add the options when you create or run a container:
docker run -d \
--log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=5 \
--name=media-server \
myimage
max-size=10m– each log file is capped at 10 MiB.max-file=5– Docker keeps at most five rotated files per container.
These settings are the first line of defense. They prevent a single container from filling the disk, but they don’t delete old logs after the rotation limit is hit. That’s where logrotate comes in.
Logrotate configuration
Create a dedicated logrotate file for Docker logs:
sudo nano /etc/logrotate.d/docker-containers
Add the following:
/var/lib/docker/containers/*/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 root root
sharedscripts
postrotate
# Docker writes to a file descriptor; we need to signal it to reopen logs
if /usr/bin/docker info > /dev/null 2>&1; then
/usr/bin/docker logs --details > /dev/null 2>&1
fi
endscript
}
Explanation of key directives
| Directive | Meaning | Trade‑off |
|---|---|---|
daily |
Rotate every day | Keeps logs fresh; may produce many small files |
rotate 7 |
Keep 7 rotated copies | 7 days of logs; adjust for storage |
compress |
Gzip old logs | Saves space; CPU cost on rotation |
delaycompress |
Compress only after the next rotation | Avoids compressing the most recent file |
missingok |
Ignore missing files | Prevents errors when a container is removed |
notifempty |
Skip empty logs | Reduces noise |
create 0640 root root |
Set permissions on new log | Ensures only root can read/write |
sharedscripts |
Run postrotate only once per file set |
Avoids duplicate Docker restarts |
postrotate … endscript |
Signal Docker to reopen logs | Keeps Docker happy after rotation |
Why the postrotate block matters
Docker keeps a file descriptor open to the current log. When logrotate renames the file, Docker keeps writing to the old, renamed file. The postrotate script tells Docker to reopen its log file, so the container starts writing to the new file immediately. Without it, you’d end up with orphaned log files that keep growing.
Applying the limits to existing containers
If you’ve already launched containers without max-size/max-file, you can retro‑apply the settings by updating the daemon configuration:
sudo nano /etc/docker/daemon.json
Add or edit the log-opts section:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Then restart Docker:
sudo systemctl restart docker
Existing containers will now honor the limits. New containers will inherit the defaults automatically.
Testing the rotation
A quick sanity check:
- Generate a lot of logs
docker exec -d media-server sh -c "while true; do echo $(date) >> /var/log/media.log; sleep 1; done" - Wait a few minutes – the log file should grow until it hits 10 MiB, then a new file appears.
- Check logrotate – run
sudo logrotate -f /etc/logrotate.d/docker-containersand look at/var/lib/docker/containers/.../*.log. You should see the old files compressed and only a handful remaining.
If everything looks good, you’re set. Your NAS will no longer be threatened by runaway Docker logs.
This setup is a staple in my own home lab. I’ve seen this go wrong when people forget the postrotate step and end up with a mountain of orphaned logs. In practice, the combination of Docker’s built‑in limits and a tidy logrotate rule keeps the disk usage predictable and the system stable.
See also
- Keep a 1 GB VPS from dying: a single cron job that purges /var/log/syslog after 30 days
- When firewalld blocks HTTP traffic even though port 80 is open: the services vs ports trap
- Stuck in emergency mode after adding an NTFS mount to /etc/fstab: how to fix it
- How to Stop Podman From Creating 0777 Permissions on Bind‑Mounted Directories When Running as a Non‑Root User
- Using ACLs to give a group write access to /var/www/html without changing ownership