Concepts¶
The DNS module models DNS data the same way it's modeled on the wire, with one twist around naming so that international domain names work cleanly with Drupal's URL and storage layers. This page walks through the key concepts site admins need to know to use the module effectively.
Zones and records¶
A zone is the unit of authority for a domain — for example
example.com. In this module, a zone is a content entity of type
dns_zone with a name, an owner, and a set of attached records.
A record is a content entity of type dns_record, scoped to a
zone, with a type (A, AAAA, …), a prefix (the subdomain part), a TTL,
and type-specific data (an IP address, a target hostname, etc.).
Every record belongs to exactly one zone via a required entity reference. Zones contain zero or more records. Deleting a zone is blocked while records exist — the delete form refuses with a count of remaining records and a link back to the zone. Remove the records first, then the zone. (Cascade deletion via an explicit "delete zone and all records" option may land in a later release.)
Zone names: name vs label¶
DNS zone names can contain non-ASCII characters (internationalized
domain names — IDN, e.g. münchen.de). On the wire, DNS itself only
carries ASCII, so IDN names are encoded with Punycode
(xn--mnchen-3ya.de). The module stores both forms and surfaces them
cleanly:
nameis the canonical lowercase Punycode form. It's the entity's primary key and what shows up in URLs (/dns/xn--mnchen-3ya.de), cache tags, and any place the on-wire form matters.labelis the Unicode display form. It's what every page title, link text, and Views column shows by default.
For pure-ASCII zones (example.com), name and label are equal and
the distinction doesn't show up in the UI.
When you create a zone, the module accepts either form as input —
type münchen.de or paste xn--mnchen-3ya.de, both produce the same
canonical pair. The wire form is read-only after first save: the
zone name is its identity, so renaming is conceptually
delete-and-recreate.
Records and the rdata model¶
Most record types share a small set of fields and differ only in one or two type-specific values. The module exploits this:
- A handful of "shared" base fields are real entity fields, queryable and indexable:
zone— entity reference to the parent zone.prefix— the subdomain part (e.g.www).record_type— A, AAAA, CNAME, MX, …ttl— time-to-live in seconds.ip_address— the IP for A/AAAA records (using thefield_ipaddressmodule's binary-storage field type).target— the target hostname for CNAME, MX, NS, SRV, PTR, DNAME records. Stored in BIND zone-file form (see below).- Type-specific data that doesn't fit a shared field — MX/SRV
priority, SRV weight/port, TXT content, CAA flags, etc. — lives in a
long-tail
rdataJSON field.
Whether a key earns promotion to a real shared field follows a
deliberate threshold: it has to be shared by at least two record types
and be operationally meaningful to query across types. ip_address
and target clear that bar; priority and weight don't.
For site admins this matters because:
- Standard Views columns / sorts / filters work for the shared fields.
- For rdata-stored values (e.g. MX priority), a custom Views field handler is provided that reads a single key out of the JSON and renders it as a column. See Customizing the records view.
Record types as plugins¶
Each record type (A, AAAA, CNAME, NS, MX, TXT, CAA, SRV, PTR, HTTPS,
SVCB in core; DNAME, SSHFP, TLSA, SMIMEA, OPENPGPKEY, DS, DNSKEY in
the optional dns_extras submodule) is a plugin. The plugin owns:
- which shared base fields it claims (A and AAAA claim
ip_address; CNAME claimstarget); - type-specific validation (e.g. an A record requires an IPv4 address, not just any IP; a CNAME target must be a valid hostname);
- duplicate-detection rules for that type;
- how to render the record's value in list contexts.
For site admins this is mostly transparent: in the record form, choose the type from the dropdown and the form re-renders with only the fields that type uses. For developers, see Writing a record type.
Target storage in BIND zone-file form¶
Targets (the target field on CNAME, MX, NS, PTR, SRV, HTTPS, SVCB
in core — and DNAME in the dns_extras submodule) follow
RFC 1035 §5.1 BIND
zone-file conventions and are stored in that exact form:
- A name without a trailing dot —
www,mail.example.com— is relative to the zone's origin.wwwin zoneexample.comresolves towww.example.com.. - A name ending in
.—www.example.com.— is an absolute fully-qualified name. The trailing dot is preserved in storage. - The literal
@denotes the zone apex itself.
Storage preserves the user's choice rather than canonicalizing to
FQDN, which keeps zone-file export a direct write of the field with
no per-record context. The record form shows a live preview of the
resolved name so you can see exactly what www or @ will mean
inside your zone.
Cross-type rules¶
Some DNS rules apply across record types and are enforced at the entity level rather than within any single plugin. The current set:
- CNAME exclusivity (RFC 2181 §10.1) — a name with a CNAME cannot have any other record. Adding a CNAME at a name where other records already exist is rejected, and adding any non-CNAME record at a name with an existing CNAME is rejected.
Ownership and access¶
Zones have a uid (owner) with separate administer / create
/ view-any / view-own / edit-own / delete-own
permissions. Records inherit their access from the parent zone — if
you can update the zone, you can manage its records. There are no
per-record permissions. See Permissions.
Per-zone delegation is shipped: each zone has a Collaborators tab
on its canonical page where the owner (or an admin) can grant a
specific capability set to another Drupal user. Capabilities are
fine-grained (view records, edit records, etc. — see the
permissions page for the full vocabulary). Owner
implies all capabilities automatically; admins bypass the system.
Provider integrations layer on top via the dns_zone access-policy
scope when they ship.
URL structure¶
Frontend (entity canonicals):
| Path | What |
|---|---|
/dns/{zone} |
View a zone |
/dns/{zone}/edit, /delete |
Edit / delete the zone |
/dns/zones/add |
Add a zone |
/dns/{zone}/records/{record_id} |
View a record |
/dns/{zone}/records/{record_id}/edit |
Edit a record |
/dns/{zone}/records/{record_id}/delete |
Delete a record |
/dns/{zone}/records/add |
Add a record (zone pre-bound) |
/dns/records/add |
Add a record (no zone pre-bound) |
Admin overview:
| Path | What |
|---|---|
/admin/content/dns |
DNS landing |
/admin/content/dns/zones |
Zone collection |
/admin/content/dns/records |
Records view (Views-backed) |
/admin/config/content/dns |
Module-wide settings |