}

Docker daemon.json: Complete Configuration Reference 2026

Docker daemon.json: Complete Configuration Reference 2026

The Docker daemon (dockerd) is the background service that manages Docker containers, images, networks, and volumes. While you can configure Docker using command-line flags, the preferred method is using the daemon.json configuration file. This 2026 reference covers every major option with annotated examples, validation steps, how to reload configuration without a full restart, and troubleshooting for common JSON syntax errors.

What is daemon.json?

The daemon.json file is a JSON configuration file that lets you customize Docker daemon behavior without modifying systemd service files or startup scripts. Changes persist across Docker updates and provide a cleaner, version-controllable configuration approach.

File Location

Operating System Location
Linux /etc/docker/daemon.json
Windows C:\ProgramData\docker\config\daemon.json
macOS (Docker Desktop) ~/.docker/daemon.json or via Docker Desktop UI

On a fresh Docker installation this file does not exist — you need to create it:

# Create the directory if it does not exist
sudo mkdir -p /etc/docker

# Create the file
sudo touch /etc/docker/daemon.json

All Major Configuration Options

log-driver and log-opts

Control how container logs are stored and rotated. The default driver is json-file, which writes logs to the local filesystem. Without size limits, logs can grow to fill the disk.

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5",
    "compress": "true"
  }
}

Key log-opts parameters:

Option Description Example
max-size Maximum size before rotation "10m", "100m", "1g"
max-file Number of rotated files to keep "3", "5"
compress Compress rotated log files "true"
labels Attach container labels to log entries "env,version"

Available log drivers:

Driver Description
json-file Default — logs to local JSON files
syslog Writes to the system syslog
journald Writes to systemd journal
fluentd Sends logs to Fluentd
awslogs Sends logs to Amazon CloudWatch
gcplogs Sends logs to Google Cloud Logging
splunk Sends logs to Splunk
none Disables logging for all containers

Centralized logging with Fluentd:

{
  "log-driver": "fluentd",
  "log-opts": {
    "fluentd-address": "localhost:24224",
    "tag": "docker.{{.Name}}"
  }
}

storage-driver

The storage driver controls how image layers and container filesystems are stored on disk. overlay2 is the recommended choice for all modern Linux distributions.

{
  "storage-driver": "overlay2"
}

With optional kernel check override (older kernels):

{
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}

Available storage drivers:

Driver When to use
overlay2 Recommended for all Linux (kernel 4.0+)
fuse-overlayfs Rootless Docker mode
btrfs Btrfs filesystem
zfs ZFS filesystem
devicemapper Legacy — not recommended

To move the data root to a different disk:

{
  "data-root": "/mnt/docker-data"
}

Warning: Changing the storage driver makes existing images and containers inaccessible. Always backup before changing.


insecure-registries

Allow Docker to communicate with private or development registries that do not have a valid TLS certificate:

{
  "insecure-registries": [
    "registry.local:5000",
    "192.168.1.100:5000",
    "internal-registry.company.local:5000"
  ]
}

Warning: Never use insecure registries in production. Configure proper TLS certificates for any registry handling sensitive images.


registry-mirrors

Registry mirrors speed up image pulls by caching Docker Hub images locally. Useful for CI/CD pipelines, large teams, or air-gapped environments.

{
  "registry-mirrors": [
    "https://mirror.gcr.io",
    "https://docker-mirror.example.com"
  ]
}

For a self-hosted mirror (e.g., Harbor or a Docker distribution registry):

{
  "registry-mirrors": [
    "https://registry.internal.company.com:5000"
  ]
}

dns

Configure custom DNS servers applied to all containers. Useful when your network has internal DNS servers or Docker's default DNS resolution is unreliable:

{
  "dns": ["8.8.8.8", "8.8.4.4"],
  "dns-search": ["example.com", "corp.internal"],
  "dns-opts": ["timeout:2", "attempts:3", "ndots:1"]
}

When to set custom DNS:

  • Your host resolves internal hostnames that containers also need
  • You want to ensure consistent DNS across all containers regardless of host configuration
  • You are running in a corporate network with a split-horizon DNS

live-restore

Keep containers running when the Docker daemon is stopped, restarted, or upgraded. This is essential for production environments where container downtime must be minimized:

{
  "live-restore": true
}

Benefits:

  • Containers survive daemon restarts and upgrades
  • Enables zero-downtime Docker upgrades on a host
  • Reduces the blast radius of daemon crashes

Limitations:

  • Not compatible with Docker Swarm mode
  • Some daemon configuration changes still require restarting the affected containers
  • Attaching to a container started before the daemon restart may not work

exec-opts (native.cgroupdriver=systemd)

This option is required when running Docker on a host managed by Kubernetes. Both the kubelet and the container runtime must use the same cgroup driver. The recommended value is systemd:

{
  "exec-opts": ["native.cgroupdriver=systemd"]
}

Why this matters for Kubernetes:

If Docker uses the default cgroupfs driver while kubelet is configured for systemd, pods may fail to start and you will see errors like:

failed to create kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd"

Always set native.cgroupdriver=systemd on any node joining a Kubernetes cluster.

Full recommended configuration for a Kubernetes node:

{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true
}

default-ulimits

Set default resource limits for all containers. This prevents a runaway container from exhausting system file descriptors or processes:

{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    },
    "nproc": {
      "Name": "nproc",
      "Hard": 65536,
      "Soft": 65536
    },
    "memlock": {
      "Name": "memlock",
      "Hard": -1,
      "Soft": -1
    }
  }
}

memlock with -1 means unlimited — required for GPU workloads and some databases.


Additional Useful Options

Default address pools — prevent IP range conflicts with your network:

{
  "default-address-pools": [
    {"base": "172.20.0.0/16", "size": 24}
  ]
}

Metrics — expose a Prometheus scrape endpoint:

{
  "metrics-addr": "127.0.0.1:9323",
  "experimental": true
}

Debug mode — increase daemon log verbosity for troubleshooting:

{
  "debug": true,
  "log-level": "debug"
}

IPv6 support:

{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}

Security hardening:

{
  "userns-remap": "default",
  "no-new-privileges": true,
  "userland-proxy": false
}

Complete Annotated daemon.json Example

Below is a production-ready daemon.json. JSON does not support comments natively — each key is explained in the table after the snippet. Use the JSON block directly without modifications.

{
  "storage-driver": "overlay2",
  "data-root": "/mnt/docker-data",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5",
    "compress": "true"
  },
  "exec-opts": ["native.cgroupdriver=systemd"],
  "live-restore": true,
  "registry-mirrors": [
    "https://mirror.gcr.io"
  ],
  "insecure-registries": [],
  "dns": ["8.8.8.8", "8.8.4.4"],
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    }
  },
  "default-address-pools": [
    {"base": "172.20.0.0/16", "size": 24}
  ],
  "metrics-addr": "127.0.0.1:9323",
  "experimental": true,
  "userland-proxy": false,
  "no-new-privileges": true,
  "log-level": "warn",
  "max-concurrent-downloads": 10,
  "max-concurrent-uploads": 5
}

Each key explained:

Key Purpose
storage-driver Use overlay2 for best performance on modern kernels
data-root Store Docker data on a dedicated volume
log-driver / log-opts Log rotation — keep 5 files of up to 50 MB each, compressed
exec-opts Required for Kubernetes nodes (systemd cgroup driver)
live-restore Keep containers alive when the daemon restarts
registry-mirrors Pull-through cache for Docker Hub images
insecure-registries Private registries without TLS (keep empty in production)
dns Default DNS for all containers
default-ulimits Raise open file descriptor limits system-wide
default-address-pools Prevent IP range conflicts with corporate network
metrics-addr Prometheus metrics endpoint (localhost only)
userland-proxy Disable for better network performance
no-new-privileges Security: prevent privilege escalation inside containers
log-level Reduce daemon log noise in production
max-concurrent-downloads/uploads Increase parallel image throughput

Validate daemon.json Before Restarting

Method 1: dockerd --validate (Docker 23.0+)

Docker 23.0 introduced a built-in validation flag:

sudo dockerd --validate --config-file /etc/docker/daemon.json
  • Exit code 0: configuration is valid.
  • Non-zero exit with error message: fix the reported issue before restarting.

Method 2: JSON syntax check with python3

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

A clean JSON file produces formatted output with no errors. Any syntax error is printed with the line number.

Method 3: jq

cat /etc/docker/daemon.json | jq .

Both python3 -m json.tool and jq catch JSON syntax errors but cannot validate Docker-specific option names and types. Use dockerd --validate for full semantic validation when available.


Reload Config Without a Full Restart

Some daemon options can be applied without restarting Docker by sending SIGHUP to the daemon process:

sudo kill -SIGHUP $(pidof dockerd)

Options that support SIGHUP reload (no restart needed):

  • debug
  • log-level
  • labels
  • live-restore
  • cluster-store
  • cluster-advertise
  • max-concurrent-downloads
  • max-concurrent-uploads

Options that require a full daemon restart:

  • storage-driver
  • exec-opts
  • data-root
  • log-driver / log-opts
  • insecure-registries
  • registry-mirrors
  • dns

Full restart procedure:

# 1. Validate the new configuration
sudo dockerd --validate --config-file /etc/docker/daemon.json

# 2. Reload systemd (if you also edited the service file)
sudo systemctl daemon-reload

# 3. Restart Docker
sudo systemctl restart docker

# 4. Confirm Docker is healthy
sudo systemctl status docker
docker info | head -30

Troubleshooting: Common JSON Syntax Errors

Error: "unable to configure the Docker daemon with file"

Docker emits this error when daemon.json is invalid. Check the daemon logs:

sudo journalctl -u docker.service -n 30

Then validate the file:

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

Most common JSON mistakes:

Mistake Bad example Fixed example
Trailing comma after last item {"debug": true,} {"debug": true}
Single quotes instead of double {'debug': true} {"debug": true}
Missing comma between items {"debug": true "log-level": "info"} {"debug": true, "log-level": "info"}
Unquoted string value {"log-level": info} {"log-level": "info"}
Boolean as string {"live-restore": "true"} {"live-restore": true}
Integer as string {"max-concurrent-downloads": "10"} {"max-concurrent-downloads": 10}

Error: "Conflicting options: option already set in file"

You cannot set the same option in both daemon.json and Docker's systemd service flags. Check the service file:

sudo systemctl cat docker.service

Look for the ExecStart line. Any flag like --log-driver, --storage-driver, or --dns must be removed if the same key exists in daemon.json.

Error: Docker starts but containers cannot reach the network

Check for IP range conflicts:

docker network inspect bridge
ip route

If Docker's default 172.17.0.0/16 overlaps with your corporate network, set a different range in daemon.json:

{
  "bip": "192.168.200.1/24",
  "default-address-pools": [
    {"base": "192.168.201.0/24", "size": 28}
  ]
}

Reset to Default Configuration

If Docker will not start after a bad change:

sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.backup
sudo systemctl start docker

Fix the backup file, then restore it and restart.


How to Apply Changes

systemd-based systems (Ubuntu, Debian, CentOS 7+, Fedora, RHEL)

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl status docker

Older init systems

sudo service docker restart

Verify Applied Configuration

# Human-readable summary
docker info

# Check specific settings
docker info --format '{{.LoggingDriver}}'
docker info --format '{{.Driver}}'
docker info --format '{{.CgroupDriver}}'

Environment-Specific Configuration Examples

Kubernetes Node

{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {"max-size": "100m", "max-file": "3"},
  "storage-driver": "overlay2",
  "live-restore": true
}

Development Environment

{
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {"max-size": "10m", "max-file": "3"},
  "dns": ["8.8.8.8", "8.8.4.4"],
  "insecure-registries": ["localhost:5000"],
  "debug": true,
  "experimental": true,
  "features": {"buildkit": true}
}

CI/CD Build Server

{
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {"max-size": "20m", "max-file": "3"},
  "registry-mirrors": ["https://mirror.gcr.io"],
  "max-concurrent-downloads": 10,
  "max-concurrent-uploads": 5,
  "features": {"buildkit": true}
}

Air-Gapped / Restricted Network

{
  "storage-driver": "overlay2",
  "registry-mirrors": ["https://internal-registry.company.com:5000"],
  "insecure-registries": ["internal-registry.company.com:5000"],
  "dns": ["10.0.0.53"],
  "dns-search": ["company.internal"],
  "log-driver": "syslog",
  "log-opts": {
    "syslog-address": "udp://10.0.0.100:514",
    "tag": "docker/{{.Name}}"
  },
  "default-address-pools": [{"base": "10.200.0.0/16", "size": 24}]
}

NVIDIA GPU Host

{
  "storage-driver": "overlay2",
  "default-runtime": "nvidia",
  "runtimes": {
    "nvidia": {
      "path": "nvidia-container-runtime",
      "runtimeArgs": []
    }
  },
  "log-driver": "json-file",
  "log-opts": {"max-size": "50m", "max-file": "3"},
  "default-ulimits": {
    "memlock": {"Name": "memlock", "Hard": -1, "Soft": -1}
  }
}

Related Docker Guides

Summary

The daemon.json file is the recommended way to configure Docker. Key takeaways for 2026:

  1. Always validate before restarting: sudo dockerd --validate --config-file /etc/docker/daemon.json
  2. Reload without restart for supported options: sudo kill -SIGHUP $(pidof dockerd)
  3. Kubernetes nodes must set "exec-opts": ["native.cgroupdriver=systemd"]
  4. Enable log rotation in every environment — the default json-file driver has no size limit unless you configure max-size and max-file
  5. Enable live-restore on production hosts to keep containers running during daemon upgrades
  6. No conflicts — never duplicate an option between daemon.json and systemd service flags

For the complete list of available options, refer to the official Docker daemon documentation.