Docker Daemon Global Configuration to Unify Team Development Environments

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.

  • Consistently setting DNS to 1.1.1.1, 8.8.8.8,
  • Fixing the log driver to json-file + max-size=10m,
  • Or configurations for proxies, 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 centralized. This is precisely the role of Docker daemon global configuration (daemon.json).

Below, we'll cover:

  • Which file to create
  • Where to create it
  • How to write it
  • And in what situations it proves useful for developers and teams.


1. Two Ways to Configure the Docker Daemon {#sec-7390246eab38}

The Docker daemon (dockerd) can be configured primarily in two ways:

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

While you can combine both methods, specifying the same option in both will prevent the daemon from starting at all. For example, if you include a log driver in both the --log-driver flag and daemon.json, Docker will error out and terminate during startup.

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

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

2. daemon.json Location

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

While some might use Docker in non-Linux environments, I primarily work with Linux, so I'm less familiar with other OSes. However, here's a convenient table summarizing the default locations per OS:

Environment Default Path Notes
Linux (standard installation) /etc/docker/daemon.json Most common case
Linux (Docker installed with 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 might not exist by default, so if it's missing, you can create it yourself.

3. Basic Usage Pattern: “Create File → Restart Daemon” {#sec-bffe465cc36f}

On Linux, the typical workflow is as follows:

  1. Write/Modify daemon.json
{
  "dns": ["1.1.1.1", "8.8.8.8"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
  1. Pre-validate the configuration file
sudo dockerd --validate --config-file=/etc/docker/daemon.json
# If 'configuration OK' appears, it's valid :contentReference[oaicite:7]{index=7}
  1. Restart Docker daemon
sudo systemctl restart docker

From now on, newly launched containers will inherit these global settings as defaults unless specified otherwise.

4. Key Setting: Globally Pinning DNS Servers {#sec-d9c2238a423f}

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 often because they rely on the host's DNS settings/environment.

For instance:

  • Your entire team wants to use Cloudflare DNS (1.1.1.1)
  • There's an endpoint only accessible via your company's internal DNS server

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

4.2 Configuration Example (daemon.json)

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

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

⚠️ Caution: DNS settings are reflected in /etc/resolv.conf inside the container. They are not applied immediately to already running containers, but only to newly launched ones.

5. Key Setting 2 – Global Logging Driver & Options Configuration {#sec-360ddebc7b6c}

Container logs are typically stored under /var/lib/docker/containers/... via the json-file driver. 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 to “simply use json-file, but configure 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 will be a maximum of 10MB.
  • A maximum of 5 files will be retained.
  • Excess files will be automatically deleted.

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

For platform or infrastructure teams, there's often a need 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 will be automatically sent to Fluentd without needing a separate docker run --log-driver=... command.

Personally, I'm also 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, unifying viewing, filtering, and retention policies using just journalctl.

If you wish to use journald as your global log driver, you can configure it like this, for example:

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

Since tag is used as the container name here:

  • You can quickly review real-time logs using journalctl -f | grep {container_name}.
  • You can also combine it with options like --since "10m ago" to view logs only after a specific time.
  • Or, using the -t option (based on tag/identifier) like journalctl -f -t {container_name}, you can specifically pinpoint logs for a particular container.

While it's also possible to view logs by unit, like journalctl -u docker.service, 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”
  • If logging: (Compose) or --log-driver, --log-opt (CLI) are specified for individual containers, only that container will override the global settings.

Strategically, we recommend a configuration where:

  • Common values are in daemon.json.
  • Only specific services are overridden individually.

6. Key Setting 3 – Global Network Configurations like Proxy, Insecure Registry {#sec-0d687ac65460}

There are other frequently used options in global settings.

6.1 Proxy Settings

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

{
  "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 way, the Docker daemon will follow these proxy settings when pulling images or using the network during builds.

6.2 Insecure Registry

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

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

This can be a security risk, so be careful to use it only in internal testing environments.


7. Key Setting 4 – Default Network Range, Storage Driver, and More {#sec-3598d5fb02d3}

Some more infrastructure-oriented options:

7.1 Customizing the Default Bridge Network Range

When you want to avoid IP conflicts with VPNs or internal company networks:

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

This ensures Docker uses 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 use only overlay2:

{
  "storage-driver": "overlay2"
}

The actual supported storage drivers vary by OS/kernel, so always consult the dockerd documentation and your distribution's guide.


8. If You're Experiencing This 'Deja Vu', It's Time to Adopt Global Settings {#sec-807a100451aa}

You don't need to be an infrastructure expert. If you've recently experienced any of the following, it's high time you started configuring daemon.json.

  • You're digging through docker-compose.yml and copy-pasting log settings every time you start a new project: If you're constantly fetching max-size and max-file settings from old code and pasting them in again, you're already wasting valuable time. Set it globally once, and all your containers will automatically start in 'diet' mode.
  • Containers that worked perfectly in the office suddenly lose internet connection in a cafe or VPN environment: This is a classic "but it worked on my machine!" scenario. If you want your containers to communicate consistently with the outside world in any network environment, without being swayed by the host's DNS settings, then global DNS pinning is the answer.
  • You're losing your mind trying to manually adjust settings on countless server nodes: Are you debugging "ghost bugs" caused by subtly different Docker configurations on each server? Deploying a single daemon.json file can make all your servers behave like a disciplined army, following the exact same rules.

The optimal moment to adopt these settings is when you're tired of repetitive configurations or fed up with debugging issues caused by environmental changes.

Summary

  • Docker's global defaults are managed in daemon.json.
  • The location is typically /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…
  • Global settings are useful for repetitive configurations and when deploying many nodes across diverse environments.

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

image of docker daemon json setting