Container logs felt harmless to me for much longer than they should have.
They looked like background noise. Housekeeping. The kind of thing you only think about after a problem appears.
That was the mistake.
Docker will keep writing logs very patiently if you let it. If a service is noisy enough, the host disk eventually becomes the thing absorbing that patience. And the dangerous part is that nothing about the failure feels dramatic at first. There is no cinematic moment. There is just a slow shift from “this container is chatty” to “why is the host suddenly under storage pressure?”
What finally helped me was treating logging as part of container design, not as cleanup after the fact.
Once you do that, the problem becomes much less mysterious. Docker’s defaults explain the risk, and Docker’s own documentation also explains the way out.
- Why Docker log growth is easier to ignore than it should be
- What the default
json-filebehavior actually does - Why Docker recommends the
locallogging driver for general use - How to enable safe rotation if you stay with
json-file - The easy mistake: changing defaults but forgetting existing containers
- What I would check when a host is already under pressure
- The logging rule I now trust for small homelabs
For the technical baseline below, I use Docker's official documentation and separate documented platform behavior from my own placement and operating recommendations.
Docker log growth is dangerous because it usually looks polite
This is what makes the issue so easy to postpone.
A container is supposed to log. We want visibility. We want service output. We want to know what the app is doing. That all sounds responsible.
The problem is that Docker’s default behavior is not quietly protecting your disk for you.
The official logging documentation says Docker uses the json-file logging driver by default, and it is very direct about the risk: by default, no log rotation is performed. Docker even recommends the local logging driver to prevent disk exhaustion, specifically because the default json-file setup can consume a significant amount of disk space for containers that generate a lot of output.
That is the entire story in one paragraph.
The host is not going to save itself from chatty containers unless you make a decision first.
The default is more historical than ideal
This part made the whole subject feel less strange to me.
Docker keeps json-file as the default for backward compatibility and for situations where Docker is used as a runtime for Kubernetes. That does not mean it is the best general default for a typical homelab box.
It means the default exists partly because history exists.
That is an important emotional distinction, because many people treat defaults as recommendations. Here, the default is not really a strong recommendation for every standalone Docker host. Docker’s own docs point elsewhere for general disk-safety thinking.
Once I understood that, it became much easier to stop thinking, “well, surely the default must be fine.”
The default is common.
That is not the same thing as ideal.
For most homelabs, the local driver is the calmer answer
Docker’s documentation does not dance around this. It explicitly recommends the local logging driver to prevent disk exhaustion.
Why?
Because the local driver:
- performs log rotation by default;
- uses a more efficient storage format;
- is designed to be a safer general-purpose local choice for ordinary Docker hosts.
Docker documents the local driver as preserving about 100MB of log messages per container by default, using 20MB files and keeping 5 files with compression enabled. That is a much more adult starting point than unlimited json-file growth.
This is the kind of default I want in a homelab.
Not because every container needs perfect logging discipline from day one, but because I do not want one noisy service to be able to consume storage quietly while I am focused on something else.
If I am setting a fresh host, the daemon-level change I trust most is:
{
"log-driver": "local"
}
That goes in Docker’s daemon.json, usually:
/etc/docker/daemon.json
Then restart Docker.
That alone moves the host from “logs can grow forever unless I remember to care” to “logs have a sane default boundary unless I explicitly choose otherwise.”
If you stay with json-file, rotation should stop being optional
There are still valid reasons to stay with json-file.
Maybe a workflow expects it.
Maybe you want maximum compatibility.
Maybe you are following a deployment pattern that is easier to reason about if you leave the driver in place.
That is fine.
But if I stay with json-file, I no longer treat rotation as optional decoration.
Docker’s own documentation shows the path clearly: configure max-size and max-file so the logs rotate automatically.
A simple daemon-level example looks like this:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Two details here are easy to miss and worth remembering:
- Docker expects
log-optsvalues indaemon.jsonto be strings. - If you forget rotation,
json-filewill just keep growing.
That second point is obvious only after it is already expensive.
The most common mistake is changing the daemon default and assuming the problem is solved
This is the trap I most want the article to prevent.
Docker’s documentation is very clear: after changing the daemon logging configuration and restarting Docker, the new settings apply automatically only to newly created containers. Existing containers do not pick up the new logging configuration automatically.
That sentence matters more than many people realize.
Because it means this is not enough:
- edit
daemon.json; - restart Docker;
- feel relieved.
If the containers that are already filling the disk were created before the change, they will keep using their old logging configuration until they are recreated.
That is one of those beautifully irritating details that explains why a host can still behave “wrong” even after you technically changed the right setting.
So the real workflow is:
- choose the driver and rotation policy;
- update
daemon.json; - restart Docker;
- recreate the containers that need the new policy.
That last step is where the change becomes real.
If the host is already under pressure, I start with visibility before cleanup
Once the disk is getting tight, I do not want blind deletion. I want a quick picture of where Docker space is going.
One useful starting point from Docker’s CLI reference is:
docker system df
That does not solve log growth by itself, but it does help reintroduce structure when the Docker side of the host starts feeling larger than expected.
At that point, I also think in layers:
- how much space is going to images;
- how much is going to stopped containers;
- how much is going to volumes;
- and whether the noisy service problem is really a logging-driver problem, a bad app behavior problem, or both.
This is very similar to the inventory-first approach in the Proxmox storage types guide. The calmer pattern is always inventory first, deletion second.
Do not treat Docker’s raw log files like normal application files
This is a subtle but important operational point.
Docker’s documentation for the json-file driver warns that these log files are designed to be accessed exclusively by the Docker daemon, and that interacting with them using external tools may interfere with Docker and cause unexpected behavior.
That matters because a lot of people eventually discover the large files on disk and feel tempted to “just truncate them” like any other log.
I understand the temptation.
I do not trust it.
If the logging policy is wrong, I would rather fix the logging policy than build a habit around manually wrestling Docker’s internal files.
The host should not depend on ad hoc heroics to stay breathable.
The logging rule I trust now
This is the rule I would give my earlier self:
If the host is a normal homelab Docker machine, use the local logging driver by default.
If you need json-file, configure rotation explicitly from day one.
If you changed the daemon policy after containers already existed, recreate those containers so the policy actually takes effect.
And if the disk is already in trouble, inventory the host first instead of acting out of panic.
That rule is not glamorous, but it is the kind of thing that keeps a lab calm.
Logs are supposed to help you understand a service.
They are not supposed to quietly become the service’s biggest storage dependency.
The container engine changes some defaults, but not the need for limits and retention. The Podman versus Docker comparison shows where daemonless and rootless operation alter the logging model without removing operational responsibility.
This operating decision also connects to Resource Limits in Docker: Restricting CPU and RAM Usage Per Container, where the same tradeoff appears at a different layer of the homelab.
FAQ
Why can Docker logs fill a host disk so easily?
Because Docker’s default json-file logging behavior does not rotate logs automatically unless you configure rotation yourself. A noisy container can therefore keep writing until the host pays the price.
Is the local logging driver better for most homelabs?
Usually, yes. Docker explicitly recommends it to prevent disk exhaustion, and it rotates logs by default using a more efficient storage format.
If I change daemon.json, do my current containers start rotating logs automatically?
No. Docker’s documentation is clear that new daemon logging defaults apply automatically only to newly created containers. Existing containers need to be recreated to pick up the new configuration.
Can I just manually edit or truncate Docker’s json-file logs?
That is not a good operational habit. Docker warns that those files are meant to be accessed exclusively by the Docker daemon, and external interference can cause unexpected behavior.
Should I always switch from Docker to Podman just to get better logging behavior?
Not necessarily. Better logging discipline inside Docker is usually simpler than changing engines for this one issue. The engine choice matters, but log rotation policy is still something you should define deliberately either way.



