COREDNS-DYNUPDATE(7)
π COREDNS-DYNUPDATE(7) π
okay bestie, so this is the dynupdate page from the CoreDNS Plugins manual, and it's kind of a lot, but we're gonna get through it together, i promise π«Ά
β¨ NAME β¨
dynupdate β accepts authenticated RFC 2136 DNS UPDATE messages for an explicit, opt-in authoritative zone. that's it, that's the whole vibe π
πΈ DESCRIPTION πΈ
So the dynupdate plugin serves one writable authoritative zone, and it does it through the normal CoreDNS authoritative file implementation. One per server block, periodt β the plugin may be used only once per server block. Got separate writable zones? Separate server blocks, babe. An RFC 1035-style zone file gives you the initial data, and that file is never modified β it is not the vibe of this plugin to touch it, ever π
Configure database when you want a persistent primary: a successful UPDATE gets committed to the local database before its new snapshot becomes visible or before the success response is sent. meanwhile, with no database, updates live in memory only and are lost on restart or Corefile reload β so that mode is literally just for temporary data and testing. fyi. π
UPDATE requests must carry a TSIG that's been validated by the tsig plugin. and ngl, dynupdate does not receive or store TSIG secrets β not its business, not its problem. every single mutation also has to match an explicit allow rule containing the key name, owner name, and RR type. use * as the owner name or RR type only when you actually intend that broader permission, bestie, don't be out here handing out * because you're feeling generous π
Also configure require_opcode UPDATE in the tsig plugin so unsigned UPDATE requests get rejected right at the protocol boundary. clean. iconic. UPDATE requests for a different zone receive NOTAUTH β they do not fall through to query-only backends. but ordinary queries outside the dynamic zone still pass to the next plugin, so nobody else gets held hostage. π¦
The implementation supports RFC 2136 prerequisites, add and delete operations, CNAME and apex SOA/NS invariants, automatic SOA serial updates, and the current snapshot for AXFR. SOA serial zero is rejected because RFC 2136 recommends avoiding it for interoperability, and automatic increments skip zero after wraparound. love a plugin with standards β¨
DNSSEC records and related zone-integrity metadata are rejected too β that's SIG, KEY, NXT, DS, RRSIG, NSEC, DNSKEY, NSEC3, NSEC3PARAM, TALINK, CDS, CDNSKEY, TA, DLV, and ZONEMD β because the plugin cannot regenerate them after an update. IXFR and automatic DNSSEC re-signing are not supported. The plugin is experimental; it does not provide multi-primary replication or atomic transactions across zones.
β οΈ Do not expose the UPDATE service without network controls in addition to TSIG authentication. fr fr. TSIG alone is not the whole security plan. π
The cache plugin automatically bypasses dynamic zones, so their authoritative queries always read the current snapshot β even after negative or positive answers. other middleware, like header, still processes those requests and responses, and unrelated zones stay cacheable. external recursive caches can still hold onto old answers until their TTL expires though, so like, can't fix that for you π AXFR requests pass through transfer and its access controls. successful changes trigger best-effort NOTIFY, and bursts get coalesced down to one in-flight notification per zone instance. efficient queen. π
π PERSISTENCE π
database uses an embedded bbolt <https://github.com/etcd-io/bbolt> database β no etcd server, no container, none of that. its parent directory must exist and be writable by CoreDNS. use a local filesystem with working file locks and sync semantics, not a shared network filesystem, i'm begging π«Ά
The database is private to one zone and one CoreDNS process. overlapping instances in that process share transactions and snapshots during a Corefile reload, so prerequisites cannot race and an old instance cannot overwrite a newer generation. slay. π
Configuration validation does not create or modify the database. a missing database is initialized from file on the first query, transfer, or authenticated UPDATE after startup. this prevents a failed startup from preserving an obsolete seed. until that first access, the seed must remain available; creation errors return SERVFAIL rather than acknowledging an update. π
After that, the database β including the SOA serial β is authoritative; editing or removing the seed does not replace dynamic data. corrupt, incompatible, wrong-zone, or over-limit databases cause an error, not a fallback to the seed. a failed commit returns SERVFAIL without publishing the candidate snapshot or serial. and after an abrupt process exit, the database reopens at a committed transaction. π
Stop CoreDNS before copying the database for an offline backup or restoring it. never edit, replace, or delete a live database. to deliberately reset the zone: stop CoreDNS, back up and remove the database, then restart with the desired seed. if initial creation fails, remove the uninitialized database before retrying. do not lower limits below the existing zone's size when reloading. database files can retain reusable free pages after records are deleted β max_bytes limits live uncompressed DNS data, not on-disk file size. iykyk π§
π¦ SYNTAX π¦
dynupdate [ZONE] {
file DBFILE
database PATH
allow KEY NAME TYPE [TYPE...]
max_records COUNT
max_bytes BYTES
max_update_records COUNT
}
ZONEβ the single authoritative zone. if omitted, the server block must define exactly one zone. one. just one. πDBFILEβ the RFC 1035-style seed zone file. a relative path is resolved below the path configured by therootplugin. it's required, but it's read only when initializing a new database or when starting in memory-only mode. so like, required but lowkey shy πdatabaseβ optional.PATHis a local database file, also resolved relative toroot. the database is created with mode0600on systems that support Unix file permissions. π₯KEYβ the normalized TSIG key name configured in thetsigplugin.NAMEβ an exact owner name,@for the zone apex, or*for all names in the zone.TYPEβ one or more RR types,ANYto authorize deleting all RRsets at one owner name, or*for all supported update operations. a wildcard type must be the only type in the rule. no mixing, bestie, it's not that kind of party πmax_recordsβ defaults to10000records in the zone.max_bytesβ defaults to8388608bytes of uncompressed DNS record data.max_update_recordsβ defaults to1024records total in an UPDATE's Prerequisite and Update sections.
Limits must be positive integers. requests exceeding the configured limits are refused atomically with REFUSED; seed or stored data above the zone limits is rejected during startup. updates are serialized and rebuild the bounded zone snapshot, so this backend is intended for small dynamic zones β not high-volume bulk loading. know your lane π
At least one allow rule is required. the plugin owns the configured zone, so don't configure a second authoritative backend for the same zone unless its independent behavior is explicitly intended. π
β¨ EXAMPLES β¨
okay so this is where it gets real, bestie β examples time. π
For temporary ACME challenge records, you load a seed zone and permit one key to update TXT records at the challenge owner. This example uses memory-only mode.
π¨ Generate a private key for your deployment; the example secret is public. Do not ship that example secret, fr fr.
example.org {
tsig {
secret update-key.example.org. i9M+00yrECfVZG2qCjr4mPpaGim/Bq+IWMiNrLjUO4Y=
require_opcode UPDATE
}
dynupdate {
file example.org.zone
allow update-key.example.org. _acme-challenge.example.org. TXT
}
}
For a persistent zone, add database. A client that needs several record types at selected names can use separate narrow rules:
example.org {
tsig {
secret update-key.example.org. i9M+00yrECfVZG2qCjr4mPpaGim/Bq+IWMiNrLjUO4Y=
require_opcode UPDATE
}
dynupdate {
file example.org.zone
database example.org.db
allow update-key.example.org. host.example.org. A AAAA
allow update-key.example.org. _acme-challenge.example.org. TXT
}
}
A minimal seed file is:
$ORIGIN example.org.
@ 60 IN SOA ns.example.org. hostmaster.example.org. 1 3600 600 86400 60
@ 60 IN NS ns.example.org.
ns 60 IN A 192.0.2.53
With a BIND-format TSIG key file, nsupdate -k update.key can submit:
server 127.0.0.1 53
zone example.org.
prereq nxrrset host.example.org. A
update add host.example.org. 60 A 192.0.2.10
send
Use nsupdate -v -k update.key for TCP. Query host.example.org. A directly on this server to see the change. With database configured it remains after restart. For DHCP forward and reverse updates, configure each zone in its own server block with its own seed, database and least-privilege allow rules. The DHCP server remains responsible for lease expiry, record cleanup, and coordinating its forward and reverse requests.
π«Ά DHCP CLIENT PERMISSIONS π«Ά
The required permissions depend on the UPDATE messages sent by the DHCP implementation, not just the address records it creates. For example, Kea 2.0.2 D2 writes DHCID records in both the forward and reverse zones and uses an ANY deletion when releasing a name. Allowing only A/AAAA or PTR lets some steps succeed but refuses later steps. Forward and reverse updates are separate transactions: a rejected reverse update does not undo a successful forward update.
For a DHCP-managed host.example.org. at 192.0.2.10, the forward-zone rule can be:
allow update-key.example.org. host.example.org. A AAAA DHCID ANY
The corresponding rule in 2.0.192.in-addr.arpa. can be:
allow update-key.example.org. 10.2.0.192.in-addr.arpa. PTR DHCID ANY
πANYexplicitly permits deleting all RRsets at the authorized name; it does not mean only the other types listed in the rule. Do not place unrelated static records at those names. Use*for the name only when the DHCP updater is trusted to manage the entire zone. KeepDHCIDconflict resolution enabled on the DHCP side; a TSIG key identifies the updater, not the client that owns a lease.
π INTEROPERABILITY AND SIZING π
With BIND nsupdate and Kea kea-dhcp-ddns installed, run:
go test -race ./test -run '^TestDynUpdate' -count=3
go test ./plugin/dynupdate -run '^$' -bench '^BenchmarkUpdate$' -benchmem -count=3
The Kea test supplies synthetic lease-change notifications to a real D2 process and verifies IPv4 and IPv6 forward/reverse creation, renewal, ownership conflicts, removal, and name reuse. It is not a DHCP address allocation, lease-expiration, or physical-network test. Missing client binaries skip the corresponding local tests; Linux CI installs both. Distribution confinement may require approved paths for the Kea test process. COREDNS_KEA_CONFIG_DIR, KEA_PIDFILE_DIR, and KEA_LOCKFILE_DIR can select prepared writable directories. Linux CI uses this facility to keep Ubuntu's AppArmor policy enabled. Do not point a test at runtime directories used by a live Kea service.
The benchmark changes a record in 100-, 1000-, and 10000-record zones, with and without synchronous persistence and four concurrent query workers. ns/op measures one protocol-engine transaction, excluding transport and TSIG verification, while the query metrics report concurrent query latency and throughput. Allocations include the query workers when enabled. Measure on the filesystem and hardware used for deployment: updates rebuild the entire zone and queries can wait for the update and disk commit. The record limits bound accepted data, not update latency or peak process memory. This backend is intended for small, infrequently updated zones, not a high-throughput DHCP service.
πΈ SEE ALSO πΈ
See the file, transfer, and tsig plugins for authoritative data, AXFR/NOTIFY, and TSIG authentication configuration.
- RFC 2136 (
https://www.rfc-editor.org/info/rfc2136/) β defines DNS UPDATE. π¦ - RFC 1982 (
https://www.rfc-editor.org/info/rfc1982/) β defines DNS serial number arithmetic. π
okay that's the whole page, bestie π β it's from the CoreDNS manual, dated October 2026, and the page is COREDNS-DYNUPDATE(7). go touch some zones (carefully) β¨π
π¦ where this page comes from
- opensuse-leap 16.0: coredns-extras 1.15.0-bp160.1.1 Β· Apache-2.0 AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms