Docs / Custom domains

Custom domains

Point your hostname at aft.page after claim. The first one is free. CNAME to cname.aft.page; your default URL stays.

Add your domain

Your first custom domain is free — no approval. Claim the site → CNAME the hostname to cname.aft.page → attach it from project Domains. Need more than one? Request it from the same tab; approved accounts get up to 2 hostnames per site.

DNS

A new hostname: point it at aft.page, then attach it.

CNAME  app.example.com  →  cname.aft.page

Moving a live site from another host? Attach it first, before you touch DNS. aft shows two TXT records (one proves you own the name, one issues the certificate). Add them; your site keeps serving from its old host. Once the domain says active, switch the CNAME. HTTPS is already ready, so there is no downtime.

Testing before you switch? Until the CNAME moves, your app runs at your-app.aft.page. If it calls its own API (say api.example.com), that API's CORS settings must allow https://your-app.aft.page too, or every request from the preview fails. Add it while you test, and remove it after the switch if you like.

A new domain starts in pending. Your default URL keeps working the whole time. Private sign-in still uses that hostname for cookies and sessions, so don't remove it.

HTTPS

Certificates issue after DNS is live and aft.page has verified the hostname with aft. Status moves pending → active on the same Domains tab; a failure moves it to error with a message explaining why. This step depends on DNS propagation, which is outside aft.page's control and can take anywhere from a few minutes to a few hours depending on your registrar.

Apex

Bare example.com needs ALIAS / ANAME / CNAME flattening to cname.aft.page (plain CNAME at apex is not valid DNS). Prefer a subdomain (app. / www.) when unsure — it avoids the flattening step entirely.

API

# list domains on a site
curl https://api.aft.page/v1/sites/{slug}/domains -H "Cookie: …"

# add one
curl -X POST https://api.aft.page/v1/sites/{slug}/domains \
  -H "Content-Type: application/json" -H "Cookie: …" \
  -d '{"hostname":"app.example.com"}'

# re-check status (same as clicking Refresh)
curl -X POST https://api.aft.page/v1/sites/{slug}/domains/app.example.com \
  -H "Cookie: …"

# remove
curl -X DELETE https://api.aft.page/v1/sites/{slug}/domains/app.example.com \
  -H "Cookie: …"

A domain response looks like { "hostname", "status": "pending" | "active" | "error", "sslStatus", "error" }. error is null until something needs your attention.

Troubleshooting

Status stuck on pending — first confirm the CNAME is actually live (dig CNAME app.example.com) and give DNS time to propagate. If it's been live a while, hit Refresh on the Domains tab (or the re-check API call above) to force aft.page to re-check status instead of waiting for the next automatic check.

Seeing "Custom domains are not fully enabled on aft.page yet"? That's a message from our side, not a problem with your DNS — your CNAME is correct, but aft.page custom domains setup isn't finished issuing certificates yet. Nothing to fix on your end; the domain will move to active once that's turned on.

Still pending? The TXT records or the CNAME are missing or still propagating. Wait, then run aft domain refresh. A hostname can only be attached to one site; a CNAME pointing at aft.page takes over an unverified attach from another project.

Next: Capabilities — declare what a Worker or Next app needs before it deploys.