Custom domains
Every app gets https://<app>.aloof.si. You can also serve it from your own domain, such as api.example.com or example.com, with a free HTTPS certificate that we issue and renew automatically. It works the same way as on Fly.io, Railway and Render: add the domain, create a few DNS records at your registrar, and we do the rest.
Step by step
- Add the domain (dashboard → your app → Domains, or the CLI, API or MCP):
aloof domains my-app add api.example.com
- Create the DNS records it prints at the place where your DNS is hosted (usually your registrar, or Cloudflare, Route 53, etc.):
The exact values, including your own token, are shown in the dashboard,
Type Name Value Purpose TXT _aloof-challenge.api.example.comaloof-verify=<token>proves you own the domain (always needed) CNAME api.example.commy-app.aloof.siroutes traffic for a subdomain A example.com178.104.200.75routes traffic for a root (apex) domain, or instead of the CNAME AAAA example.com2a01:4f8:1c1f:71d2::1IPv6, added next to the A record (optional, but if you publish an AAAA it must be ours) aloof domains my-app listand the API response. - Wait a few minutes. We re-check DNS automatically (after 2 minutes, then every 5, 10 and 30 minutes, backing off to every 6 hours), so a pending domain becomes verified by itself. To check right now, press Check now in the dashboard or run
aloof domains my-app verify api.example.com. - Open
https://api.example.com. The certificate is issued on the first HTTPS request, which usually takes a few seconds.
Subdomain or root domain?
- Subdomain (
api.example.com,www.example.com): add a CNAME to<app>.aloof.siplus the TXT record. This is the simplest option, and it keeps following us if our server address ever changes. - Root / apex domain (
example.com): DNS doesn't allow a plain CNAME there. Add the A record (and the AAAA record for IPv6) plus the TXT record. Or, if your DNS provider offers ALIAS, ANAME or CNAME flattening (Cloudflare, Namecheap, DNSimple, Route 53 for AWS targets only, and others), point that record at<app>.aloof.siinstead. Use one style or the other, not both.
www and root domain together
Add the one you want as your main address, for example example.com. Once it is verified, we also answer on www.example.com with a permanent redirect (HTTP 308, path and query kept) to https://example.com, with no extra verification, as long as www points at us as well (CNAME to <app>.aloof.si, or the same A/AAAA records). The same works the other way: if you add www.example.com and verify it, example.com redirects to it. If you'd rather serve both without redirecting, add both as separate domains (each counts toward your limit). The redirect is only ever to a domain you have verified.
Registrar and DNS-provider tips
In every panel: a Name/Host field is usually relative to your domain, so for api.example.com enter api (and _aloof-challenge.api for the TXT record). For the root domain the name is @. Remove any older A, AAAA or CNAME record for the same name first. A name can't have a CNAME next to other records.
Cloudflare
DNS → Records → Add record. Set the routing records (CNAME, A, AAAA) to DNS only (grey cloud). With the orange-cloud proxy on, the domain resolves to Cloudflare's addresses instead of ours, so the routing check fails and we can't issue a certificate; domains behind the proxy aren't supported. The TXT record is never proxied. Cloudflare allows a CNAME on the root domain (it flattens it for you), so example.com → CNAME <app>.aloof.si works there.
GoDaddy
My Products → your domain → DNS → Add New Record. GoDaddy has no ALIAS/ANAME and no CNAME on the root, so for example.com use the A record (and the AAAA record for IPv6) with Host @, and delete the default "Parked" A record. Subdomains use a CNAME with Host api. TXT Host: _aloof-challenge.api. GoDaddy's minimum TTL is 600 seconds, so allow about 10 minutes.
Namecheap
Domain List → Manage → Advanced DNS → Add New Record. Host is api or @. For the root domain you can use an ALIAS Record to <app>.aloof.si or the A record (and the AAAA record for IPv6). Delete the default "URL Redirect" or parking records for the same host. TXT Host: _aloof-challenge.api. The nameservers must be Namecheap BasicDNS or PremiumDNS for Advanced DNS to apply.
Amazon Route 53
Hosted zones → your zone → Create record. Name is api (leave it empty for the root domain). Route 53's "Alias" option only targets AWS resources, so it can't point at us: for the root domain use A and AAAA records with the plain values, and for subdomains a CNAME. Put the TXT value in quotes: "aloof-verify=…".
Propagation
New records usually show up within a few minutes, but resolvers can cache the old answer for as long as the previous record's TTL (often up to an hour, rarely 24–48 hours). There's nothing to do while you wait: we keep checking, and you can also press Check now. Manual checks are rate limited (see Limits).
Status and monitoring
Each domain has a status and a last-checked time (dashboard, CLI aloof domains <app> list, API GET /v1/domains, MCP list_domains):
- pending: not verified yet. We keep re-checking. An unverified claim is released after 7 days, which frees the name for anyone to claim, so add it again if you need more time.
- verified: ownership and routing both check out, and HTTPS is on. We re-check every 30 minutes.
- dns_error: it was verified, but its DNS no longer checks out (a record was changed or deleted, or a proxy was switched on). The domain is not removed and keeps being served and renewed as long as traffic still reaches us, but fix the records. It returns to verified automatically once DNS is right again. One failed lookup doesn't flag a domain: it has to fail on two checks in a row.
Limits
- Custom domains per account (every app counts, pending ones too): Free 1, Hobby 3, Pro 10. Remove a domain to free a slot; the www/apex redirect twin doesn't count.
- Adding domains: up to 20 per hour per account. Manual verification: up to 30 per hour per account, and one check per domain every 10 seconds. Over the limit you get HTTP 429 with a
Retry-Afterheader. The automatic re-checks don't count. - The platform also caps the total number of certificate-issuing custom hostnames. If it were ever full, a domain with correct DNS stays pending and verifies automatically when there is room.
- Not supported yet: wildcard domains (
*.example.com), and domains behind Cloudflare's orange-cloud proxy.
If verify fails
TXT … not found: the record hasn't propagated yet, or the name is wrong. Many DNS panels add your domain automatically, so enter just_aloof-challenge.apirather than the full name. Check withdig TXT _aloof-challenge.api.example.com +short.CNAME points to …orresolves to …; expected …: the routing record points somewhere else. Remove old A/AAAA/CNAME records for the same name, turn off proxying (Cloudflare), and check withdig api.example.com +short. If you publish an AAAA record it must be ours too, or IPv6 visitors would land elsewhere; remove it or use the value we show.- "domain claimed by another account": someone already holds a verified claim, or a recent one, on that name. Unverified claims are released after 7 days, and another account can take over a pending claim older than an hour. If you own the domain and a verified claim is wrong, contact Support.
- Verified, but HTTPS shows a certificate error: give it a minute after the first request. CAA records on your domain must allow Let's Encrypt (
letsencrypt.org). Also,aloof certsshows the status.
CLI, API and MCP
aloof domains my-app add example.com | list | verify example.com | remove example.com
POST /v1/apps/<app>/domains {"domain": "example.com"}
POST /v1/apps/<app>/domains/<domain>/verify
GET /v1/apps/<app>/domains (one app) GET /v1/domains (whole account, with your limit)
DELETE /v1/apps/<app>/domains/<domain>
MCP tools: add_domain, list_domains, verify_domain, remove_domain
Each domain in the response carries status, last_checked_at, dns_records (ownership, routing, plus a, aaaa and recommended) and, for root or www domains, www_pair.