I recently bought the domain got-a.page and turned it into a free, community-run subdomain service. Anyone can claim a name like yourname.got-a.page with one small JSON file and one pull request. No hosting bill, no registrar account, no ads, no tracking.
This guide walks through the whole thing: picking a name, choosing a mode, opening the PR, and what to expect after it merges.
What is got-a.page?
got-a.page gives you a free subdomain for your profile, product, project or community. Claims live in a public GitHub repo, one JSON file per page, and a maintainer merges them. There are two ways to use your name:
Instant mode - no website? We host the page for you.
Fill in your name, a tagline and your links, and a fast, accessible page is rendered at yourname.got-a.page. Light and dark mode included, in one of six themes: sunrise, lagoon, forest, plum, slate, ember. Person and product pages are supported today.
{
"mode": "instant",
"owner": { "github": "yourusername" },
"page": {
"type": "person",
"title": "Your Name",
"tagline": "What you're about, in one line",
"avatar": "https://github.com/yourusername.png",
"theme": "sunrise",
"links": [{ "label": "GitHub", "url": "https://github.com/yourusername" }],
"sections": [{ "heading": "About", "text": "A few sentences about you." }]
}
}
Point mode - already hosting somewhere?
Point your name at GitHub Pages, Vercel, Netlify, Cloudflare Pages, or anywhere that gives you a hostname or IP. CNAME, A, AAAA and TXT records are supported. One DNS rule to know: a CNAME can't be combined with other record types on the same name.
{
"mode": "point",
"owner": { "github": "yourusername" },
"purpose": "My portfolio",
"records": { "CNAME": "yourusername.github.io" }
}
You can switch modes later by editing your file with a new PR. And yes, it's really free: the domain is paid for years ahead and everything else runs on free tiers.
Before you start
- A GitHub account. Claims are tied to it:
owner.githubmust match the PR author, and only you (or a maintainer) can edit or remove your page later. - A name that's 2-40 characters of lowercase letters, numbers and hyphens.
- Up to 2 pages per GitHub account while we're young.
- Everything in the repo is public, forever. Don't put private data in your file.
Step 1: Open the guided claim form
Go to got-a.page/claim. The form writes the JSON for you, so you never touch raw JSON. There's a name checker on the homepage if you want to see whether your name is free first.
Step 2: Answer a few questions
Enter your page name, pick instant or point mode, and fill in the fields. Instant mode asks for your title, tagline, theme and links. Point mode asks for the DNS target your host recommends.
Step 3: Propose it on GitHub
The button at the end opens the claim repo on GitHub with your file prefilled. GitHub will ask you to fork (one click), then you choose "Propose changes" and open the pull request.
Automated validation checks review your file. Follow the check results on your PR - fork PRs don't get automatic bot comments, so the checks are where the feedback lives. A maintainer merges when it looks good.
Never made a pull request before? The repo's contributing guide walks you through every click. It's a kind place for your first one.
Step 4 (point mode only): connect your host before merge
This is the step people miss. A merged claim creates DNS records, but it does not add the domain to your hosting account. Add yourname.got-a.page on your host before the claim is merged:
-
GitHub Pages: your website repo > Settings > Pages > Custom domain, enter
yourname.got-a.page, Save. Use"records": { "CNAME": "yourusername.github.io" }in your claim. - Vercel: your project > Settings > Domains > Add Domain. Copy the project-specific CNAME target Vercel gives you into your claim.
-
Netlify: Domain management > Add a domain you already own. Keep external DNS and copy the recommended target (usually
your-site.netlify.app). -
Cloudflare Pages: your Pages project > Custom domains > Set up a domain. Use your
your-site.pages.devtarget.
The docs at got-a.page/docs have the full per-host walkthrough.
What to expect after your PR merges
Instant mode: your page goes live within a few minutes. Until the index republishes, your address may still show the "unclaimed" page - that's normal, give it a few minutes and hard-refresh.
Point mode: DNS publishes first, then your host verifies the domain and issues its HTTPS certificate. Browsers will show a privacy or certificate error for your address during that window. That's expected - minutes to hours, occasionally longer. GitHub documents up to 24 hours for Enforce HTTPS to become available; turn it on once you can.
One HTTPS note: .page is on the HSTS preload list, so browsers force HTTPS on every got-a.page address. Instant pages are always secure (handled for you), and point-mode targets must serve valid HTTPS or browsers will refuse to load them. All the hosts above do that automatically once the custom domain is added.
"Is it broken?" - troubleshooting
| What you see | What's going on |
|---|---|
| Certificate/privacy error right after merge (point mode) | Normal. Your host's certificate isn't ready yet. Wait, then enable Enforce HTTPS when offered. |
Your old yourname.github.io shows the same error |
Expected. GitHub Pages redirects the old address to your custom domain as soon as you save it, so both show the error during the wait and both recover together. |
| Your address still says "unclaimed" (instant mode) | The index hasn't republished yet. A few minutes, then hard-refresh. |
| Page loads but looks unstyled | Your site is loading CSS/JS from the old address or over http://. Use relative asset URLs or update your static site generator's base URL setting. |
| Still stuck after a day | Open an issue in the claim repo with your page name and what you see. Real humans read them. |
The rules, short version
- Claim with your own GitHub account.
- Your page is public. Everything in the repo is public.
- No phishing, scams, malware, impersonation, illegal or adult content.
- Some names are reserved (service addresses, brand names, and words that would make the place less welcoming).
- See abuse? Email
abuse@got-a.page.
Extras
Badges: once your page is live, grab an "I got a page" or "Launched on got-a.page" badge from got-a.page/badges - HTML and Markdown snippets, ready to paste into your README.
What's coming later: more page types (project, community and event templates), a Wall of Pages gallery, and email on your subdomain. None of that is live yet - I'm adding it in later phases, and everything above is what works today.
Wrap up
- Check your name on got-a.page
- Claim it at got-a.page/claim
- Open the PR, follow the checks, done
Claim repo: github.com/got-a-page/claim - MIT licensed, and issues and first PRs are welcome. If you claim a page, drop your new address in the comments. I'd love to see what you make of it.
Top comments (2)
Hey Dhanush! 👋😊
First of all, congratulations on launching got-a.page! I really like the idea of combining free subdomains, GitHub pull requests, and GitOps-based DNS management.
I was curious about the implementation, so I downloaded your claim repository and spent some time reviewing the validation logic, ownership checks, and DNS synchronization code.
I found a few things worth sharing. 🔍
🔴 1. IPv6 validation accepts malformed addresses
In scripts/src/lib/ips.ts, the current implementation is:
This checks the character set but doesn’t validate IPv6 syntax.
For example, a:b, ::::, and abcd: can pass this function despite being invalid IPv6 addresses.
I’d recommend using Node.js’s built-in net.isIP() instead:
This is directly verifiable from the source.
🟠 2. Git reference loading may fail to enumerate existing claims
In scripts/src/lib/store.ts, loadPagesAtRef() uses:
Without -r, git ls-tree doesn’t recursively enumerate the JSON files inside pages/.
Since the following loop only processes paths ending in .json, existing claims may not be loaded as intended.
Additionally, Git errors are caught and converted into an empty map.
Because this function supplies historical claim data for PR comparisons, I’d recommend investigating its effect on ownership validation.
A safer starting point would be:
I’d also distinguish a genuinely empty directory from a failed Git operation.
🔴 3. DNS synchronization has a potentially broad deletion boundary
In scripts/src/dns-sync.ts, the reconciliation logic includes:
This means any record classified as managed but absent from the desired state becomes a deletion candidate.
That approach can be valid for an exclusively managed DNS zone.
However, if multiple automation systems share the same zone or management marker, the deletion scope deserves additional protection.
I’d recommend explicitly verifying ownership and management scope before destructive operations.
To be clear, I haven’t demonstrated an unintended deletion against your live Cloudflare zone. This is an architectural risk identified through code inspection.
🟠 4. IP address classification could be more robust
The IPv4 and IPv6 restrictions currently rely on manually maintained regular expressions and prefix checks.
For example, the IPv4 exclusions don’t comprehensively cover all special-purpose address ranges, including 240.0.0.0/4.
Using standard IP parsing and an explicit address-classification policy would make this easier to maintain and test.
🟡 5. DNS reconciliation isn’t atomic
The synchronization process performs create, update, and delete operations sequentially.
If an API request fails halfway through, the zone may temporarily remain in a partially updated state.
I’d consider adding stronger failure reporting, post-apply verification, and recovery tests.
This isn’t necessarily a bug, but it’s important for operational reliability.
✅ What I liked
There are also several good engineering decisions here:
These are sensible foundations for a community project.
My suggested priorities:
One important limitation: my review covered the supplied claim repository, not the complete production infrastructure. I haven’t audited the Instant Mode Worker, live Cloudflare permissions, or the deployed GitHub branch protection settings.
So these are source-level findings and architectural recommendations, not claims that your production service has been compromised.
Overall, I appreciate the transparency and simplicity of the project. Making a useful service free and approachable while encouraging people to learn GitHub contributions is a great initiative.
I hope these findings are helpful. I’m sharing them constructively because I genuinely like what you’re building.
Keep up the good work, Dhanush! 🌱🔐
Thanks for the points
Feel free to add the suggested things as issues in the repository so it will be easy to track.