Unifying Team Development Environments with Docker Daemon Global Configuration

Whether you're using Docker locally or on a server, you often find yourself repeatedly copying and pasting the same configurations into docker-compose.yml for every project.

  • Always setting DNS to 1.1.1.1, 8.8.8.8
  • Fixing the log driver to json-file + max-size=10m
  • Proxy settings, insecure registries, default network ranges, and more…

These aren't individual container settings, but rather "host-wide defaults", which are much easier to manage if you extract them. This is precisely the role of Docker daemon global configuration (daemon.json).

Below, we'll cover:

  • Which file
  • Where to create it
  • How to write it
  • In what situations it's useful for developers and teams


1. Two Ways to Configure the Docker Daemon

There are two primary ways to configure the Docker daemon (dockerd):

  1. Using a JSON configuration file (daemon.json)Recommended
  2. Passing options via CLI flags when running dockerd

While you can mix and match them, if you specify the same option in both, the daemon will fail to start. For example, if you include a log driver in both the --log-driver flag and daemon.json, Docker will throw an error and shut down during startup.

For standardizing team/server environments, it's generally recommended to:

"Consolidate as much as possible into daemon.json, and use flags minimally."

2. daemon.json Location Overview

The file is located at /etc/docker/daemon.json. This is for Linux, of course.

While some may use Docker in environments other than Linux, I primarily use it on Linux, so I'm not as familiar with other OSes. However, here's a table summarizing the default locations for various operating systems:

Environment Default Path Notes
Linux (Standard Installation) /etc/docker/daemon.json Most common case
Linux (Docker installed via snap) /var/snap/docker/current/config/daemon.json Ubuntu snap package
Windows Server / Docker Engine C:\ProgramData\Docker\config\daemon.json
Docker Desktop (Mac / Windows) ~/.docker/daemon.json
  • This file may not exist by default, so if it's missing, you can create it and start using it.

3. Basic Usage Pattern: "Create File → Restart Daemon"

For Linux, the typical workflow is as follows:

  1. Create/Edit daemon.json
{
  "dns": ["1.1.1.1", "8.8.8.8"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
  1. Validate the configuration file beforehand
sudo dockerd --validate --config-file=/etc/docker/daemon.json
# If "configuration OK" appears, it's normal
  1. Restart the Docker daemon
sudo systemctl restart docker

From now on, any new containers started will inherit these global settings as defaults, unless otherwise specified.

4. Key Configuration: Setting a Global DNS Server

4.1 Why Global DNS?

If you frequently encounter issues like containers "strangely failing to find external APIs" or "internal domains not resolving," it's usually because they depend on the host's DNS settings/environment.

For example:

  • Your entire team wants to use Cloudflare DNS (1.1.1.1)
  • There are endpoints accessible only through your company's internal DNS server

In such cases, it's far more convenient to standardize DNS at the Docker daemon level rather than adding dns: to docker-compose.yml for every project.

4.2 Configuration Example (daemon.json)

{
  "dns": ["1.1.1.1", "8.8.8.8"]
}

If you already have a daemon.json file, simply add the "dns": [...] entry inside the root { ... }.

⚠️ Note: DNS settings are reflected in /etc/resolv.conf inside the container. They are not immediately applied to already running containers; they take effect for newly launched containers.

5. Key Configuration 2 – Global Logging Driver & Options

Container logs are typically stored via the json-file driver under /var/lib/docker/containers/.... Changing this globally allows you to:

  • Log format
  • Log storage location
  • Log rotation policy

To apply these uniformly across all containers.

5.1 Default json-file Driver + Rotation

The most common pattern is "just use json-file, but set up rotation to prevent disk overflow."

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

With this setup:

  • Each container's log file size is capped at 10MB
  • A maximum of 5 files are maintained
  • Excess files are automatically deleted.

5.2 Centralized Log Collection Drivers (fluentd, journald, etc.)

Platform or infrastructure teams often want to send all container logs to a centralized logging system.

For example, if using Fluentd:

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

With this configuration, all container logs are automatically sent to Fluentd without needing a separate docker run --log-driver=... command.

Personally, I'm quite fond of the journald driver. In a systemd-based Linux environment, it allows you to consolidate both application logs and Docker container logs into a single journald instance, enabling unified querying, filtering, and retention policies using journalctl.

If you want to use journald as a global log driver, you could configure it like this, for example:

{
  "log-driver": "journald",
  "log-opts": {
    "tag": "{{.Name}}"
  }
}

Here, since tag is set to the container name:

  • You can quickly scan real-time logs using journalctl -f | grep {container_name}
  • You can combine it with options like --since "10m ago" to view logs from a specific time onward
  • You can use the -t option (based on tag/identifier) like journalctl -f -t {container_name} to specifically target logs from a particular container.

Of course, it's also possible to view logs by unit, such as journalctl -u docker.service, but filtering by container name is more intuitive and requires less typing, making it much more frequently used in practice.

5.3 Relationship with Compose / docker run

  • Global log-driver + log-opts act as "defaults."
  • Specifying logging: (Compose) or --log-driver, --log-opt (CLI) for individual containers will override these settings for that specific container.

Strategically:

  • Common values go into daemon.json
  • Only special services get individual overrides

This configuration is recommended.


6. Key Configuration 3 – Global Network Settings like Proxy, Insecure Registry

There are other frequently used options in global configuration.

6.1 Proxy Settings

If you can only access external networks through a corporate proxy, you can configure the proxy at the daemon level instead of adding environment variables every time.

{
  "proxies": {
    "http-proxy": "http://proxy.example.com:3128",
    "https-proxy": "http://proxy.example.com:3128",
    "no-proxy": "localhost,127.0.0.1,.corp.example.com"
  }
}

This ensures that the Docker daemon follows these proxy settings when pulling images or using the network during builds.

6.2 Insecure Registry

If you absolutely must use a registry without TLS (e.g., for internal development):

{
  "insecure-registries": ["my-registry.local:5000"]
}

Be aware that this can be a security risk, so it should only be used in internal test environments.


7. Key Configuration 4 – Default Network Range, Storage Driver, etc.

7.1 Customizing the Default Bridge Network Range

If you want to avoid IP conflicts with your VPN or internal network:

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

This will make Docker use the 10.20.x.0/24 range when creating new bridge networks.

7.2 Forcing a Storage Driver

The default storage driver can vary depending on the Linux distribution. If your team has decided to only use overlay2:

{
  "storage-driver": "overlay2"
}

The actual supported storage drivers depend on the OS/kernel, so always check the dockerd documentation and your distribution's guide.


Understood. Focusing on "who" (persona) often makes the text stiff and sound like generic AI. I've tried to rewrite it with a focus on human experience and "frustrating situations" to resonate more with readers.


8. If You're Experiencing This 'Déjà Vu', It's Time to Adopt This

You don't need to be an infrastructure expert. If you've recently experienced any of the following, now is the time to tweak your daemon.json:

  • Repeatedly copying and pasting log settings into docker-compose.yml every time you start a new project: If you're constantly digging through yesterday's code to find max-size and max-file settings just to paste them again, you're already wasting valuable time. Set them globally just once, and all your containers will automatically start in 'diet' mode.
  • Containers that worked perfectly in the office suddenly lose internet connectivity in a cafe or VPN environment: This is a classic "it worked on my machine!" scenario. If you want your containers to consistently communicate with the outside world, regardless of network environment, without being swayed by the host's DNS settings, then global DNS pinning is the answer.
  • Feeling overwhelmed trying to match settings across numerous server nodes: Are you troubleshooting 'ghost bugs' caused by subtle differences in Docker settings between servers? Deploying a single daemon.json file ensures all your servers operate under the same rules.

When repetitive configurations become tiresome, or you're fed up with troubleshooting due to environmental changes, that's the perfect moment to adopt these settings.

Summary

  • Docker's global defaults are managed in daemon.json.
  • The location is usually /etc/docker/daemon.json.
  • Examples of common global settings:
    • DNS: "dns": ["1.1.1.1", "8.8.8.8"]
    • Log driver: "log-driver": "json-file", "log-opts": {...}
    • Proxy, insecure registry, default network range, storage driver, etc.
  • Global settings are useful for repetitive configurations and when deploying many nodes in diverse environments.

If you're constantly writing the same options in docker-compose.yml or docker run, it might be time to move them up to daemon.json.

image of docker daemon json setting