Configure and Validate the Docker Engine Daemon with dockerd
dockerd reads its policy from daemon.json, and you can validate a change before it ever touches the running service. Allow about 20 minutes to build a small, reviewable configuration, validate it, and understand which changes actually need a restart.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell, Docker Engine installed, and permission to read the daemon configuration. The examples match Docker Engine 29.8.1 from the installed docker-ce package. Editing the normal system configuration and restarting Docker require elevated privileges; validating a separate file does not.
1. Check the installed daemon
Start with read-only checks that confirm which executable and package you are about to configure:
$ command -v dockerd
/usr/bin/dockerd
$ dockerd --version
Docker version 29.8.1, build 464cd50
$ dpkg-query -W -f='${Package} ${Version}\n' docker-ce
docker-ce 5:29.8.1-1~ubuntu.24.04~noble
The installed manual describes Linux defaults including /etc/docker/daemon.json for configuration, /var/lib/docker for persistent data, /var/run/docker.sock for the default Unix socket, json-file for container logs, and info for the daemon log level. A rootless installation uses a different configuration location, so check how your service is started before editing a file.
2. Inspect the current configuration and service
Do not overwrite an existing configuration. These are ordinary read-only checks:
$ sudo test -f /etc/docker/daemon.json && sudo sed -n '1,200p' /etc/docker/daemon.json
$ systemctl cat docker.service
$ systemctl is-active docker.service
An absent daemon.json is normal. The service unit may pass flags such as --host to dockerd, and Docker rejects a setting duplicated between flags and the JSON file even when the values match. Check the unit before adding keys such as hosts, log-driver or debug.
Checkpoint
Record the file path and any daemon flags shown by systemctl cat. If the service is not called docker.service on your system, use the unit name your package or administrator supplied.
3. Build a minimal configuration
For a new system, make a copy of the current file if it exists, then create the directory and file. This is a configuration change, so use elevated privileges deliberately:
$ sudo install -d -m 0755 /etc/docker
$ if sudo test -f /etc/docker/daemon.json; then
sudo cp --preserve=mode,ownership,timestamps /etc/docker/daemon.json /etc/docker/daemon.json.bak
fi
$ sudoedit /etc/docker/daemon.json
For the editor contents, start with settings that are easy to reason about:
{
"log-level": "info",
"log-driver": "json-file",
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"default-stop-timeout": 10
}
These are the values the installed manual documents for a Linux daemon, so this file makes the intended baseline visible rather than changing it. Docker configuration keys use the flag names without the leading hyphens, and options that accept several values use the plural form, such as labels for the label flag.
Warning
Do not add a remote TCP listener merely to make a client connect. The manual's --tls and --tlsverify settings control transport security, but an exposed daemon socket is a high-impact administrative interface. If you need remote access, design the address, certificates, firewall policy and service startup together.
4. Validate without starting the daemon
Use a separate file while iterating. It avoids touching the live configuration and does not start Docker:
$ install -m 0600 /dev/null /tmp/dockerd-check.json
$ editor /tmp/dockerd-check.json
$ dockerd --validate --config-file=/tmp/dockerd-check.json
configuration OK
$ printf 'validation exit status: %s\n' "$?"
validation exit status: 0
--validate checks the daemon configuration and exits. A non-zero status means the file is not ready to use, and typical causes are malformed JSON, an unknown directive, or a value with the wrong type. Keep the test file private if it contains proxy URLs, certificate paths or other sensitive operational details.
A deliberately invalid file should fail the same way:
$ printf '%s\n' '{"unknown-option": true}' > /tmp/dockerd-invalid.json
$ dockerd --validate --config-file=/tmp/dockerd-invalid.json
unable to configure the Docker daemon with file /tmp/dockerd-invalid.json: the following directives don't match any configuration option: unknown-option
$ printf 'validation exit status: %s\n' "$?"
validation exit status: 1
Remove temporary files after checking them, but do not remove the backup of a working production configuration until the replacement has been tested:
$ rm -- /tmp/dockerd-check.json /tmp/dockerd-invalid.json
5. Apply the configuration through the service manager
Once the live file has passed validation, restart the service so the daemon reads it. This disrupts Docker API access and may affect containers, so choose a maintenance window:
$ sudo systemctl restart docker.service
$ sudo systemctl is-active docker.service
active
$ sudo docker info --format '{{.ServerVersion}}'
29.8.1
A manually launched dockerd runs in the foreground and logs to the terminal. It is useful for troubleshooting, but do not start a second daemon against the same data directory or socket while the service is active. Stop a manually started daemon with Ctrl+C.
If the restart fails, inspect the service log before changing more settings:
$ sudo systemctl status docker.service --no-pager
$ sudo journalctl -u docker.service -n 80 --no-pager
Recovery
To recover the previous file, restore the backup and restart again:
$ sudo cp --preserve=mode,ownership,timestamps /etc/docker/daemon.json.bak /etc/docker/daemon.json
$ sudo dockerd --validate --config-file=/etc/docker/daemon.json
$ sudo systemctl restart docker.service
6. Check the result and avoid misleading tests
Confirm the daemon responds and inspect the settings that matter to your change:
$ sudo docker info
$ sudo docker info --format 'Server={{.ServerVersion}} Logging={{.LoggingDriver}}'
The docker info output is a daemon-side check. It does not prove every container inherited a new default: existing containers keep their own configuration, and a setting such as the default stop timeout applies only when no container-specific value is supplied. A logging-driver change is likewise a default for newly created containers, not a conversion of old log files.
Networking settings deserve extra care. The installed manual says --iptables and IP masquerading are enabled by default, while --ipv6 is disabled by default. Changing bridge addresses, forwarding, firewall integration or the storage driver can affect existing workloads, so take a configuration backup and test those changes on a disposable host first.
Done means
- Versions known. The installed
dockerdanddocker-ceversions are confirmed. - Existing setup checked. The service unit and existing configuration were reviewed before adding keys.
- Validation passed. The JSON passed
dockerd --validatewith exit status 0. - No shortcut listener. No unprotected remote listener was added along the way.
- Service confirmed live. The service is active and
docker infoconfirms the daemon responds. - Backup kept. A restorable backup remains until the new configuration has behaved correctly.