Reload a CoreDNS Corefile safely and verify the new DNS answer

John Burns

A small Corefile edit can change the answer a resolver gives to every client that uses it. The risky part is not typing one more host record. It is deciding whether the new configuration is valid, whether the running process actually adopted it, and whether clients are receiving the intended answer rather than an answer held in a cache.

This guide uses CoreDNS 1.14.6 to serve a small internal-style name from the hosts plugin, enable the CoreDNS reload plugin, and prove a Corefile change with a direct DNS query. The completed result is a resolver that changes app.example.test from 192.0.2.20 to 198.51.100.20 after a Corefile edit, without a manual signal or service restart. Use the documentation address ranges in this example only as placeholders; replace the name and address with values approved for the DNS zone you administer.

The procedure was tested in an isolated Linux amd64 directory with CoreDNS 1.14.6. The process listened only on loopback port 1053, so it did not change the host resolver or serve a network. The downloaded archive matched the release’s adjacent SHA-256 file. A dig query returned 192.0.2.20 before the edit and 198.51.100.20 after the reload log recorded completion. A deliberately unknown Corefile directive made a fresh CoreDNS invocation exit with status 1. This is a local syntax and reload test, not evidence that a production DNS topology, Kubernetes deployment, TLS listener, or forwarding path is safe to change without its own review.

CoreDNS 1.14.6 was released on 10 July 2026. The patch release includes forwarding and secondary-zone improvements as well as fixes for ARM and MIPS build issues. The configuration pattern here is useful independently of those release details: validate the exact binary and Corefile, then test the DNS behavior that the change is supposed to produce.

Decide what should reload

The CoreDNS reload plugin watches the Corefile itself by calculating a SHA-512 value periodically. When that file changes, CoreDNS parses and reloads the new configuration. That is distinct from the hosts plugin’s own reload behavior for an external hosts-style file. If records live inline in the Corefile, as they do below, use the CoreDNS reload plugin. If records live in a separate file, use the hosts plugin’s reload setting and test that file path instead.

Keep the smallest possible scope for an initial test. A server block that owns only a local test name makes the expected result unambiguous. Do not add a forward stanza merely to make a test look more realistic; forwarding can expose an internal name or make a typo look like a successful external lookup. In a production configuration, retain the existing plugin chain and make a reviewed, minimal diff.

The hosts plugin creates A, AAAA, and PTR data from hosts-style entries. Its fallthrough setting passes an unmatched name to the next plugin in the server block. That is useful when a later plugin is deliberately responsible for the rest of the zone. It is not a substitute for defining the intended authority and forwarding behavior.

Fetch and verify a fixed CoreDNS release

Start from a disposable directory on the machine where the test will run. The release archive and its checksum file are published as separate assets. Check the archive before extracting or running it. Do not replace an operating system package or a Kubernetes image with this local test binary.

set -eu
version=1.14.6
workdir=$(mktemp -d)
cd "$workdir"
base="https://github.com/coredns/coredns/releases/download/v${version}"

curl --fail --location --output coredns.tgz \
  "$base/coredns_${version}_linux_amd64.tgz"
curl --fail --location --output coredns.tgz.sha256 \
  "$base/coredns_${version}_linux_amd64.tgz.sha256"

expected=$(cut -d ' ' -f1 coredns.tgz.sha256)
actual=$(sha256sum coredns.tgz | cut -d ' ' -f1)
test "$actual" = "$expected"
printf '%s\n' 'CoreDNS archive checksum matched'

tar -xzf coredns.tgz coredns
chmod 0755 coredns
./coredns -version

The test comparison is intentionally explicit because the checksum file names the release asset while this example saves it locally as coredns.tgz. If you retain the upstream filename, sha256sum -c can consume the sidecar file directly. Stop on any failed download or checksum comparison.

The tested binary printed the following version information:

CoreDNS-1.14.6
linux/amd64, go1.26.5, 424d125

For a managed installation, use the artifact source and upgrade method documented by that platform. Record the actual image digest or package version in the change record. The test binary establishes the behavior of this example; it does not validate a different build supplied by a distribution or container registry.

Build a narrow Corefile

Create a Corefile that binds only to a non-privileged loopback test port. The reload 2s line is the minimum supported check interval. CoreDNS may add jitter when multiple instances share a Corefile, so a production verification should allow for the documented interval rather than assuming an exact second.

.:1053 {
    hosts {
        192.0.2.20 app.example.test
        fallthrough
    }
    reload 2s
    log
}

.:1053 makes this server block authoritative for the root zone on port 1053. The inline hosts entry supplies the test A record. fallthrough has no later resolver in this minimal example, but it documents the behavior required when this block is added ahead of an existing plugin chain. log is useful in a short lab because it records the query and reload events; consider query volume and privacy before enabling it in a busy production resolver.

Before touching a running service, run an independent parser check in a disposable context. CoreDNS does not have a separate dry-run flag; starting it with an invalid Corefile should fail before it can serve DNS. For example, an unknown directive should produce a nonzero exit status:

.:1054 {
    hosts {
        192.0.2.20 app.example.test
    }
    definitely-not-a-coredns-plugin
}
./coredns -conf Corefile.invalid
printf 'exit status: %s\n' "$?"

In the isolated test, this command exited with status 1. Run the valid Corefile only after that negative check has shown that the command path reports a configuration mistake. A valid configuration starts a server and remains in the foreground, so use a service manager or a separate terminal when testing it:

./coredns -conf Corefile

Prove the answer before and after the edit

Query the test listener directly. This avoids the host resolver, a local caching daemon, and any upstream DNS path that could hide the CoreDNS answer.

dig @<resolver-address> -p <test-port> app.example.test A +short

The initial test returned:

192.0.2.20

Now change only the address in the Corefile:

.:1053 {
    hosts {
        198.51.100.20 app.example.test
        fallthrough
    }
    reload 2s
    log
}

Wait longer than the configured interval, then repeat the same direct query:

dig @<resolver-address> -p <test-port> app.example.test A +short

The observed result was:

198.51.100.20

The CoreDNS log also contained Reloading followed by Reloading complete. Those two checks answer different questions: the log shows that CoreDNS processed a configuration change, while the query proves that the served DNS data changed. Retain both in a change record, along with the Corefile diff and the CoreDNS version.

Treat listener changes as a different operation

Reloading is graceful for normal Corefile changes, but the CoreDNS reload documentation describes a failure mode when a changed configuration moves a listener to a port already in use. CoreDNS can close the existing listener before discovering it cannot bind the replacement. Keep port, address, health endpoint, and Prometheus listener changes out of a routine record edit whenever possible. Validate them separately with a port check, a maintenance plan, and a rollback path.

For an existing systemd or Kubernetes deployment, do not copy the lab’s port or inline record into the production manifest. Instead, inspect the current Corefile, make a narrowly scoped change, confirm the platform’s reload mechanism and log location, and query from an appropriate client or controlled test pod. Check the record’s TTL and any client-side cache before declaring that a stale answer means the reload failed.

A safe CoreDNS change has a clear expected answer, an artifact and syntax check before service impact, and a direct query after the change. In the local 1.14.6 test, that sequence showed the Corefile reload and the new address without restarting the process. Apply the same proof to the real zone before widening the change.

Sources