agentleFS
Rafaelrr5Rafaelrr5/agent-cortex/skills/domain-dns-cutover/SKILL.md

domain-dns-cutover

Skill1 starsChanged 37 days agoMITView on GitHub

Move a domain to new hosting; verify at authoritative NS.

  • Sends data out

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. About 0 are common, 12 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before running certbot / issuing TLS for a domain

    line 26
  2. Very specific:

    Not this skill: MX/SPF/DKIM/DMARC and mail deliverability — that is custom-domain-email, which owns the email half of DNS.

    line 28
  3. Distinctive:

    Look for the shape of the answer, because each one means something different:

    line 66
  4. Distinctive:

    Add the domain in the destination's panel — this is what creates the zone.

    line 99
  5. Distinctive:

    Read the destination's nameservers from that account (defaults published in docs are frequently not what your account is assigned).

    line 100
  6. Distinctive:

    Only then change NS at the registrar.

    line 102
  7. Distinctive:

    Consequence for planning: when the user wants Route B but the destination has no zone yet, Route A gets them live today and Route B becomes …

    line 109
  8. Distinctive:

    After nameservers change, registrars commonly freeze the zone for a period (registro.br: ~2 h) before publishing anything.

    line 116
  9. Distinctive:

    When a provider's browser/web console will not take input, do not fight it and do not start guessing at root passwords.

    line 163
  10. Distinctive:

    Check whether the local key has a passphrase before promising unattended access:

    line 210
  11. Distinctive:

    When a user says "I'll wait for things to unblock", correct the premise: waiting buys nothing but delay.

    line 228
  12. Distinctive:

    Concluding "the records were not saved" from a cache miss: Check the authoritative servers, and prefer "saved but not published yet".

    line 244
  13. Distinctive:

    Copying a provider's documented default nameservers: Read them from the user's own account.

    line 251

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Domain DNS Cutover

Pointing a domain the user owns at new infrastructure — a VPS, a new host, a new DNS provider — and proving it actually resolves before calling it done.

When to Use

  • "I want to put my domain on <provider>"
  • "Move the domain to the VPS / to Hostinger / off Vercel"
  • Choosing between an A record and delegating nameservers
  • A domain that stopped resolving after a provider change
  • Any registrar-panel work: NS delegation, zone records, provider transfer
  • Before running certbot / issuing TLS for a domain

Not this skill: MX/SPF/DKIM/DMARC and mail deliverability — that is custom-domain-email, which owns the email half of DNS.

Supporting files:

  • references/registro-br-and-hostinger.md — .br registrar rules, transition windows, Hostinger API endpoints and their misleading error codes
  • scripts/dns-authoritative-check.py — re-runnable check of A records against the authoritative nameservers (handles the Windows nslookup encoding trap)

Step 0 — Separate the three layers before answering anything

Users compress three independent things into "put the domain on X". Untangling them is most of the value you add, and getting it wrong sends them to the wrong panel.

LayerWhat it isWhere it changesMoves to the new provider?
Registration / providerwho administers and renews the namethe registraroften not required
DNS (NS)who answers queries for the zoneregistrar → "change nameservers"optional
Hostingwhere the site actually runsthe host / VPSthis is the real goal

State which layers the task actually needs. Very often only hosting has to move, and the domain can stay exactly where it is.

ccTLD trap: some ccTLDs cannot be transferred between registrars at all. A .com.br never leaves registro.br — the registry is single. What exists is changing the provider to the new host's code (Hostinger = HSTDOMAINS (127)), which is independent of DNS and usually unnecessary. Never promise a "transfer" before checking the TLD's rules.

Step 1 — Read the current state from DNS, not from the user

Memory and panels go stale; the resolver does not. Check before proposing.

python scripts/dns-authoritative-check.py example.com

Look for the shape of the answer, because each one means something different:

ResultMeans
NS at the old providernothing has moved yet
NS at the registrar's own DNS + empty zonedomain is inert — resolves to nothing
NODATA (name exists, no A)zone is live but the record is missing or unpublished
NXDOMAINthe name itself does not exist at that server
Leftover v=spf1 -allresidual record that blocks all mail — flag it

A domain whose NS moved to the registrar with an empty zone is already down. Say so plainly rather than describing it as "in progress".

Step 2 — Pick the route: A record, or NS delegation

Both are legitimate. The choice is about where the user wants to manage the zone, and it has a hard ordering consequence.

Route A — A recordRoute B — delegate NS
Zone lives atthe registrarthe new provider
Works when the target is a VPS with a fixed IPyes, immediatelyyes
Prerequisitenonethe destination must already host a zone for this domain
Time to liveminutespropagation, plus any registrar lock
Good forshipping today; a single VPSunifying DNS + mail + hosting in one panel

The ordering rule that breaks Route B

Registrars validate the nameserver before accepting the delegation. They query the target and refuse if it is not authoritative for the domain, typically with a "query refused" / "Pesquisa recusada" error. So Route B requires, in this order:

  1. Add the domain in the destination's panel — this is what creates the zone.
  2. Read the destination's nameservers from that account (defaults published in docs are frequently not what your account is assigned).
  3. Only then change NS at the registrar.

You usually cannot do step 1 through the provider's API: a zone-write call against a domain the account does not yet own returns "domain not found" (see the reference). Treat step 1 as a manual step for the user and say so instead of burning calls on it.

Consequence for planning: when the user wants Route B but the destination has no zone yet, Route A gets them live today and Route B becomes a later improvement. Offer that inversion — do not let a management preference block shipping.

Step 3 — Respect registrar transition windows

After nameservers change, registrars commonly freeze the zone for a period (registro.br: ~2 h) before publishing anything. During the freeze, records saved in the panel are visible in the panel and absent from the authoritative servers. This is not propagation and not an error.

Read the panel's own banner before diagnosing. A screenshot that says "os servidores DNS do domínio se encontram em transição … em aproximadamente 1h11m" has already answered the question. Two separate notices often sit on the same page and mean different things:

BannerWhat it blocks
"servidores DNS em transição … Nh"publication of the zone — this is the one that matters
"Modo básico só poderá ser selecionado em Nh"only switching zone-editing modes — usually irrelevant

Dismissing both as irrelevant because one of them is, is a real failure mode.

Tell the user to stop touching the panel during the window — each save can restart the clock. "No action required" is the correct instruction, and it is worth saying explicitly, because a stalled user will otherwise keep editing.

Step 4 — Verify at the authority, never at the cache or the panel

Three sources disagree, and only one is evidence:

  1. The panel — proves the record was accepted, not that it is served.
  2. A public resolver (8.8.8.8) — may hold a negative cache entry for a name that now resolves, or serve a stale positive one.
  3. The domain's own authoritative nameservers — the only source of truth.

Query the authoritative servers by name (a.auto.dns.br, ns1.<provider>.com) and confirm the record and its value. Do not conclude "the records were never saved" from a cache miss; if the panel shows them, the honest reading is unpublished-yet, not absent.

Windows encoding trap: nslookup emits localised output in cp850, so subprocess.run(..., text=True) raises UnicodeDecodeError, the stdout is lost, and any parse built on it silently reports "no records". Decode explicitly with cp850. Also never regex the whole output for an IP — the DNS server's own address appears first and produces confident false positives. scripts/dns-authoritative-check.py handles both.

Step 5 — Getting into the target VPS

The cutover is pointless if nobody can reach the box. A brand-new VPS typically has 22 open and 80/443 closed — that is a bare server, not a fault.

When a provider's browser/web console will not take input, do not fight it and do not start guessing at root passwords. Providers expose SSH key management in their API; attaching the user's existing public key is additive, reversible, and needs no secret from them:

# 1) upload the key -> returns an id
curl -s -X POST "$API/vps/v1/public-keys" -H "Authorization: Bearer $TK" \
  -H 'Content-Type: application/json' \
  -d "{\"name\":\"agent-<device>-<date>\",\"key\":\"$(cat "$HOME/.ssh/<key-name>.pub")\"}"

# 2) attach it to the machine
curl -s -X POST "$API/vps/v1/public-keys/attach/<vmId>" -H "Authorization: Bearer $TK" \
  -H 'Content-Type: application/json' -d '{"ids":[<keyId>]}'

# 3) the ONLY proof that matters
ssh -o BatchMode=yes -o StrictHostKeyChecking=no root@<ip> 'hostname; uname -sr'

Attach calls often return a hollow success body ({"id":0,"name":"","state":""}) whether or not they worked, and some documented read-back routes do not exist (Route is not found is a routing error, not an auth error). Only a real SSH login verifies it. Allow ~20 s for the key to land.

When attach does nothing: give up on it fast

Key attach is reliable at provisioning time and unreliable on a running box — the same call that works on a fresh VM can queue nothing at all on a live one (details and evidence in the reference). Budget two attempts and about two minutes, then switch routes. Signals that attach is a dead end here:

  • GET /vps/v1/virtual-machines/{id}/actions shows no new action for your attach, while other calls (restart, root-password) do create one.
  • ssh -v shows the right key offered and refused — the key is fine, it is simply not in authorized_keys.

Do not reboot to "make the injection apply". It is not a boot-time step; rebooting costs downtime and changes nothing. Escalate instead to setting the root password by API and installing the key yourself on the first login — that converts a password into permanent key access in one step, and afterwards the password is no longer the way in.

Handle the generated password safely: write it to a chmod 600 file before the API call that applies it (so it can never be live-and-unknown), and never print it into chat or logs — the transcript persists on disk.

Check whether the local key has a passphrase before promising unattended access:

ssh-keygen -y -P "" -f "$HOME/.ssh/<key-name>" >/dev/null 2>&1 && echo "no passphrase"

Step 6 — TLS comes last, and only it depends on DNS

Sequence the work so the DNS wait blocks as little as possible:

StepBlocked by DNS?
Webserver, runtime, process manager, firewallno
Clone, build, start the appno
curl -I http://localhost:3000 on the boxno
certbot --nginx -d domain -d www.domainyes

Everything except certificate issuance can proceed during a transition window. When a user says "I'll wait for things to unblock", correct the premise: waiting buys nothing but delay. Only the TLS step needs the name to resolve.

Gate certbot on a real resolution check, and never work around a DNS failure with --standalone (it wants port 80 and will fight the running webserver):

dig +short example.com @8.8.8.8   # must return the target IP before certbot

Pitfalls

  • Trusting stale knowledge about where DNS lives. Re-query every time; a domain's NS may have moved since the last session. Correct yourself out loud.
  • Reading the zone state and skipping the panel's banner. The banner explains the state you are trying to infer. Read the user's screenshot fully.
  • Concluding "the records were not saved" from a cache miss. Check the authoritative servers, and prefer "saved but not published yet".
  • Editing the zone-config screen when the goal is delegation. Registrars have a separate "change nameservers" action; the zone editor is the wrong screen and its basic/advanced modes are irrelevant to delegation.
  • Assuming a zone-write API call can onboard the domain. It cannot until the account owns the domain.
  • Copying a provider's documented default nameservers. Read them from the user's own account.
  • Scheduling a monitor when no delivery channel exists. A cron job on a host with a stopped gateway (or a messaging channel disabled on this device) fires nowhere. Verify the channel, or do not create the job — a silent monitor is worse than none, because the user waits for an alert that cannot arrive. Remove it and say you will check on request.

Reporting shape (Portuguese-language support)

Portuguese, direct, no preamble. Lead with the decision or the blocker, not a recap. Markdown tables for the three-layer split and for record values; give exact field values including the fact that the root record's name field is left empty at registro.br (it rejects @ and *). Separate crisply what YOU did from what only the USER can do, and say why. When an earlier statement of yours turns out wrong, correct it inline and name the wrong reasoning — users can read corrections as competence, not noise.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.