From c3c953e2bb3b6cebbcbfcbb3f59678b72f9d975f Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Tue, 25 Aug 2026 20:57:22 -0500 Subject: [PATCH 1/2] docs: document the datumctl dns plugin and Datum's DNS model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Datum hosts authoritative DNS, but the documentation stopped at a feature list and a glossary. Nothing explained how a domain becomes a working zone, and the `datumctl dns` plugin — which is how most people will drive it — was not documented at all. The datumctl section gains a task-oriented guide for the plugin: install it, create a zone, point the registrar at Datum's nameservers, add and change records, import an existing zone file, export, and script against the output. The Domains & DNS section becomes real product documentation. Domain ownership verification gets its own page, because it is the gate that decides whether a zone is provisioned at all and it was previously undocumented. Zones, records, ALIAS, and migrating a zone in or out each get a page, and the overview explains how a domain and a zone relate. One correction outside the section: the ALB DNS setup page attributed a zone stuck at PROGRAMMED=False to missing delegation and told readers to change their nameservers. Delegation happens at the registrar and has no bearing on whether Datum provisions a zone; the usual cause is an unverified domain. That row now names the real cause and links to the verification page. Every command, flag, and status word is taken from the released plugin's own help output or from the operator's source. Behaviour that is not yet released is deliberately absent. --- alb/dns-setup.mdx | 6 +- datumctl/plugins/dns.mdx | 457 +++++++++++++++++++++++++++++ docs.json | 8 +- domain-dns/alias-records.mdx | 56 ++++ domain-dns/dns-records.mdx | 137 +++++++++ domain-dns/dns-zones.mdx | 137 +++++++++ domain-dns/dns.mdx | 144 +++++---- domain-dns/domain-verification.mdx | 107 +++++++ domain-dns/domains.mdx | 14 +- domain-dns/migrate-dns.mdx | 96 ++++++ 10 files changed, 1106 insertions(+), 56 deletions(-) create mode 100644 datumctl/plugins/dns.mdx create mode 100644 domain-dns/alias-records.mdx create mode 100644 domain-dns/dns-records.mdx create mode 100644 domain-dns/dns-zones.mdx create mode 100644 domain-dns/domain-verification.mdx create mode 100644 domain-dns/migrate-dns.mdx diff --git a/alb/dns-setup.mdx b/alb/dns-setup.mdx index ae4208e..4d25c30 100644 --- a/alb/dns-setup.mdx +++ b/alb/dns-setup.mdx @@ -9,6 +9,10 @@ This guide prepares a domain for use with a Datum Application Load Balancer by c This guide assumes your domain is already delegated to Datum nameservers. See [DNS](/domain-dns/dns) for nameserver details and ALIAS record behavior. + +Datum does not provision a zone until you have verified that you own the domain. If the zone below stays unprogrammed, verification is the first thing to check — see [Verify domain ownership](/domain-dns/domain-verification). + + --- ## Prerequisites @@ -263,7 +267,7 @@ datumctl delete dnszone $ZONE \ | Symptom | Root Cause | Resolution | |---------|------------|------------| -| Zone stuck at `PROGRAMMED=False` | Domain not delegated to Datum nameservers | Update nameservers at your registrar | +| Zone stuck at `PROGRAMMED=False` | Most often the domain has not been verified, which also shows the zone as `Rejected`. Delegation is unrelated — a zone programmes whether or not the registrar points at Datum. | Verify domain ownership, then wait for the zone to programme. See [Verify domain ownership](/domain-dns/domain-verification). | | `nslookup` / `dig` returns NXDOMAIN | Zone not yet propagated | Wait 1–2 minutes and retry | | ALIAS resolves to wrong address | `TARGET` missing trailing dot | Re-apply the record with a trailing dot on the target | | Record not appearing | `--validate=false` omitted | Re-apply with `--validate=false` | diff --git a/datumctl/plugins/dns.mdx b/datumctl/plugins/dns.mdx new file mode 100644 index 0000000..b5bbdf2 --- /dev/null +++ b/datumctl/plugins/dns.mdx @@ -0,0 +1,457 @@ +--- +title: "DNS plugin" +sidebarTitle: "DNS plugin" +description: "Install the datumctl dns plugin and manage Datum Cloud DNS zones and records from your terminal." +--- + +The `dns` plugin extends `datumctl` with commands for creating DNS zones, pointing your domain at Datum, and editing records — all from the terminal. Once you install it, `datumctl dns` behaves like any other `datumctl` command and inherits your current organization, project, and credentials. + + + The plugin is a preview release. The current published version is `v0.7.0-dev.1`, so expect commands, flags, and output to change before a stable release. + + +For DNS concepts — zones, nameservers, record types, and ALIAS/CNAME flattening — see [DNS](/domain-dns/dns). For how plugins are installed, verified, and upgraded in general, see [Using plugins](/datumctl/plugins/using-plugins). + +## Install the plugin + + + + The plugin ships in the official **datum** catalog, so no extra catalog registration is needed: + + ```bash + datumctl plugin install dns + ``` + + This installs the version the catalog recommends. To pin a specific one instead, see [pinning a version](/datumctl/plugins/using-plugins#pinning-a-version). + + + + ```bash + datumctl dns version + ``` + + `version` runs entirely offline — no credentials, no project, and no API call — so it is the first command to run whenever something else fails. + + + + Every other command acts on a project. Set a context once, or pass `--project` per command: + + ```bash + datumctl ctx use / + ``` + + The plugin never guesses a project. See [Contexts & scoping](/datumctl/contexts-and-scoping) for how scope is resolved. + + + +Upgrade and remove the plugin with the usual commands: + +```bash +datumctl plugin upgrade dns +datumctl plugin remove dns +``` + + + If you build the plugin yourself and put a `datumctl-dns` binary on your `PATH`, `datumctl` blocks it until you run `datumctl plugin trust dns`. Trust is recorded against the binary's fingerprint, so rebuilding it means trusting it again. + + +## Create a zone + +A zone holds the records for one domain. Create one by domain name: + +```bash +datumctl dns zone create example.com +``` + +The command waits up to two minutes for Datum to assign nameservers, then prints them — a zone is not usable until it has them, and you cannot delegate the domain without knowing what they are. Change that with `--timeout`, or skip the wait entirely: + +```bash +# Return as soon as the zone exists +datumctl dns zone create example.com --no-wait + +# Attach a description +datumctl dns zone create example.com --description "production apex" + +# Validate against the API server without creating anything +datumctl dns zone create example.com --dry-run +``` + + + A zone's domain name is immutable. There is no `zone update`, and moving to a different domain means creating a new zone. + + +## Point your domain at Datum + +Creating a zone does not make the domain resolve through Datum. Your registrar has to publish the nameservers Datum assigned to the zone. + +```bash +datumctl dns zone nameservers example.com +``` + +```text +Nameservers for example.com + ns1.datumdomains.net. not set at registrar + ns2.datumdomains.net. not set at registrar + ns3.datumdomains.net. not set at registrar + ns4.datumdomains.net. not set at registrar + +Delegation Incomplete — 0 of 4 nameservers set at the registrar + +Set these nameservers at your domain registrar: + ns1.datumdomains.net. + ns2.datumdomains.net. + ns3.datumdomains.net. + ns4.datumdomains.net. + +Re-check with: datumctl dns zone nameservers example.com --check +``` + +Copy the printed nameservers into your registrar's control panel, then re-check: + +```bash +datumctl dns zone nameservers example.com --check +``` + +Without `--check`, the command compares against what the control plane last reconciled. `--check` queries public DNS live, as a second and independent source of truth: it observes what the internet resolves right now rather than trusting stored state, which is what tells you whether delegation actually works. Use `--timeout` to change the per-query timeout. + +The command reports delegation as one of four states: + +| Delegation state | Meaning | +| --- | --- | +| `Complete` | Your registrar publishes every assigned nameserver. | +| `Partial` | Your registrar publishes some of them — usually a half-finished edit. | +| `Incomplete` | Your registrar publishes none of them. | +| `Unknown` | There is nothing to compare against yet. | + +`Unknown` is not a failure, and the summary line says which of its three causes applies: + +- `no nameservers assigned yet` — the zone does not have its nameservers yet. This is normal for the first few minutes after you create a zone. +- `the registrar's nameservers have not been checked yet` — the zone has a linked domain, but nobody has looked at what the registrar publishes. +- `no linked domain to check the registrar against` — there is no domain object to compare against at all. + +None of the three is evidence about your registrar, so none of them means your delegation is wrong. For the same reason, individual nameservers are annotated `unknown` rather than `not set at registrar` while the state is `Unknown`. + +Registrar changes take time to propagate. Allow for the parent zone's TTL before you treat a change as failed. + +## List and inspect zones + +```bash +# Every zone in the project — `datumctl dns zone` alone does the same +datumctl dns zone list + +# Only the ones that are not working yet +datumctl dns zone list --status error + +# Raw API objects +datumctl dns zone list -o json +``` + +```text +NAME STATUS RECORDS NAMESERVERS DELEGATED AGE +example.com OK 12 ns1.datumdomains.net., ns2.datumdomains.net., ns3.datumdomains.net., ns4.datumdomains.net. yes 14d +old.acme.io OK 8 ns1.datumdomains.net., ns2.datumdomains.net., ns3.datumdomains.net., ns4.datumdomains.net. no 21d +staging.acme.io Pending 2 — unknown 3m + +3 zones — 2 OK, 1 Pending, 0 Rejected, 0 Error +``` + +Filter with `--status ok|pending|error`, add `-o wide` for extra columns, and pass `--no-headers` to drop the header row. + +For one zone in detail — its status, its delegation, and what it contains — use `describe`: + +```bash +datumctl dns zone describe example.com +datumctl dns zone describe example.com -o yaml +``` + +## Delete a zone + + + Deleting a zone deletes every record in it, and the domain stops resolving through Datum. The operator owns each record set through a controller `ownerReference`, so they are garbage-collected with the zone. + + +The confirmation asks for the zone name typed in full, and the command refuses to run non-interactively without `--yes`: + +```bash +datumctl dns zone delete example.com + +# In a script +datumctl dns zone delete example.com --yes + +# Validate the deletion without performing it +datumctl dns zone delete example.com --dry-run +``` + +## Add and change records + +Give the zone, the name, the type, and one or more values. Names are relative to the zone: `www`, `*`, `_dmarc`, or `@` for the domain itself. + +`create` appends — the values already at that name stay, and an exact duplicate is refused: + +```bash +datumctl dns record create example.com www A 203.0.113.10 +datumctl dns record create example.com www A 203.0.113.11 --ttl 5m +``` + +`set` overwrites — every value already at that name and type is removed and the ones you give take their place: + +```bash +datumctl dns record set example.com www A 203.0.113.20 + +# Two values at once +datumctl dns record set example.com www A 203.0.113.20 203.0.113.21 +``` + +`set` is the "change my A record" verb and `create` is the "add a second A record" verb. They are separate because one command cannot express both intents safely. + +Both accept `--dry-run` to validate and show the change without applying it, and `--wait` to block until the DNS backend has programmed the record (`--timeout` bounds the wait). + +Two rules catch most mistakes: + +- **Names are relative.** Use `www`, not `www.example.com`. Use `@` for the domain itself. +- **Targets are absolute.** End every hostname inside a value with a dot: `mail.example.com.`, not `mail`. + +## Enter record values + +Flat types take their value positionally. Repeat the argument for several values: + +```bash +datumctl dns record create example.com www A 203.0.113.10 203.0.113.11 +datumctl dns record set example.com @ TXT "v=spf1 include:_spf.example.com ~all" +datumctl dns record create example.com cdn CNAME lb.example.net. +``` + +Structured types are taught with named flags: + +```bash +datumctl dns record create example.com @ MX --preference 10 --exchange mail.example.com. +datumctl dns record create example.com _sip._tcp SRV --priority 10 --weight 5 --port 5060 --target sip.example.com. +datumctl dns record create example.com @ CAA --flag 0 --tag issue --value letsencrypt.org +datumctl dns record create example.com api HTTPS --priority 1 --target . --param alpn=h3,h2 +``` + +| Type | Positional value | Named flags | +| --- | --- | --- | +| `A`, `AAAA` | `` | — | +| `CNAME`, `ALIAS`, `NS`, `PTR` | `` | — | +| `TXT` | `` | `--data` | +| `MX` | ` ` | `--preference`, `--exchange` | +| `SRV` | ` ` | `--priority`, `--weight`, `--port`, `--target` | +| `CAA` | ` ` | `--flag`, `--tag`, `--value` | +| `TLSA` | ` ` | `--usage`, `--selector`, `--matching-type`, `--cert-data` | +| `HTTPS`, `SVCB` | ` [k=v ...]` | `--priority`, `--target`, `--param k=v` | +| `SOA` | ` `, or ` ` alone to accept the backend defaults | `--mname`, `--rname`, `--serial`, `--refresh`, `--retry`, `--expire`, `--minimum` | + +Both notations work for every type, so a value pasted out of a provider export or `dig` output needs no translation. Mixing the two notations for one value is an error, not a merge. + +```bash +datumctl dns record create example.com _sip._tcp SRV "10 5 5060 sipserver.example.com." +datumctl dns record create example.com --line "www 300 IN A 203.0.113.10" +``` + +For long TXT values that will not survive shell quoting, `--data` reads a file with `@path` or standard input with `-`: + +```bash +datumctl dns record create example.com selector1._domainkey TXT --data @dkim.txt +dig +short TXT _dmarc.example.com | datumctl dns record set example.com _dmarc TXT --data - +``` + + + Datum manages a few records for you — the zone's SOA, its apex NS records, and anything a Gateway creates. Editing or deleting one requires `--force`, and a platform-managed record you overwrite reverts. + + +## Set a TTL + +`--ttl` takes seconds or a duration, and the units combine: `--ttl 300`, `--ttl 5m`, `--ttl 1h30m`. Omit it and the record uses `Auto`, which the backend resolves to 300 seconds. TTLs are stored as written and are not rounded onto a preset ladder. + +## List and inspect records + +Records are listed one row per value, with the name, type, TTL, value, and status: + +```bash +# Everything in the zone +datumctl dns record list example.com + +# Only the mail records +datumctl dns record list example.com --type MX,TXT + +# Only one name +datumctl dns record list example.com --name www + +# Only what is not working +datumctl dns record list example.com --status conflict + +# Only what the platform manages +datumctl dns record list example.com --managed +``` + +`--status` accepts `programmed`, `pending`, `conflict`, `not-owner`, `error`, and `rejected`; the first word alone also works, so `not` selects `Not owner`. `STATUS` is the per-owner-name condition, not the rolled-up one on the record set — the interesting outcomes only exist per name. + +`describe` shows the values at one name both in presentation format and broken out into named fields, along with the backend's own status message. Omit the type to see every type at that name: + +```bash +datumctl dns record describe example.com www +datumctl dns record describe example.com @ MX +``` + + + A semicolon starts a comment in zone-file syntax, so TXT values containing one display escaped — `v=DMARC1; p=none` reads back as `"v=DMARC1\; p=none"`. The stored value is unchanged. + + +## Delete a record + +Pass a value to remove only that value, or leave it off to remove every value at that name and type. The prompt says how many, so the difference is never a surprise. + +```bash +# One value +datumctl dns record delete example.com www A 203.0.113.11 + +# Every A record at that name +datumctl dns record delete example.com www A + +# No prompt, for scripts +datumctl dns record delete example.com www A --yes + +# Show what would be deleted without deleting it +datumctl dns record delete example.com www A --dry-run +``` + +When the last value of a type leaves a zone, the record set holding it is deleted rather than left empty. + +## Import an existing zone + +Moving a domain in from another provider starts with the zone file you exported there: + +```bash +# Load a zone file exported from another provider +datumctl dns zone import example.com --file example.com.zone + +# Read from standard input +cat example.com.zone | datumctl dns zone import example.com --file - + +# Replace each type present in the file rather than merging into it +datumctl dns zone import example.com --file example.com.zone --replace + +# Check the import without writing anything +datumctl dns zone import example.com --file example.com.zone --dry-run +``` + +If you do not have a zone file, snapshot what the domain resolves to today and import that: + +```bash +datumctl dns zone import example.com --discover +``` + +Import groups records by type before writing, so each record type costs one API call however many records it holds. TTLs are taken from the file exactly as written. Use `--timeout` to bound how long `--discover` waits. + +## Export and apply a zone file + +`zone export` flattens every record set in the zone back into a BIND zone file: + +```bash +# Print the zone to the terminal +datumctl dns zone export example.com + +# Save it to a file +datumctl dns zone export example.com --file example.com.zone +``` + +`record apply` is the declarative counterpart: it diffs a zone file against the live zone, prints what would change, and converges. Export, edit, and apply is a closed loop — exporting and re-applying an untouched file reports no changes, which makes `apply --dry-run` usable as a drift check. + +```bash +# See the diff without touching anything +datumctl dns record apply example.com -f example.com.zone --dry-run + +# Show and apply the difference +datumctl dns record apply example.com -f example.com.zone + +# Make the zone exactly match the file +datumctl dns record apply example.com -f example.com.zone --prune +``` + +By default `apply` only adds and updates. `--prune` also deletes the records the file does not mention. Platform-managed records are never pruned or modified, and what was skipped is always reported. There is no `--force` on `apply` — a zone file is not the place to say "yes, delete my delegation", so use `record delete --force` where the record is named explicitly. + + + With `--prune`, the diff is computed from the zone as it was read. If another writer changes the zone while the command runs, the retry converges against the newer state and may delete a record the diff did not show. The dry run is a good description of the change, not an upper bound on it. + + +## Script the plugin + +Every command accepts `-o`: + +| Format | Use it for | +| --- | --- | +| `table` | The default, for reading at a terminal. | +| `wide` | The table plus extra columns. | +| `json`, `yaml` | Full API objects, for scripts. | +| `name` | Bare identifiers, one per line, for pipelines. | + +```bash +datumctl dns zone list -o name | xargs -n1 datumctl dns zone describe +datumctl dns zone list -o json | jq -r '.items[].spec.domainName' +datumctl dns record list example.com -o name +``` + +`record list -o json` and `-o yaml` emit the raw record set objects rather than the flattened rows, so a script never has to reconstruct them. `--no-headers` drops the header row from `table` and `wide`. Data goes to standard output and everything else to standard error, so `-o json > zones.json` is always clean. + + + The table view is a presentation and its columns can change. Script against `-o json` or `-o name`. + + +Useful global flags: `--project`, `--org`, `-o`/`--output`, `-v`/`--verbose`, `-q`/`--quiet`, `-y`/`--yes`, and `--color auto|always|never`. For the wider scripting picture, see [Output formats & scripting](/datumctl/output-and-scripting). + +### Exit codes + +A bulk operation that partly fails never exits `0`. + +| Code | Name | Meaning | +| --- | --- | --- | +| 0 | — | Success | +| 1 | `DNS_ERROR` | Unexpected failure | +| 2 | `DNS_USAGE` | Bad flags, arguments, or record values | +| 3 | `DNS_FORBIDDEN` | Not authorized, or DNS is not enabled for the project | +| 4 | `DNS_NOT_FOUND` | Zone or record not found | +| 5 | `DNS_CONFLICT` | Something else already owns that name | +| 6 | `DNS_INVALID` | The server rejected the request | +| 8 | `DNS_UNAVAILABLE` | Cannot reach the DNS API | +| 9 | `DNS_ABORTED` | You declined a confirmation | + +Errors print a problem, an optional fix, and the exit status: + +```text +Error: zone "nope.example" not found in project acme-prod +Fix: list the zones in this project: + datumctl dns zone list +exit status 4 # DNS_NOT_FOUND +``` + +Add `--verbose` to see the underlying cause. + +## Troubleshoot + +| Problem | What to do | +| --- | --- | +| No project set | Run `datumctl ctx use /`, or pass `--project `. The plugin never guesses a project. | +| DNS is not enabled for the project | Run `datumctl services enable dns.networking.miloapis.com --wait`. Enabling a service can require approval by the service provider, so this is not always immediate. | +| The domain does not resolve | Run `datumctl dns zone nameservers --check`. If delegation is `Incomplete` or `Partial`, fix it at your registrar. | +| A record is stuck at `Pending` | This is normal right after a write. If it lasts, run `datumctl dns record describe ` for the server's message. | +| `Conflict` | Another record occupies that name. Usually the name is not inside the zone — check for `www.example.com` where `www` was meant. | +| `Not owner` | Another record set owns that name, and `describe` names it. Edit the record through that set, or delete the set first. | +| The plugin will not run | Run `datumctl dns version`, which needs no credentials or network. If that works, the problem is authentication, context, or the API. | + +## Next steps + + + + Zones, nameservers, record types, and ALIAS/CNAME flattening explained. + + + How plugins are installed, verified, upgraded, and trusted. + + + Control which organization and project the plugin acts on. + + + Machine-readable output, structured errors, and CI patterns. + + diff --git a/docs.json b/docs.json index 5b6d141..a35e4c4 100644 --- a/docs.json +++ b/docs.json @@ -107,8 +107,13 @@ { "group": "Domains & DNS", "pages": [ + "domain-dns/dns", "domain-dns/domains", - "domain-dns/dns" + "domain-dns/domain-verification", + "domain-dns/dns-zones", + "domain-dns/dns-records", + "domain-dns/alias-records", + "domain-dns/migrate-dns" ] }, { @@ -178,6 +183,7 @@ "group": "Plugins", "pages": [ "datumctl/plugins/using-plugins", + "datumctl/plugins/dns", "datumctl/plugins/adding-catalogs", "datumctl/plugins/publishing-catalogs", "datumctl/plugins/building-plugins" diff --git a/domain-dns/alias-records.mdx b/domain-dns/alias-records.mdx new file mode 100644 index 0000000..a876ec2 --- /dev/null +++ b/domain-dns/alias-records.mdx @@ -0,0 +1,56 @@ +--- +title: "ALIAS records" +description: "Point a hostname — including the zone apex — at another hostname while still returning A and AAAA answers. Other providers call this CNAME flattening." +--- + +An **ALIAS** record points a name at another hostname the way a CNAME does, but returns **A and AAAA answers** to clients instead of a CNAME. That makes it usable at the **zone apex**, where standard DNS forbids a CNAME. + +Different providers use different names for the same idea: + +- **Cloudflare** usually calls it **CNAME flattening**. +- Other providers call it **ALIAS**, **ANAME**, or a **flattened CNAME**. + +## When to use an ALIAS record + +Use ALIAS when you want "point this name at that hostname" behavior but you can't or shouldn't use a CNAME. Most commonly: + +- At the **zone apex** (`example.com`), where standard DNS rules don't allow a CNAME. +- When you're targeting a hostname whose addresses change — a CDN or a hosted service — but clients need to receive A and AAAA records. + +A Datum Application Load Balancer endpoint is a typical target. See [DNS setup for an Application Load Balancer](/alb/dns-setup). + +## Name and value + +**Name** — the hostname inside the zone you're creating the record for. + +- For the zone apex, use `@`, the zone-file notation for the zone root. +- For a subdomain, use the label: `www` for `www.example.com`. + +**Value** — a target hostname, such as `myapp.hosting-provider.com.` + +- ALIAS values are hostnames, not IP addresses. +- The target must ultimately resolve to A or AAAA records, directly or through further DNS indirection. +- End the target with a dot. Without one it's treated as relative to your zone. See [Write values](/domain-dns/dns-records#write-values). + +## How it works + +ALIAS isn't a standardized DNS record type that recursive resolvers understand. The authoritative nameserver does the work instead: + +1. A client's resolver asks for `A` or `AAAA` for the ALIAS name, for example `example.com`. +2. Datum resolves the ALIAS target — `myapp.hosting-provider.com` — to its current `A` and `AAAA` records. +3. Datum returns those answers as if they'd been configured directly on the ALIAS name. + +The consequence worth remembering: clients don't see a CNAME in the response. They see A and AAAA records for the name they asked about. + +## ALIAS compared with CNAME + +| | CNAME | ALIAS | +|---|---|---| +| What the client receives | A CNAME, which the resolver then chases | A and AAAA records, synthesized by Datum | +| Allowed at the apex | No | Yes | +| Portable to other providers | Yes, it's a standard type | Not directly — every provider spells it differently | + +## Limitations + +- **Portability.** ALIAS and flattening behavior isn't uniform across providers. If you move DNS elsewhere, you'll need to translate the record into whatever that provider supports — and a BIND zone file can't carry it, because `ALIAS` isn't a standard type. See [Migrate a zone](/domain-dns/migrate-dns). +- **Answer types.** ALIAS synthesizes A and AAAA answers. It isn't a general replacement for other record types, and it doesn't carry the target's MX, TXT, or other records over to your name. diff --git a/domain-dns/dns-records.mdx b/domain-dns/dns-records.mdx new file mode 100644 index 0000000..0266e6e --- /dev/null +++ b/domain-dns/dns-records.mdx @@ -0,0 +1,137 @@ +--- +title: "DNS records" +description: "Supported record types, how to write names and values, TTLs, and what each record status means." +--- + +Records are the contents of a zone: the entries that turn a name into an address, a mail route, or a piece of text. You can manage them from the Datum Cloud portal, from `datumctl`, or through the API. + +## Record sets + +Datum groups records the way DNS does. Every record with the same name and the same type forms one **record set**, and all of its values share a TTL. + +``` +www A 300 203.0.113.10 +www A 300 203.0.113.11 +``` + +That's one record set — `www`, type `A` — with two values. Adding a second address adds a value to the existing set rather than creating a competing record, and resolvers return both. + +## Supported record types + +| Type | What it does | Value | +|---|---|---| +| `A` | Points a name at an IPv4 address | `203.0.113.10` | +| `AAAA` | Points a name at an IPv6 address | `2001:db8::1` | +| `CNAME` | Makes a name an alias for another hostname | A hostname | +| `ALIAS` | Apex-safe alias: points at a hostname but answers with addresses. See [ALIAS records](/domain-dns/alias-records) | A hostname | +| `MX` | Routes mail for the domain | A preference number and a mail exchange hostname | +| `TXT` | Holds free text — SPF, DKIM, DMARC, and service verification tokens | A text string | +| `NS` | Delegates a subdomain to other nameservers | A nameserver hostname | +| `SRV` | Advertises the host and port for a service | Priority, weight, port, and target | +| `CAA` | States which certificate authorities may issue for the domain | A flag, a tag, and a value | +| `TLSA` | Binds a certificate or key to a name for DANE | Usage, selector, matching type, and certificate data | +| `HTTPS` | Advertises connection parameters for HTTPS clients, such as HTTP/3 support | Priority, target, and parameters | +| `SVCB` | The general form of `HTTPS`, for other protocols | Priority, target, and parameters | +| `PTR` | Maps an address back to a name | A hostname | +| `SOA` | The zone's authority record. Datum manages this one | Managed for you | + +The apex NS records and the SOA record are written by Datum. See [Records Datum manages for you](/domain-dns/dns-zones#records-datum-manages-for-you). + +## Write names + +Record names are relative to the zone. In a zone for `example.com`: + +| You want | You write | +|---|---| +| `www.example.com` | `www` | +| `example.com` itself | `@` | +| `api.staging.example.com` | `api.staging` | +| Anything not otherwise matched | `*` | +| `_dmarc.example.com` | `_dmarc` | + +The most common mistake is writing the full name. `www.example.com` inside a zone for `example.com` creates a record for `www.example.com.example.com`. + +Underscore labels like `_dmarc`, `_acme-challenge`, and DKIM selectors are ordinary names — write them as they appear in the instructions you were given, minus the zone. + +## Write values + +Values that name another host must be **absolute**: end them with a dot. + +``` +mail.example.com. correct +mail.example.com ambiguous +mail wrong +``` + +A missing trailing dot makes the value relative to the zone, so `mail.example.com` becomes `mail.example.com.example.com` and resolution fails. This applies to CNAME, ALIAS, NS, MX exchanges, SRV targets, and PTR values. + +Two rules cover almost every mistake: + +- **Names are relative.** `www`, not `www.example.com`. +- **Targets are absolute.** `mail.example.com.`, with the dot. + +## Set TTLs + +The TTL is how long resolvers may cache an answer. Every record set has one. + +Leave it unset and the record uses `Auto`, which resolves to five minutes — short enough that mistakes are cheap to fix, long enough to be efficient for most sites. + +Set it explicitly when you have a reason: + +- **Before a planned change**, lower the TTL well in advance so the old answer expires quickly when you make the cut. +- **After things settle**, raise it for records that rarely change. + +Datum doesn't round TTLs to preset options. A TTL of 240 seconds stays 240 seconds. + +## Rules DNS itself imposes + +A few limits come from DNS, not from Datum, and every provider enforces them: + +- **A CNAME can't share a name with other records.** If `www` is a CNAME, it can't also have an A record or a TXT record. +- **The apex can't be a CNAME.** The apex already has SOA and NS records, so a CNAME there is illegal. Use an [ALIAS record](/domain-dns/alias-records) instead. +- **Only one SOA per zone**, and Datum owns it. + +## Record status + +Each record set reports a status. + +| Status | What it means | +|---|---| +| Programmed | The record is live on Datum's nameservers. | +| Pending | The write is in flight. This is normal for a few moments after any change. | +| Conflict | Something else already occupies that name. Most often the name accidentally includes the zone — check for `www.example.com` where `www` was meant. | +| Not owner | Another record set already owns that name and type. Change the record through whatever owns it, or remove that owner first. | +| Error | Datum couldn't program the record. The record's detail view carries the message. | +| Rejected | The value was refused as invalid for its type. | + +A record stuck at Pending for more than a moment is worth inspecting; the detail view for the record carries the underlying message. + + +Programmed means Datum is serving the record. It doesn't mean the world can see it — that also needs the domain [delegated](/domain-dns/dns-zones#delegation) to Datum, and it needs any previously cached answer to expire. + + +## Managing records from the terminal + +The [`datumctl` DNS plugin](/datumctl/plugins/dns#add-and-change-records) covers records in full, including entering multi-part values, bulk-applying a zone file, and filtering by status: + +```sh +datumctl dns record create example.com www A 203.0.113.10 +datumctl dns record list example.com +``` + +## Related + + + + Point the apex at a hostname and still answer with addresses. + + + Zone status, delegation, and managed records. + + + Import records in bulk from another provider. + + + A worked example with an apex ALIAS and a subdomain CNAME. + + diff --git a/domain-dns/dns-zones.mdx b/domain-dns/dns-zones.mdx new file mode 100644 index 0000000..c0a3e64 --- /dev/null +++ b/domain-dns/dns-zones.mdx @@ -0,0 +1,137 @@ +--- +title: "DNS zones" +description: "Create a DNS zone, understand what its status means, delegate it at your registrar, and learn which records Datum manages for you." +--- + +A DNS zone is Datum's hosting for one domain name. It holds the records Datum serves for that name and the nameservers that serve them. + +## What a zone covers + +A zone covers one name and everything below it that isn't delegated somewhere else. A zone for `example.com` serves `www.example.com`, `api.example.com`, and `a.b.c.example.com` — you add those as records inside the zone rather than as separate zones. + +You'd create a separate zone for a subdomain only when you want that subdomain managed independently, for example when `staging.example.com` is delegated to Datum while the apex stays at another provider. A subdomain zone is verified and delegated on its own. + +A domain name can be hosted by only one zone at a time. If you create a second zone for a name that's already hosted, it reports that the domain is already claimed and never provisions. + + +A zone's domain name is fixed when you create it. There's no rename — to host a different name, create a new zone. + + +## Create a zone + +Create a zone from the Datum Cloud portal, or from your terminal with the [`datumctl` DNS plugin](/datumctl/plugins/dns#create-a-zone): + +```sh +datumctl dns zone create example.com +``` + +Creating a zone starts a sequence you mostly watch rather than drive: + +1. Datum records the zone and, if the domain isn't tracked in the project yet, adds it. +2. Nothing else happens until the domain is verified. See [Verify domain ownership](/domain-dns/domain-verification). +3. Once verified, Datum provisions the zone and assigns its nameservers. +4. Datum creates the zone's SOA record and apex NS records. +5. The zone starts serving. It's not yet reachable from the internet — that needs delegation. + +## Zone status + +A zone reports one status. It describes the zone on Datum's side only; whether the internet actually asks Datum for this domain is a separate question, answered by [delegation](#delegation). + +| Status | What it means | What to do | +|---|---|---| +| Rejected | Datum won't provision the zone yet. Despite the word, this is usually not a refusal — the ordinary cause is that the domain hasn't been verified. | Read the message next to the status. See [Rejected doesn't mean refused](#rejected-doesnt-mean-refused). | +| Pending | The zone was accepted and is being provisioned. Nameservers are being assigned, or the zone's default records are still being written. | Wait. This normally clears in moments. | +| OK | Nameservers are assigned and the zone's default records are in place. Datum answers queries for this zone. | Add your records, then delegate at your registrar. | +| Error | Datum accepted the zone but couldn't finish programming it. | Read the message on the zone. | + +Every status carries a message from the platform explaining that particular zone's state. Read it — it's more specific than the status word. + +### Rejected doesn't mean refused + +A zone reads **Rejected** whenever Datum hasn't accepted it for provisioning, whatever the reason, and that outranks anything else the zone reports. The word sounds terminal. It usually isn't. + +By far the most common reason is that the domain isn't verified yet, which reads: + +``` +Rejected — Waiting for domain ownership verification before provisioning DNS +``` + +Nothing is wrong and nothing was refused. The zone is waiting for you to publish the verification record. See [Verify domain ownership](/domain-dns/domain-verification). Once the domain verifies, the zone provisions on its own and moves to OK. + +The other reasons a zone reads Rejected: + +- **The domain is already claimed by another zone.** A domain name can be hosted by only one zone at a time. +- **The zone's class wasn't found.** This is a platform-side problem rather than something you can fix in the zone. Contact support. + + +A zone at **OK** with no delegation is a perfectly normal state, and a useful one. It means Datum is ready and serving, and you can add and check every record before you move any live traffic. + + +## Delegation + +Delegation is the link between your registrar and Datum. Your registrar publishes which nameservers are authoritative for your domain, and until that list points at Datum, resolvers never ask Datum anything — no matter how healthy the zone looks. + +To delegate: + +1. Look up the nameservers Datum assigned to the zone. The zone's page in the portal shows them, as does `datumctl dns zone nameservers example.com`. +2. Sign in to your registrar and replace the domain's nameservers with the assigned set. See [Point your domain at Datum](/datumctl/plugins/dns#point-your-domain-at-datum) for checking delegation from the terminal. +3. Save, then wait. Registrar changes take time to reach resolvers. + +Datum reports what it observes in public DNS for the domain: + +| Delegation state | Meaning | +|---|---| +| Complete | Your registrar publishes every assigned nameserver. | +| Partial | Your registrar publishes some of them — usually a half-finished edit. | +| Incomplete | Your registrar publishes none of them. | +| Unknown | There's nothing to compare against yet — the zone has no assigned nameservers, or the registrar hasn't been checked. Normal for the first few minutes after you create a zone, and not a sign that anything is wrong. | + + +Allow for the parent zone's TTL before you treat a delegation change as failed. Top-level domains commonly cache delegations for a day or more, so a change that looks like it did nothing is often just not visible to you yet. + + +## Records Datum manages for you + +When a zone is provisioned, Datum creates two things every zone must have: + +**The SOA record** at the apex. It names the zone's primary nameserver and the responsible mailbox (`hostmaster.` at your domain), and carries the refresh, retry, and expiry timers other nameservers use. + +**The apex NS records**, one for each nameserver assigned to the zone. These are the zone's own statement of who serves it, and they need to agree with what your registrar publishes. + +Datum may also manage records created by another Datum service on your behalf — for example, records an Application Load Balancer creates for a custom hostname. + +These records behave differently from the ones you write: + +- They're created for you and kept in place. Delete the SOA or the apex NS records and Datum recreates them, because the zone is not valid without them. +- Bulk operations leave them alone. `datumctl dns record apply` never modifies or prunes a managed record and reports what it skipped, so applying a zone file can't accidentally strip your nameservers. +- Records owned by another Datum service revert if you edit them by hand. Change them through the service that created them instead. +- On export, managed records are written out as ordinary records. If you import that file into another provider, they arrive as records you own — usually the wrong thing for SOA and NS, which the new provider will want to generate itself. + +Everything else in the zone is yours: you add, change, and delete it freely. See [DNS records](/domain-dns/dns-records). + +## Delete a zone + + +Deleting a zone deletes every record in it, and the domain stops resolving through Datum. If the domain is still delegated to Datum, it stops resolving at all. + + +Delete the delegation first if the domain is live: point the registrar at its new nameservers, wait for the change to propagate, and only then delete the zone. + +Deleting a zone doesn't delete the domain. The domain stays tracked and stays verified, so you can create a new zone for it later without repeating verification. + +## Related + + + + The gate a zone passes before it's provisioned. + + + Supported types, names, values, and TTLs. + + + Bring an existing zone in without downtime. + + + Who changed which zone, and when. + + diff --git a/domain-dns/dns.mdx b/domain-dns/dns.mdx index 772191b..7ef2154 100644 --- a/domain-dns/dns.mdx +++ b/domain-dns/dns.mdx @@ -1,86 +1,124 @@ --- title: "DNS" -description: "We offer authoritative DNS hosting for your domains that you can manage through the Datum Cloud portal as well as CLI." +description: "Authoritative DNS hosting for your domains, managed from the Datum Cloud portal, datumctl, or the API." --- **Working with this resource via an AI agent?** Datum publishes a [DNS skill](/agents/skills/dns) that teaches agents the canonical patterns for this resource. -We offer authoritative DNS hosting for your domains that you can manage through our portal as well as CLI. +Datum hosts authoritative DNS for the domains you own. You create a zone for a domain, prove that you control that domain, point the domain at Datum's nameservers at your registrar, and manage records from the portal, `datumctl`, or the API. -## Current features +## What you get -1. Zone Management – Add DNS zones for any domain and subdomain, whether they are hosted by Datum or externally, for broad visibility across all of your DNS zones. -2. Global Authoritative DNS – Datum serves authoritative DNS through a globally distributed anycast system for performance and redundancy. To use Datum’s authoritative DNS, set up your domain in Datum Cloud ([cloud.datum.net](http://cloud.datum.net) or via _datumctl_) and point it to Datum’s nameservers: - - [ns1.datumdomains.net](http://ns1.datumdomains.net) - - [ns2.datumdomains.net](http://ns2.datumdomains.net) - - [ns3.datumdomains.net](http://ns3.datumdomains.net) - - [ns4.datumdomains.net](http://ns4.datumdomains.net) -3. Bulk Import/Export – Import existing zone files (BIND format, screenshot from DNS provider, sync by querying for DNS records) or export current configurations. -4. Record Operations – Add, edit, and delete modern DNS records: A, AAAA, CAA, NS, SRV, TXT, CNAME, MX, SOA, TLSA, SVCB, HTTPS. -5. View Zone Details – Active nameserver assignments; record count and zone size; last modified timestamp. -6. Audit Log – Track all zone and record changes with user attribution and timestamps. -7. Project Scoped – Manage zones within individual projects with role-based access control. +- **Global authoritative DNS.** Datum serves answers from a globally distributed anycast network for performance and redundancy. +- **Zone management.** Add zones for any domain or subdomain, whether Datum hosts the DNS or another provider does, so you have one view of your DNS estate. +- **Modern record types.** A, AAAA, ALIAS, CNAME, MX, NS, PTR, TXT, SRV, CAA, TLSA, HTTPS, SVCB, and SOA. See [DNS records](/domain-dns/dns-records). +- **Apex ALIAS records.** Point the zone apex at a hostname and still return A and AAAA answers to clients. See [ALIAS records](/domain-dns/alias-records). +- **Bulk import and export.** Import a BIND zone file, or snapshot what a domain resolves to today. Export a zone back out at any time. See [Migrate a zone](/domain-dns/migrate-dns). +- **Audit log.** Every zone and record change is recorded with the user who made it and when. See [Activity logs](/platform/activity-logs). +- **Project scoped.** Zones live in a project and follow that project's role-based access control. -## DNS record types and behaviors +## Datum's nameservers -Most record types are standardized (A, AAAA, CNAME, etc.), but some DNS “record-like” features are provider-specific behaviors (for example, “CNAME flattening”). +Datum serves your zones from: -See ALIAS (“CNAME flattening”) for details. +- `ns1.datumdomains.net` +- `ns2.datumdomains.net` +- `ns3.datumdomains.net` +- `ns4.datumdomains.net` -## Concepts and definitions +Always delegate to the nameservers Datum assigns to your specific zone rather than typing this list from memory. The zone's detail page in the portal and `datumctl dns zone nameservers ` both show the assigned set. -1. **DNS Zone -** A DNS zone is a segment of the Domain Name System that contains the DNS records for one domain or subdomain, managed as a single administrative unit. -2. **DNS Host -** A DNS host is the provider or server that stores and serves the DNS records for your domain, responding to queries from the internet. Some examples of DNS hosts are Datum, Cloudflare, Amazon Route 53, and GoDaddy. -3. **Nameserver -** A nameserver is a specialized DNS server that tells the internet where to find a domain’s DNS Zone and routes queries to the correct host. -4. **DNS Record -** A DNS record is an individual entry within a DNS zone that maps a domain name to a specific resource, such as an IP address, mail server, or another domain. -5. **BIND Format -** BIND format is a standardized text format used to represent DNS zone files, listing all the records and settings that define a domain’s configuration. -6. **Domain Connect -** Domain Connect is an open standard that allows web services and domain registrars to automatically configure DNS settings for users with simple authorization. +## How DNS on Datum works -## ALIAS / CNAME flattening + + + Create a zone for the domain or subdomain you want Datum to serve, for example `example.com`. If the domain isn't tracked in your project yet, Datum adds it for you. -### What is an ALIAS record? + A zone's domain name is fixed once the zone exists. To host a different name, create another zone. + + + Datum doesn't serve DNS for a domain until you prove you control it. You publish a TXT record at your current DNS provider, or serve a token over HTTP from the domain. -An **ALIAS** record is a provider-side feature that lets you point a hostname (including the **zone apex**, like `example.com`) at another hostname the way a CNAME does, while still returning **A/AAAA answers** to clients. + This is a gate, not a formality: no nameservers are assigned and no records are served until verification succeeds. See [Verify domain ownership](/domain-dns/domain-verification). + + + Once the domain is verified, Datum provisions the zone, assigns its nameservers, and creates the zone's SOA record and its apex NS records for you. The zone is now live on Datum's nameservers, even though nothing on the internet is asking them yet. + + + Add the records the domain needs — web, mail, verification tokens for other services. Do this before you delegate, so the domain keeps working through the cutover. See [DNS records](/domain-dns/dns-records). + + + Replace the domain's nameservers at your registrar with the ones Datum assigned. This is the moment the internet starts asking Datum for answers. -Different providers use different names for the same idea: + Delegation happens at your registrar, not on Datum, so Datum can only observe it. See [Delegation](/domain-dns/dns-zones#delegation). + + + Resolvers pick up the new delegation as the old records expire from their caches. Allow for the parent zone's TTL before you treat a delegation change as broken. + + -- **Cloudflare** commonly describes this as **“CNAME flattening”** -- Other DNS providers may call it **ALIAS**, **ANAME**, or **flattened CNAME** +## Domains and DNS zones -### When to use ALIAS +A **domain** and a **DNS zone** are two different things in Datum, and the difference matters. -Use ALIAS when you want “point this name at that hostname” behavior but **you can’t (or shouldn’t) use CNAME**, most commonly: +A [domain](/domain-dns/domains) is a record of a domain name you care about. It tracks registration details, the nameservers the name currently uses, and whether you've proven ownership — regardless of where the name is registered or who hosts its DNS. You can track a domain without Datum serving any DNS for it. -- At the **zone apex** (`example.com`) where CNAME is not allowed by standard DNS rules. -- When you want the convenience of targeting a hostname that may change IPs (CDNs, hosted services), but still need clients to receive A/AAAA records. +A **DNS zone** is DNS hosting for one name. It holds the records Datum serves and the nameservers Datum assigns. A zone always has a domain behind it: create a zone for a name that isn't tracked yet and Datum adds the domain automatically, then waits for that domain to be verified before provisioning anything. -### Expected name and value +The practical consequences: -- **Name**: the hostname inside the zone you’re creating the record for. - - For the zone apex, many DNS tools use `@` (BIND/zone-file notation) to mean “the zone root”. - - For a subdomain, use the label (for example `www` for `www.example.com`). -- **Value**: a **target hostname (FQDN)**, like `myapp.hosting-provider.com`. - - ALIAS values should be **hostnames**, not IP addresses. - - The target hostname should ultimately resolve to **A and/or AAAA** records (directly or through other DNS indirection). +- Verification belongs to the domain, not the zone. Verify a domain once and every zone for that name is unblocked. +- A domain name can be hosted by only one zone at a time. A second zone for the same name reports that the domain is already claimed and stays unprovisioned. +- Deleting a zone doesn't delete the domain. The domain stays tracked and verified. -### How it works +## Concepts -ALIAS does **not** exist as a standardized DNS RRType that recursive resolvers understand everywhere. Instead, the DNS provider’s authoritative system does the work: +**DNS zone** — The segment of the Domain Name System that holds the records for one domain or subdomain, managed as a single unit. -1. A client’s recursive resolver asks for `A` and/or `AAAA` for the ALIAS name (for example `example.com`). -2. Datum resolves the ALIAS target hostname (for example `myapp.hosting-provider.com`) to its current `A`/`AAAA` records. -3. Datum returns the resulting `A`/`AAAA` answers **as if they were directly configured on the ALIAS name**. +**DNS host** — The provider that stores and serves a domain's records, answering queries from the internet. Datum, Cloudflare, Amazon Route 53, and GoDaddy are all DNS hosts. -Important consequence: clients typically **do not** see a CNAME in the response. They see `A`/`AAAA` records for the name they queried. +**Nameserver** — A server that answers DNS queries for a zone. A domain's registrar publishes which nameservers are authoritative for it. -### What to expect compared to CNAME +**Registrar** — The company you registered the domain with. Delegation is changed at the registrar, not at the DNS host. -- **CNAME**: returns a CNAME response and relies on the resolver to chase it. -- **ALIAS / “CNAME flattening”**: returns `A`/`AAAA` directly (synthesized by the DNS provider). +**DNS record** — One entry in a zone that maps a name to a resource: an IP address, a mail server, another hostname, or free text. -### Notes and limitations +**Record set** — Every record with the same name and type, treated as a unit. `www` with two A records is one record set with two values. -- **Portability**: ALIAS/flattening is not uniform across providers. If you move DNS providers, you may need to translate this into whatever equivalent that provider supports. -- **Answer types**: ALIAS is primarily about synthesizing `A`/`AAAA` answers. It is not a general replacement for other record types. \ No newline at end of file +**Zone apex** — The zone's own name, `example.com` rather than `www.example.com`. Written as `@` in zone files and in Datum's tools. + +**Delegation** — The parent zone's NS records that say which nameservers are authoritative for your domain. Set at your registrar. + +**TTL** — How long resolvers may cache an answer. Shorter TTLs propagate changes faster and cost more queries. + +**BIND format** — The standard text format for zone files. Datum imports and exports it. + +**Domain Connect** — An open standard that lets a web service configure DNS at a registrar on your behalf with a single authorization. + +## Where to go next + + + + The gate every zone passes through before Datum serves it. + + + Zone lifecycle, statuses, nameservers, and the records Datum manages. + + + Supported types, how to write names and values, TTLs, and record status. + + + Apex-safe CNAME behavior, also known as CNAME flattening. + + + Move DNS to Datum from another provider, or move it away. + + + Point a domain at an Application Load Balancer endpoint. + + + Manage zones and records from your terminal. + + diff --git a/domain-dns/domain-verification.mdx b/domain-dns/domain-verification.mdx new file mode 100644 index 0000000..ffbb2fa --- /dev/null +++ b/domain-dns/domain-verification.mdx @@ -0,0 +1,107 @@ +--- +title: "Verify domain ownership" +description: "Prove that you control a domain before Datum serves DNS for it, using either a TXT record or an HTTP token." +--- + +Datum doesn't host DNS for a domain until you prove you control it. Verification is a gate on the whole zone: until the domain is verified, the zone has no nameservers assigned, holds no records, and answers nothing. + + +**A zone waiting on verification reports its status as `Rejected`.** Nothing was refused and you did nothing wrong — the status means Datum hasn't accepted the zone for provisioning yet, and waiting for verification is the ordinary reason. The message beside it says so: + +``` +Rejected — Waiting for domain ownership verification before provisioning DNS +``` + +Publish the verification record and the zone provisions itself. See [Zone status](/domain-dns/dns-zones#zone-status). + + +## Why Datum verifies domains + +Without a verification gate, anyone could create a zone for any name that happens to be spelled correctly and start serving real traffic for a domain someone else controls. Requiring proof of control means the only person who can host `example.com` on Datum is someone who can already change `example.com`. + +Verification also unlocks the domain for other Datum services that need a hostname you own, such as Application Load Balancers. + +## What gets verified + +Verification belongs to the **domain**, not to a zone. Verify `example.com` once and every zone you create for that name in the same project is unblocked. A domain tracked in a different project is a separate resource with its own token, so it's verified separately. + +A subdomain zone is verified against the subdomain. A zone for `staging.example.com` needs the verification token published under `staging.example.com`, not under `example.com`. + +The name must be a registrable domain. A bare public suffix such as `com` is rejected as not registrable, and verification never starts for it. + +## Choose a method + +You can prove control two ways. Datum checks DNS first, then HTTP if DNS hasn't succeeded, and **either one succeeding verifies the domain**. You don't need both. + +| Method | Prove it by | Best when | +|---|---|---| +| DNS | Publishing a TXT record at your current DNS provider | You control DNS for the domain. This is the usual choice. | +| HTTP | Serving a token from a URL on the domain | You control the web server but not the DNS, or DNS changes are slow to get approved. | + +Datum generates a unique token for the domain and shows you the exact values to publish. Copy them from the domain's page in the portal rather than composing them yourself. + +### Verify with a TXT record + +Datum asks for a TXT record on a `_datum-custom-hostname` name under your domain, holding the token as its value: + +| Field | Value | +|---|---| +| Name | `_datum-custom-hostname.example.com` | +| Type | `TXT` | +| Value | The token Datum shows you | + + +Add this record at whichever provider serves DNS for the domain **today**. If you're moving to Datum, that's still your old provider — Datum isn't authoritative for the domain until you delegate, so a verification record created inside your new Datum zone can't be seen from the internet yet. + + +Many DNS providers append the zone name to whatever you type in the name field. In those interfaces, enter `_datum-custom-hostname` rather than the full name, or you'll end up with `_datum-custom-hostname.example.com.example.com`. + +### Verify with an HTTP token + +Datum fetches a URL on your domain and compares the response body to the token: + +| Field | Value | +|---|---| +| URL | `http://example.com/.well-known/datum-custom-hostname-challenge/` | +| Response | The token Datum shows you, and nothing else | + +Requirements: + +- The request must return **HTTP 200**. A 404 tells Datum the token isn't published yet. +- The body must be exactly the token. Surrounding whitespace and a trailing newline are ignored; anything else is a mismatch. +- Datum requests `http://`. A redirect to HTTPS is followed, so serving the token only over HTTPS is fine as long as the plain HTTP URL redirects there. +- The request times out after a few seconds, so serve the token as a static response rather than generating it on demand. + +## What happens after you publish + +Datum re-checks on its own — every few seconds for the first few minutes, then about once a minute, then every five minutes. You don't need to trigger anything. Most domains verify within a minute or two of the record becoming visible, though a long TTL on a previous lookup can delay it. + +When verification succeeds: + +1. The domain is marked verified. +2. Datum provisions the zone and assigns its nameservers. +3. Datum creates the zone's SOA and apex NS records. +4. The zone moves from `Rejected` through `Pending` to `OK`, and starts serving. + +Verification is a one-time check. Datum doesn't re-verify a domain it has already verified, so you can remove the TXT record or the HTTP token afterwards — though leaving the TXT record in place costs nothing and saves you from re-doing it if the domain is ever re-added. + +## Troubleshoot verification + +| What you see | What it means | What to do | +|---|---|---| +| Record not found | Datum's lookup returned no verification record or the token endpoint returned 404. | Confirm the record exists at the provider serving the domain today. Query it yourself: `dig TXT _datum-custom-hostname.example.com` or `curl` the token URL. | +| Content mismatch | The record or response exists but doesn't hold the expected token. | Re-copy the token from the portal. Check for a doubled zone name in the record name, and for quotes or whitespace the provider added. | +| Unexpected response | The token URL answered with something other than 200 or 404 — often a redirect loop, a login page, or a 403 from a WAF. | Make the token path publicly reachable without authentication. | +| Nothing happens for a long time | The record isn't visible from the public internet yet. | Check the TTL on the name at your current provider, and confirm you published to the zone that's actually authoritative. | +| The zone still reads `Rejected` after the domain is verified | Verification and provisioning are separate steps, and the zone is re-checked on its own schedule. | Give it a moment. If it persists, read the message beside the status — a different cause, such as the name already being claimed by another zone, produces the same word. See [Zone status](/domain-dns/dns-zones#zone-status). | + +## Related + + + + Tracking the domains you own, wherever they're registered. + + + What happens once the domain is verified. + + diff --git a/domain-dns/domains.mdx b/domain-dns/domains.mdx index c7a5d3f..4e3a94a 100644 --- a/domain-dns/domains.mdx +++ b/domain-dns/domains.mdx @@ -31,6 +31,18 @@ You can add and manage domains through the Datum Cloud portal as well as our pro Once you add a domain as a resource, you can verify ownership. Verified domains become available for use in other Datum services such as Proxy and DNS Zone Hosting. +You prove ownership either by publishing a TXT record at whichever provider serves DNS for the domain today, or by serving a token over HTTP from the domain. Datum shows you the exact values to publish and re-checks on its own until it finds them. + ![Domain Verification](/images/domain-verification.png) - \ No newline at end of file + + +For the full walkthrough, including what to do when verification doesn't complete, see [Verify domain ownership](/domain-dns/domain-verification). + +## Domains and DNS zones + +A domain and a DNS zone are related but separate. The domain tracks the name itself — where it's registered, which nameservers it uses, and whether you've proven you own it. A [DNS zone](/domain-dns/dns-zones) is Datum hosting the records for that name. + +Create a zone for a domain you aren't tracking yet and Datum adds the domain for you, then waits for it to be verified before provisioning anything. Deleting a zone leaves the domain in place, still tracked and still verified. + +See [DNS](/domain-dns/dns) for how the two fit together end to end. \ No newline at end of file diff --git a/domain-dns/migrate-dns.mdx b/domain-dns/migrate-dns.mdx new file mode 100644 index 0000000..bbed525 --- /dev/null +++ b/domain-dns/migrate-dns.mdx @@ -0,0 +1,96 @@ +--- +title: "Migrate a zone" +description: "Move DNS for a domain to Datum from another provider without downtime, and export a zone back out if you leave." +--- + +Moving DNS providers is a cutover, not an edit. The safe shape is always the same: build the new zone completely, check it while nothing depends on it, then switch delegation at the registrar in one step. + +## Move a zone to Datum + + + + Do this several days ahead if you can. If your current provider serves your records with a one-day TTL, resolvers keep answering from the old provider for up to a day after you switch. Lowering TTLs first shrinks that window to minutes. + + This step happens at your current provider, not on Datum. + + + Most providers can export a BIND-format zone file. Take that export — it's the most faithful record of what you have. + + If your provider can't export, Datum can snapshot what the domain resolves to today by querying it. That catches the common record types rather than everything, so compare the result against your provider's interface afterwards. + + + Create the zone, then verify domain ownership by publishing the verification record **at your current provider** — Datum isn't authoritative for the domain yet, so it's the only place a verification record is visible from. See [Verify domain ownership](/domain-dns/domain-verification). + + Wait for the zone to reach **OK** before importing. + + + [Import](/datumctl/plugins/dns#import-an-existing-zone) the zone file, or the discovered snapshot, into the new zone: + + ```sh + datumctl dns zone import example.com --file example.com.zone + ``` + + Preview first with `--dry-run` if you want to see what a file will do before it writes anything. + + Skip the SOA and NS records from your old provider. Datum writes its own, and the old ones name the wrong nameservers. See [Records Datum manages for you](/domain-dns/dns-zones#records-datum-manages-for-you). + + + The zone is live on Datum's nameservers even though nothing is asking for it yet, which means you can test it properly. Query Datum's nameservers directly and compare the answers to what the domain returns today: + + ```sh + dig @ example.com SOA + dig @ www.example.com A + dig @ example.com MX + ``` + + Pay particular attention to mail. A missing MX record or an SPF, DKIM, or DMARC TXT record won't show up as an error — mail just starts failing after the cutover. + + + Replace the domain's nameservers at your registrar with the ones Datum assigned to the zone. This is the cutover. See [Delegation](/domain-dns/dns-zones#delegation). + + + Resolvers hold the old delegation until it expires from their caches, so both providers answer for a period. Keeping the old zone intact and correct during that window means nobody sees a broken answer either way. + + Delete the old zone once the delegation state reads **Complete** and traffic has fully moved — a week is a common, comfortable margin. + + + +## Things that don't survive an import cleanly + +| What | Why | What to do | +|---|---|---| +| Apex CNAME records | Some providers accept an apex CNAME through a proprietary extension. Standard DNS doesn't. | Recreate it as an [ALIAS record](/domain-dns/alias-records). | +| ALIAS, ANAME, or flattened CNAME records | Every provider spells this differently, and a BIND zone file can't represent it. | Recreate them as ALIAS records by hand. | +| The old SOA and NS records | They name the old provider's nameservers. | Leave them out. Datum writes its own. | +| Provider-specific record types | Redirect records, pointers to provider-hosted services, and similar extensions aren't DNS records. | Rebuild that behavior with a real service, such as an [Application Load Balancer](/alb/overview). | +| TTLs | Imported exactly as written in the file, including any long TTLs you lowered for the migration. | Review TTLs after importing and raise or lower them deliberately. | + +## Move a zone away from Datum + +[Export the zone](/datumctl/plugins/dns#export-and-apply-a-zone-file) in BIND format, then import it at your new provider: + +```sh +datumctl dns zone export example.com +``` + +Two caveats on the way out: + +- **ALIAS records can't be exported faithfully.** `ALIAS` isn't a standard record type, so other providers and BIND tooling reject those lines. Recreate them using whatever the new provider calls the same feature. +- **Records Datum manages export as ordinary records.** The SOA and apex NS records appear in the file as if they were yours. Delete them before importing elsewhere — the new provider generates its own. + +Then follow the same shape in reverse: build the zone at the new provider, check it by querying its nameservers directly, change the delegation at your registrar, and only delete the Datum zone once traffic has moved. + + +Don't delete the Datum zone before the delegation change has propagated. While your registrar still points at Datum, deleting the zone stops the domain resolving. + + +## Related + + + + Zone status, delegation, and managed records. + + + Names, values, TTLs, and supported types. + + From 39abe6d3d9f7ecab044ff1f5c46396a8af7acc2c Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Wed, 26 Aug 2026 16:13:39 -0500 Subject: [PATCH 2/2] docs: split the plugin sidebar into available and managing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DNS page sat in the same "Plugins" group as the four pages about plugin machinery — installing, trusting, adding catalogs, publishing them, writing your own. A reader looking for what DNS can do had to pick it out from a list otherwise about how plugins work at all. Splitting the group separates the two questions. "Available plugins" answers what you can install and comes first, since that is what most people arrive wanting; "Managing plugins" keeps the mechanics together below it. The split also gives compute and any later plugin an obvious home rather than lengthening a single mixed list. The page is now "DNS" in the sidebar. Under a heading that already says these are plugins, "DNS plugin" repeated the word for no gain, and the surrounding pages follow the same split of a Title Case title and a sentence case sidebar entry. Adds one line to Using Plugins pointing at the new group, so the plugins with real guides are discoverable from the page that explains searching for them. Co-Authored-By: Claude Opus 5 (1M context) --- datumctl/plugins/dns.mdx | 4 ++-- datumctl/plugins/using-plugins.mdx | 2 ++ docs.json | 9 +++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/datumctl/plugins/dns.mdx b/datumctl/plugins/dns.mdx index b5bbdf2..b3b406c 100644 --- a/datumctl/plugins/dns.mdx +++ b/datumctl/plugins/dns.mdx @@ -1,6 +1,6 @@ --- -title: "DNS plugin" -sidebarTitle: "DNS plugin" +title: "DNS Plugin" +sidebarTitle: "DNS" description: "Install the datumctl dns plugin and manage Datum Cloud DNS zones and records from your terminal." --- diff --git a/datumctl/plugins/using-plugins.mdx b/datumctl/plugins/using-plugins.mdx index 813f493..a93066a 100644 --- a/datumctl/plugins/using-plugins.mdx +++ b/datumctl/plugins/using-plugins.mdx @@ -39,6 +39,8 @@ datumctl plugin search deploy --index acme Results show the plugin name, the catalog it came from, its version, its trust badge, and a short description. +Plugins with a full guide of their own are listed under **Available plugins** in the sidebar — currently the [DNS plugin](/datumctl/plugins/dns). + Prefer to explore interactively? `plugin browse` opens a filterable picker where you can inspect a plugin's details and install it in place: ```bash diff --git a/docs.json b/docs.json index a35e4c4..aaa7737 100644 --- a/docs.json +++ b/docs.json @@ -180,10 +180,15 @@ ] }, { - "group": "Plugins", + "group": "Available plugins", + "pages": [ + "datumctl/plugins/dns" + ] + }, + { + "group": "Managing plugins", "pages": [ "datumctl/plugins/using-plugins", - "datumctl/plugins/dns", "datumctl/plugins/adding-catalogs", "datumctl/plugins/publishing-catalogs", "datumctl/plugins/building-plugins"