}

Docker daemon.json Complete Guide — All Options with Examples (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 SystemLocation
Linux/etc/docker/daemon.json
WindowsC:\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:

OptionDescriptionExample
max-sizeMaximum size before rotation"10m", "100m", "1g"
max-fileNumber of rotated files to keep"3", "5"
compressCompress rotated log files"true"
labelsAttach container labels to log entries"env,version"

Available log drivers:

DriverDescription
json-fileDefault — logs to local JSON files
syslogWrites to the system syslog
journaldWrites to systemd journal
fluentdSends logs to Fluentd
awslogsSends logs to Amazon CloudWatch
gcplogsSends logs to Google Cloud Logging
splunkSends logs to Splunk
noneDisables 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:

DriverWhen to use
overlay2Recommended for all Linux (kernel 4.0+)
fuse-overlayfsRootless Docker mode
btrfsBtrfs filesystem
zfsZFS filesystem
devicemapperLegacy — 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:

KeyPurpose
storage-driverUse overlay2 for best performance on modern kernels
data-rootStore Docker data on a dedicated volume
log-driver / log-optsLog rotation — keep 5 files of up to 50 MB each, compressed
exec-optsRequired for Kubernetes nodes (systemd cgroup driver)
live-restoreKeep containers alive when the daemon restarts
registry-mirrorsPull-through cache for Docker Hub images
insecure-registriesPrivate registries without TLS (keep empty in production)
dnsDefault DNS for all containers
default-ulimitsRaise open file descriptor limits system-wide
default-address-poolsPrevent IP range conflicts with corporate network
metrics-addrPrometheus metrics endpoint (localhost only)
userland-proxyDisable for better network performance
no-new-privilegesSecurity: prevent privilege escalation inside containers
log-levelReduce daemon log noise in production
max-concurrent-downloads/uploadsIncrease 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:

MistakeBad exampleFixed 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.

Leonardo Lazzaro

Software engineer and technical writer. 10+ years experience in DevOps, Python, and Linux systems.

More articles by Leonardo Lazzaro