Zone transfers (AXFR)
dnswiz can serve AXFR (full zone transfers, RFC 5936) to your own secondary nameservers. Useful if you want to keep a self-hosted BIND or NSD secondary as a hot spare, ship the zone into an internal network, or hand the data to an audit tool.
dnswiz is always the primary; AXFR-out is the only transfer direction supported. AXFR-in (treating someone else as primary) isn’t in scope.
What we serve, and what we don’t
| Status | |
|---|---|
| AXFR (full transfer) | Supported, TCP-only |
| IXFR (incremental) | Not yet, IXFR queries fall back to AXFR |
| NOTIFY (RFC 1996) | Not yet, your secondaries poll on SOA refresh |
| TSIG (RFC 8945) | Optional, per zone, hmac-sha1/224/256/384/512 |
| Static record types | Transfer cleanly |
| Signed zones (DNSSEC enabled) | Refused. Today’s signing is online-per-answer; we don’t ship pre-signed RRsets. |
| Dynamic records (POOL, GEO, CANARY, ANAME) | Refused. Their answers vary per query; a zone file would be a lie. |
Enable on a zone
- Open the zone in the console.
- Zone settings → Zone transfers (AXFR) → Enable.
- Add the source CIDRs that are allowed to pull (your
secondary’s IP, or the range it speaks from). The allow-list is
strict: anything not on the list gets
REFUSEDbefore the query is parsed. - (Optional) Click Generate TSIG to mint a shared secret. The secret is shown once; copy it into your secondary’s config.
That’s it. From the secondary:
dig @ns1.dnswiz.app yourdomain. AXFR
# or with TSIG
dig @ns1.dnswiz.app -y hmac-sha256:transfer-key:BASE64SECRET yourdomain. AXFR
Why TCP-only
AXFR is always over TCP. UDP isn’t a legal transport for it (RFC 5936 §4.2). dnswiz answers AXFR queries on TCP/53 and rejects them on UDP/53, same as any other authoritative server.
TSIG
TSIG signs the AXFR request and response with a shared secret. It’s the standard way to authenticate transfers when source-IP isn’t sufficient (NATed secondaries, multi-tenant networks).
- Algorithm: hmac-sha256 by default. We accept hmac-sha1, sha224, sha384, sha512 if your secondary insists.
- Key name: auto-generated as
transfer-<short-id>; you can rename in the panel. - Secret: shown once at generation time. Save it to your secondary’s config; dnswiz only keeps it sealed at rest.
- Rotation: click Generate TSIG again. The new secret replaces the old one immediately, plan a short window where the secondary won’t pull until you update its config.
- Disable: click Clear TSIG. The zone then accepts transfers from any IP on the allow-list with no TSIG required.
Source CIDR allow-list
Strictest IP gate first, parsed before the DNS query is even decoded. Examples:
203.0.113.5/32 one specific secondary
198.51.100.0/24 a /24 range
2001:db8:1::/48 an IPv6 prefix
An empty allow-list means “refuse everyone,” not “allow everyone.” You always need at least one entry.
What a transfer looks like on the wire
A successful AXFR is:
- SOA (first record)
- Every other record in the zone, in whatever order dnswiz emits
- SOA again (last record, RFC 5936 §2.2 framing)
The SOA serial is dnswiz’s own (a Unix timestamp at the last zone change). Your secondary uses it to decide whether to re-pull.
Why we refuse on signed zones
When DNSSEC is enabled, dnswiz signs each RRset at query time with the active ZSK. A full AXFR would need every RRset signed in advance, which our online-signing model doesn’t produce. The trade-off is intentional: dynamic features and DNSSEC both work, but the cost is that signed zones aren’t transferable today. If you need a signed secondary, talk to us about scope.
Why we refuse on dynamic zones
If a zone has any POOL, GEO, CANARY, or ANAME record, the “zone file” doesn’t have a stable representation. POOL members come and go based on health; GEO answers vary by client country; CANARY answers vary by ramp time. Shipping a snapshot to a secondary would be a snapshot of one moment for one client view, which a secondary would then serve uniformly to every client. dnswiz refuses rather than mislead a secondary into serving lies.
If you really want a static secondary of a mostly-dynamic zone,
move the dynamic records into a separate zone (e.g.,
app.example.com for the dynamic stuff, example.com for the
static apex + delegations) and enable AXFR only on the static one.
Refused reasons you might see
| Reason | Meaning | Fix |
|---|---|---|
transfers-disabled | AXFR isn’t enabled on this zone. | Enable in the console. |
ip-not-allowed | Source IP isn’t on the allow-list. | Add the secondary’s CIDR. |
tsig-required | A TSIG key is configured; the query came in unsigned. | Sign the query with the key. |
tsig-bad-key | Query signed with a key name we don’t know. | Use the key name shown in the panel. |
tsig-bad-sig | Signature doesn’t verify (wrong secret or wrong algorithm). | Re-copy the secret; check the algorithm. |
zone-signed | The zone has DNSSEC enabled; AXFR is refused. | Disable DNSSEC, or talk to us. |
zone-dynamic | The zone has GSLB records; AXFR is refused. | See “dynamic zones” above. |
udp-not-allowed | AXFR was attempted over UDP. | Use TCP. |
All refusals also surface in Refused-query forensics within seconds, with source IP and reason.
Per-rule audit
Every change (enable, disable, allow-list edit, TSIG generation or clear) lands in Settings → Audit log with who did it and when.