From 3a910bdc48a8a593853a034bd8592dd0444206f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?batuhan=20i=C3=A7=C3=B6z?= Date: Sat, 7 Nov 2026 02:21:00 +0100 Subject: [PATCH 1/3] Show the DNS records a Space domain actually asks for The domains page told everyone to publish two `_stattic-verify` TXT records, two `A` records and two `AAAA` records. A Space domain asks for two `A` records on the apex and a `www` CNAME, and no TXT record unless the hostname is already in use elsewhere. That last case now has its own section: the provider's `atomic-domain-` challenge, and the `_spacefast-claim` record for a hostname another Space serves. Co-Authored-By: Claude Opus 5.5 --- content/(serve)/domains.mdx | 24 ++++++++++++++---------- content/cli/domains.mdx | 5 +++-- evals.yaml | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/content/(serve)/domains.mdx b/content/(serve)/domains.mdx index caa2dcc7..42f74fce 100644 --- a/content/(serve)/domains.mdx +++ b/content/(serve)/domains.mdx @@ -70,24 +70,28 @@ A domain belongs to a **team**, not to a Space. You add it once to the team's in An unassigned domain has no records to show. Instructions appear once the domain is assigned to a Space, which is why `sf domains add` assigns in the same command. -Each record the API returns has four fields: `type`, `name`, `value`, and `purpose`. Adding the apex `example.com` produces six of them in the common case, because the `www` twin is set up alongside it. +Each record the API returns has four fields: `type`, `name`, `value`, and `purpose`. Adding the apex `example.com` usually produces three, because the `www` twin is set up alongside it. | Type | Name | Value | Purpose | | --- | --- | --- | --- | -| `TXT` | `_stattic-verify.example.com` | `stattic-team-verification=tm_xxxxxxxx` | `verification` | -| `TXT` | `_stattic-verify.www.example.com` | `stattic-team-verification=tm_xxxxxxxx` | `verification` | -| `A` | `example.com` | `192.0.79.132` | `routing` | -| `A` | `www.example.com` | `192.0.79.132` | `routing` | -| `AAAA` | `example.com` | the IPv6 address in your instructions | `routing` | -| `AAAA` | `www.example.com` | the IPv6 address in your instructions | `routing` | +| `A` | `example.com` | `192.0.79.157` | `routing` | +| `A` | `example.com` | `192.0.79.175` | `routing` | +| `CNAME` | `www.example.com` | `example.com` | `routing` | -The TXT value carries your team id and proves you control the zone. The address records are generated for your hostname, so copy the exact values from your own output rather than the ones above. +A subdomain like `app.example.com` gets its two `A` records and nothing else. The addresses are generated for your hostname, so copy the exact values from your own output rather than the ones above. :::warning[Delete the old address records first] -Every observed `A` record has to point at Spacefast. A leftover record from your previous host sitting beside the correct one blocks verification, and the diagnostics will report the hostname as not configured while both are live. The same rule applies to `AAAA` when IPv6 is offered. +Every observed `A` record has to point at Spacefast. A leftover record from your previous host sitting beside the correct one blocks verification, and the diagnostics will report the hostname as not configured while both are live. ::: -Spacefast generates `A`, `AAAA` and `TXT` records only. There is no CNAME or ALIAS instruction. +### When a TXT record shows up + +Most domains need no TXT record. One appears only when the hostname is already in use elsewhere and you have to prove it is yours: + +- **Another host still holds it.** The record is named for the hostname, its value starts with `atomic-domain-`, and the domain waits until it is published. Remove any CNAME at that name first; a TXT record cannot sit beside one. +- **Another Space serves it.** Adding it here leaves a claim and returns a `_spacefast-claim.` TXT record. Publish it, then verify to move the domain to this Space. + +Keep exactly one `atomic-domain-` record per hostname. Two of them, even when one is correct, make the claim fail. ## Apex and www travel together diff --git a/content/cli/domains.mdx b/content/cli/domains.mdx index a63a735a..e4e804a3 100644 --- a/content/cli/domains.mdx +++ b/content/cli/domains.mdx @@ -52,8 +52,9 @@ ID: dom_xxxxxxxx Verification: pending Configure DNS for example.com: - TXT _stattic-verify.example.com stattic-team-verification=tm_xxxxxxxx - A example.com 192.0.79.132 + A example.com 192.0.79.157 + A example.com 192.0.79.175 + CNAME www.example.com example.com Next: `sf domains check example.com` ``` diff --git a/evals.yaml b/evals.yaml index 96005bbc..c649d5ab 100644 --- a/evals.yaml +++ b/evals.yaml @@ -18,7 +18,7 @@ questions: routes: /anonymous-and-claim - id: domain-dns-records question: Which DNS records do I add to connect example.com? - expected: ["TXT record at _stattic-verify.example.com", "A records", "www is set up alongside the apex"] + expected: ["A records for example.com", "a CNAME for www.example.com", "no TXT record unless the hostname is already in use elsewhere"] routes: /domains - id: domains-rm question: Does `sf domains rm` delete the domain? From 0c9b16ada94d1aca01ed4ca47d4deb6c6c6ce1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?batuhan=20i=C3=A7=C3=B6z?= Date: Sun, 8 Nov 2026 02:11:07 +0100 Subject: [PATCH 2/3] Make the domains page agree with how claims and moves work - A domain another Space serves now creates a claim with a TXT record, not a domain_in_use error; the move and error-table sections say so. - The claim bullet says when the move completes and that a claim expires. - A subdomain usually gets two A records; the TXT cases still apply. - Remove a leftover AAAA too, since it sends IPv6 visitors to the old host. - The troubleshooting page no longer says a CNAME is never issued. --- content/(serve)/domains.mdx | 12 ++++++------ content/troubleshooting.mdx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/content/(serve)/domains.mdx b/content/(serve)/domains.mdx index 42f74fce..6abedb8b 100644 --- a/content/(serve)/domains.mdx +++ b/content/(serve)/domains.mdx @@ -78,10 +78,10 @@ Each record the API returns has four fields: `type`, `name`, `value`, and `purpo | `A` | `example.com` | `192.0.79.175` | `routing` | | `CNAME` | `www.example.com` | `example.com` | `routing` | -A subdomain like `app.example.com` gets its two `A` records and nothing else. The addresses are generated for your hostname, so copy the exact values from your own output rather than the ones above. +A subdomain like `app.example.com` usually gets just its two `A` records. The addresses are generated for your hostname, so copy the exact values from your own output rather than the ones above. :::warning[Delete the old address records first] -Every observed `A` record has to point at Spacefast. A leftover record from your previous host sitting beside the correct one blocks verification, and the diagnostics will report the hostname as not configured while both are live. +Every observed `A` record has to point at Spacefast. A leftover record from your previous host sitting beside the correct one blocks verification, and the diagnostics will report the hostname as not configured while both are live. Remove any `AAAA` record left from your previous host too: it sends IPv6 visitors there. ::: ### When a TXT record shows up @@ -89,7 +89,7 @@ Every observed `A` record has to point at Spacefast. A leftover record from your Most domains need no TXT record. One appears only when the hostname is already in use elsewhere and you have to prove it is yours: - **Another host still holds it.** The record is named for the hostname, its value starts with `atomic-domain-`, and the domain waits until it is published. Remove any CNAME at that name first; a TXT record cannot sit beside one. -- **Another Space serves it.** Adding it here leaves a claim and returns a `_spacefast-claim.` TXT record. Publish it, then verify to move the domain to this Space. +- **Another Space serves it.** Adding it here creates a claim instead of failing, and returns a `_spacefast-claim.` TXT record. Publish it, then verify. The move to this Space happens once you can also remove the domain from the Space that holds it; otherwise remove it there first, as in [Moving a domain to another Space](#moving-a-domain-to-another-space). A claim expires after 24 hours. Keep exactly one `atomic-domain-` record per hostname. Two of them, even when one is correct, make the claim fail. @@ -157,14 +157,14 @@ The redirect target is either an absolute URL or another Space. There is no path ## Moving a domain to another Space -There is no move operation. Unassign, then assign: +Unassign, then assign: ```bash sf domains rm example.com --space old-site sf domains add example.com --space new-site ``` -Assigning a domain that is still bound elsewhere fails with `domain_in_use`, and reassigning while the previous teardown is still draining fails with `domain_detach_in_progress`. Wait for the unassign to finish. The `--wait` flag on `sf domains rm` does that for you and is on by default. +Adding a domain another Space still serves creates a claim with a TXT record to publish, as described in [When a TXT record shows up](#when-a-txt-record-shows-up). Reassigning while the previous teardown is still draining fails with `domain_detach_in_progress`. Wait for the unassign to finish. The `--wait` flag on `sf domains rm` does that for you and is on by default. ## Removing versus deleting @@ -227,7 +227,7 @@ www.example.com purpose=www dns=not_configured txt=missing ssl=missing | `managed_domain_protected` | 400 | You passed the id of a built-in `space.fast` or `view.fast` hostname. | | `domain_already_exists` | 409 | The team already has that hostname. | | `domain_quota_exceeded` | 409 | The plan's external domain group limit is reached. | -| `domain_in_use` | 409 | Another verified claim serves it, or it is still assigned to a Space. | +| `domain_in_use` | 409 | The hostname is already on this Space, a previous attachment is still being removed, or you tried to delete a domain that is still assigned. | | `domain_detach_in_progress` | 409 | A previous unassign is still draining. | | `domain_not_bound` | 409 | You set a redirect, or retried SSL, on a domain with no Space. | | `domain_primary_redirect_conflict` | 400 | A redirecting domain cannot be primary. Clear the redirect first. | diff --git a/content/troubleshooting.mdx b/content/troubleshooting.mdx index fdcda0d5..cc6cf920 100644 --- a/content/troubleshooting.mdx +++ b/content/troubleshooting.mdx @@ -81,7 +81,7 @@ If two files would answer the same URL after that resolution, the publish stops sf domains diagnostics example.com --space my-site ``` -`dns_records_missing` means the records have not been observed yet. The usual cause is a leftover `A` record from your previous host sitting beside the correct one. Every observed `A` record has to point at Spacefast, so delete the old ones. Spacefast issues `A`, `AAAA`, and `TXT` records only, never a CNAME. See [Custom domains](/domains). +`dns_records_missing` means the records have not been observed yet. The usual cause is a leftover `A` record from your previous host sitting beside the correct one. Every observed `A` record has to point at Spacefast, so delete the old ones, and any `AAAA` left from your previous host. An apex gets two `A` records and a `www` CNAME; a TXT record appears only when the hostname is in use elsewhere. See [Custom domains](/domains). ### The domain went `failed` after working From 16166313c1af6aa336ff61cb36c3cb39a7e51480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?batuhan=20i=C3=A7=C3=B6z?= Date: Sun, 8 Nov 2026 02:15:44 +0100 Subject: [PATCH 3/3] Describe both ways a domain claim moves a hostname A claim moves the hostname either when you can also manage the Space that holds it, or once its TXT record is seen. A different team takes the second path; nothing waits for the other claim to stop verifying. The diagnostic row now names the code the API returns, domain_ownership_required. --- content/(serve)/domains.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/(serve)/domains.mdx b/content/(serve)/domains.mdx index 6abedb8b..eb42b0c5 100644 --- a/content/(serve)/domains.mdx +++ b/content/(serve)/domains.mdx @@ -89,7 +89,7 @@ Every observed `A` record has to point at Spacefast. A leftover record from your Most domains need no TXT record. One appears only when the hostname is already in use elsewhere and you have to prove it is yours: - **Another host still holds it.** The record is named for the hostname, its value starts with `atomic-domain-`, and the domain waits until it is published. Remove any CNAME at that name first; a TXT record cannot sit beside one. -- **Another Space serves it.** Adding it here creates a claim instead of failing, and returns a `_spacefast-claim.` TXT record. Publish it, then verify. The move to this Space happens once you can also remove the domain from the Space that holds it; otherwise remove it there first, as in [Moving a domain to another Space](#moving-a-domain-to-another-space). A claim expires after 24 hours. +- **Another Space serves it.** Adding it here creates a claim instead of failing, and returns a `_spacefast-claim.` TXT record. If you can also manage the Space that holds it, verify with move and the domain moves without the record. Otherwise publish the record at your DNS host and verify: once Spacefast sees it, the domain moves to this Space and the old Space stops serving it. Either way, a claim expires 24 hours after it was created; add the domain again for a new one. Keep exactly one `atomic-domain-` record per hostname. Two of them, even when one is correct, make the claim fail. @@ -183,7 +183,7 @@ Every domain a team owns lives on one page, whether or not it is assigned. In th Over the API, `GET /v1/domains` lists the team's inventory and `GET /v1/spaces/{spaceId}/domains` lists what one Space serves on. The CLI's `sf domains ls` is the per-Space list. -Two different teams may add the same hostname. Only serving is exclusive, so a team that proves control can take over a hostname whose current holder has stopped verifying. +Two different teams may add the same hostname. Only serving is exclusive: a team that publishes its claim's TXT record moves the hostname to its own Space. Adding a domain also counts against a plan limit, measured in external domain groups. One group is a registrable apex plus all of its subdomains. Over the limit, the add fails with `domain_quota_exceeded`. @@ -207,7 +207,7 @@ www.example.com purpose=www dns=not_configured txt=missing ssl=missing | --- | --- | --- | | `dns_records_missing` | The required records have not been observed. Verification keeps polling. | Add the records at your DNS host. | | `verification_required` | The hostname needs proof of DNS control to keep serving. | Add the verification TXT record. | -| `hostname_claim_conflict` | Another verified claim is serving this hostname. | Prove control here. The takeover completes once the other claim stops verifying. | +| `domain_ownership_required` | Another Space serves this hostname. | Publish the claim's TXT record, then verify to move it here. | | `ssl_pending` | Certificate issuance is in progress. | Wait. | | `ssl_renewal_blocked` | A DNS record, usually CAA, is blocking issuance. | Fix the record, then retry SSL. | | `provider_pending` | The edge has not observed the hostname yet. | Wait. |