How to Manage Docker Log Size with logrotate and json-file Limits

Keep noisy containers from eating all your disk space by capping Docker’s default JSON logs, understanding where logrotate fits, and checking log growth before it becomes an outage.

DockerLogsDisk safety
What you learn

How Docker stores container logs by default, how to limit log growth globally or per service, when traditional logrotate helps, and how to confirm rotation is working.

Best for

Small VPS operators running Docker Compose who have seen disk usage creep up because one chatty container wrote forever.

Risk to watch

Deleting active log files by hand can hide evidence and confuse running services. Rotation is safer than random cleanup.

Before you begin

  • A Linux server running Docker Engine.
  • Permission to edit Docker daemon configuration and restart Docker if needed.
  • Awareness that restarting Docker briefly affects running containers.
  • A backup or snapshot if this is a critical production host.

Many Docker disk emergencies are really log emergencies. The app is “fine,” but one container keeps writing error messages, debug noise, or access logs into Docker’s default JSON log files until the disk fills up. When that happens, the app may fail in strange ways that look unrelated at first.

Expected outcome: By the end, your Docker host will have sane log size caps, a clearer log retention strategy, and a safer way to inspect or prune log buildup without guessing.

Step 1: Understand where Docker stores logs by default

Unless you choose a different logging driver, Docker commonly uses the json-file logging driver. That means each container gets a JSON log file under a path like:

/var/lib/docker/containers/<container-id>/<container-id>-json.log

These files grow as the container writes to stdout and stderr. The docker logs command reads from them. If you never set size limits, a noisy container can grow indefinitely.

That is why the best first fix is usually to set built-in Docker rotation options on the json-file driver, not to depend only on generic system log cleanup.

Step 2: Inspect which logs are growing

Start with general disk usage:

df -h

docker system df

Then inspect large container log files:

sudo find /var/lib/docker/containers -name '*-json.log' -type f -printf '%s %p\n' | sort -nr | head -20

If you want human-readable sizes:

sudo find /var/lib/docker/containers -name '*-json.log' -type f -exec du -h {} + | sort -hr | head -20

Check which container a large file belongs to:

docker ps --no-trunc --format 'table {{.ID}}\t{{.Names}}'

The long container ID in the file path should match the container ID list. Once you know which service is noisy, inspect recent log output:

docker logs --tail 100 my-container

Sometimes the best log fix is not only rotation. It is also fixing the underlying warning loop or reducing an overly verbose log level.

Step 3: Set Docker json-file log limits

For host-wide defaults, edit or create /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

This means each container keeps up to 5 log files of 10 MB each before older ones are rotated away.

Validate the JSON file if you changed it by hand:

python3 -m json.tool /etc/docker/daemon.json

Then restart Docker:

sudo systemctl restart docker

If you do not want a host-wide change yet, you can set log options per service in Compose:

services:
  app:
    image: ghcr.io/example/app:1.0.0
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

Recreate the affected services after changing Compose:

docker compose up -d

For many small VPS stacks, a sensible global default plus occasional per-service overrides is the cleanest balance.

Step 4: Use logrotate for host logs and special cases

logrotate is still useful, but usually for logs outside Docker’s default container JSON flow, such as:

  • Nginx logs written to files on the host
  • Application logs mounted into host directories
  • Custom scripts writing into /var/log

Example /etc/logrotate.d/myapp file for a file-based app log:

/srv/myapp/logs/*.log {
  daily
  rotate 7
  compress
  missingok
  notifempty
  copytruncate
}

Test the config without forcing changes:

sudo logrotate -d /etc/logrotate.conf

Force a test rotation if needed:

sudo logrotate -f /etc/logrotate.conf

Important: Do not rely on host logrotate alone to manage Docker’s active JSON container logs. Docker’s own json-file limits are the safer primary control there.

Step 5: Verify that rotation is actually happening

After restarting Docker or recreating services, inspect one container:

docker inspect my-container --format '{{json .HostConfig.LogConfig}}'

You should see the logging driver and options you set.

Check active log file sizes again later:

sudo find /var/lib/docker/containers -name '*-json.log' -type f -exec du -h {} + | sort -hr | head -20

For host-managed file logs, inspect the rotated files and timestamps:

ls -lah /srv/myapp/logs

Expected outcomes:

  • No single container log file grows without limit.
  • You know which logs are managed by Docker and which are managed by logrotate.
  • Disk growth becomes easier to predict and easier to investigate.

Practical cleanup commands to know

If a server is already under pressure, these commands help you investigate safely:

journalctl --disk-usage
sudo du -sh /var/lib/docker
sudo du -sh /var/log/* | sort -hr | head

Avoid truncating or deleting active container logs unless you fully understand the tradeoffs. It is better to set rotation, restart cleanly if needed, and then re-check disk usage.

Rollback and recovery notes

If a Docker restart caused trouble, revert /etc/docker/daemon.json to the previous working version and restart Docker again:

sudo cp /etc/docker/daemon.json.bak /etc/docker/daemon.json
sudo systemctl restart docker

If a per-service Compose logging change caused issues, restore the old Compose file and recreate that service:

docker compose up -d

Keep in mind that rotation settings do not recreate old deleted logs. If you need forensic retention, copy or archive important logs before experimenting on a problem host.

Troubleshooting common Docker log problems

Docker failed to restart after editing daemon.json.
The JSON file may be invalid. Validate it with python3 -m json.tool and check sudo journalctl -u docker -n 100.

My container still has one giant log file.
Existing files may not shrink immediately. Rotation limits help going forward. You may need a container restart and some time for the new policy to take effect.

docker logs stopped showing old output.
That is expected once rotation removes older log segments. Increase max-file or forward logs centrally if you need longer retention.

I already use Loki, ELK, or another logging stack.
You may still want local size caps. Centralized logging does not always stop local files from growing.

Disk is still full after fixing container logs.
Look at journald, old images, stopped containers, caches, and application file logs too. Log problems often overlap with image or volume cleanup needs.

Warning: A log limit that is too small can hide recent errors you needed for debugging. Pick caps that control growth without making troubleshooting impossible.

What to do next

Once your logs are under control, the next reliability habit is making sure lightweight app data like SQLite can be backed up and restored without corruption. Continue with How to Back Up and Restore SQLite App Data Safely.