runs-on.dev README

The project's README from github.com/zordhalo/runs-on.dev. As one markdown file: README.md.

runs-on.dev

runs-on.dev

Free subdomains for developers. Claim yourname.runs-on.dev in seconds, then point it wherever you like.

Claim a name  ·  Quickstart  ·  Guides  ·  Records  ·  Policy

stars names claimed tests license: AGPL-3.0


Claiming a name writes one file to this repository. That file is the record. It is the only thing that makes the name resolve, and you can read it without asking anyone.

{
  "name": "yourname",
  "owner": { "github": "yourname" },
  "claimedAt": "2026-01-01T00:00:00.000Z",
  "records": {}
}

There is no hidden database. The registry is this directory, the history is the git log, and the rules are in lib/.

Why this exists

A real top-level domain means an ICANN application. The 2026 round's evaluation fee alone is $227,000, before you've built or run a registry to back it. That's not a plausible way to get a custom-looking address for a side project.

runs-on.dev gets the same feeling: a distinctive ending instead of vercel.app or github.io, for the price of one domain, about $10 a year, by giving away subdomains under it. This is a subdomain registry, not a TLD. Every name you claim lives under runs-on.dev, which Advance Labs registered and is responsible for. Saying that plainly, instead of dressing it up as something bigger, is the whole basis for trusting it. There's prior art doing exactly this: is-a.dev, js.org, eu.org.

Claim a name

Go to runs-on.dev, sign in with GitHub, and type the name you want. If it's available, claiming it writes a record to domains/<name>.json in this repo, as shown above, and the name is live within seconds. One name per GitHub account. See docs/claiming.md for eligibility rules, the per-account limit, and why they exist.

Point it at your own hosting

By default a claimed name serves a small profile card built from your GitHub account. To point it at your own site, forward email, or a plain redirect instead, there are two ways to change its record.

From the site. Sign in and open runs-on.dev/manage. Pick a record type, fill it in, and save. That writes a commit to domains/<name>.json in this repository, exactly as a merged pull request would, and DNS follows within seconds. The form offers the record types in the combinations DNS actually permits, so it cannot build a record the schema would reject.

By pull request. Still supported, and the right choice when you want the change reviewed before it lands:

  1. Fork this repo.
  2. Edit domains/<name>.json, adding a record under records (and optionally subdomains, for a one-level-deep entry like _atproto).
  3. Open a pull request. CI validates the change against schema/record.schema.json; once it's green and merged, a workflow pushes the record to DNS automatically.

Both paths enforce the same rules, from the same code in lib/edit.js: only the owner may change a record, and owner, claimedAt, and name are immutable once set.

Type Shape Coexistence
CNAME a hostname string Alone: cannot sit next to A, TXT, or MX.
A 1+ IPv4 addresses With TXT, MX.
TXT 1+ strings, up to 255 chars each With A, MX.
MX 1 to 5 { priority, value } entries With A, TXT.
URL one absolute http(s):// string Alone: cannot sit next to anything, not allowed under subdomains.

Nine hosting providers, a URL redirect, email forwarding, a Bluesky handle, and Discord verification, each with the exact record to copy, are in docs/guides.md. The same walkthroughs render on the site at /docs/guides/<provider> with more detail per provider; the markdown file is the compact version for reading here.

Once a name serves your own site, docs/seo.md covers what changes when that site lives on a subdomain: robots.txt and sitemaps are per host rather than per domain, redirect names cannot rank, and a name needs its own Search Console property.

Two worked examples

Vercel, the shortest path from claim to a live custom domain:

"records": { "CNAME": "cname.vercel-dns.com" }

Add you.runs-on.dev as a custom domain on the Vercel project; it shows you this same CNAME target.

A Bluesky handle, which needs no hosting at all, just a subdomain entry:

"subdomains": {
  "_atproto": { "TXT": ["did=did:plc:abc123"] }
}

Full record reference, the subdomains grammar, and why CNAME can't coexist with anything else: docs/records.md.

How it works

A single wildcard *.runs-on.dev DNS record points every possible subdomain at one Vercel project, so an unclaimed or record-less name still resolves with a valid HTTPS certificate and gets served the profile-card page. Claiming a name is therefore a git commit, not a DNS write. Pointing a name at your own hosting merges a record into domains/<name>.json, and a GitHub Actions workflow pushes that exact record to Vercel's DNS API on merge, which then takes priority over the wildcard for that one name. More detail, including the two write paths and the token split, in docs/architecture.md.

The rules

Everything CI checks on a domains/** pull request, so you can verify a PR yourself before opening it:

See lib/pr.js for the implementation CI actually runs, and docs/contributing.md for the full breakdown of what it checks.

Self-hosting

This is an open registry, not a hosted product with a private backend. Running your own copy under a domain you own means:

  • Fork this repo and rename it; REGISTRY_REPO in .env.example points at wherever the fork lives.
  • Register your own domain, point a wildcard record at your deployment, and add it to Vercel (or adapt scripts/sync-dns.mjs and lib/dns.js for a different DNS provider).
  • Change ROOT in proxy.js and the hostname literals in app/page.jsx and app/sites/[name]/page.jsx from runs-on.dev to your domain.
  • Create your own GitHub OAuth app and set GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET.
  • Review data/reserved-*.json and adjust lib/eligibility.js for your own abuse tolerance.
Local development
npm install
npm run dev

The claim flow needs a signed-in GitHub session, and the session and OAuth cookies are set Secure (see app/api/auth/github/route.js and .../callback/route.js). A Secure cookie is dropped by the browser over plain HTTP, so the GitHub sign-in flow cannot be exercised on http://localhost. This is correct for production: runs-on.dev is on the HSTS preload list, so it's always HTTPS there, and a cookie that only ever travels over HTTPS shouldn't get a Secure-free code path just for local convenience.

To exercise sign-in locally, serve the app over HTTPS with a locally-trusted certificate, mkcert being the simplest way:

mkcert -install
mkcert localhost

Then run next dev behind a TLS-terminating proxy pointed at it, and set APP_ORIGIN to the https:// URL you're serving from so the OAuth redirect URI matches. Everything that doesn't touch sign-in, name validation, schema checks, the blocklist, the record UI, works over plain http://localhost without any of this. See .env.example for every variable the app reads.

Star the registry

Every name claimed here is one commit in this repo, authored under the claimant's own GitHub account. If you have a name, you're already in the log — a star keeps the registry easy for the next person to find.

Contributing

Bug fixes, blocklist additions, and doc improvements are welcome. See docs/contributing.md for how to add to the blocklists, run the tests, and what CI checks.

npm install
npm test

License

The code in this repository is AGPL-3.0 licensed. It is a network service, so section 13 applies: run a modified copy and let other people use it over a network, and you owe those users your source. Using the registry, or claiming a name, carries no such obligation — this binds people who fork and host the software, not people who point a subdomain at their site.

Up to commit 3492bf7 the code was MIT, and that grant still stands for the code as it was then; see NOTICE.

The bundled profanity blocklist (data/reserved-words.json) is seeded from LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words (English list) and keeps its own CC BY 4.0 license; see data/README.md.

Credits

The idea of giving away free subdomains under one registered domain isn't new; credit to is-a.dev for the prior art, and to js.org and eu.org for more of it.


Operated by Advance Labs, which registered runs-on.dev and is the party responsible for what runs under it. See POLICY.md.

runs-on.dev (zordhalo/runs-on.dev)

Searching Database…

这是什么?一个免费的子域名注册库——几秒钟就能认领一个「yourname.runs-on.dev」子域名并把它指向任何你想要的地方,认领记录本身以文件形式存放在这个 GitHub 仓库里。
这是真正的顶级域名注册商,还是别的东西?它是一个子域名注册库,不是顶级域名:每个被认领的名称都在 runs-on.dev 这一个域名之下,而这个域名确实由运营方(Advance Labs)拥有并通过 ICANN 注册。
我怎么认领自己的名称?访问 runs-on.dev,用 GitHub 登录,输入你想要的名称;如果它还没被占用,认领操作会向这个仓库的 domains/ 文件夹写入一条 JSON 记录,名称会在几秒内生效解析。
认领名称需要满足什么条件?只需要一个 GitHub 账户:注册时间至少 30 天、至少有一个公开仓库,并且还没有在注册库里持有名称。
我可以抢注多个名称,或者之后再改名吗?不行——每个 GitHub 账户严格只能持有一个名称,重命名现有记录会被直接拒绝;你只能去认领一个全新的名称。
AGPL-3.0 许可证有什么需要注意的地方?代码采用 AGPL-3.0,所以如果你 fork 后把修改过的副本当作网络服务提供给他人使用,就必须向他们提供源代码;而仅仅认领名称或使用这个公共注册库并不承担这种义务。
认领名称在幕后实际上是怎么运作的?默认情况下,一条通配符 DNS 记录把所有可能的子域名都指向同一个 Vercel 项目,所以认领本质上只是向 domains/*.json 提交一次 git commit。当你把某个名称指向自己的托管时,一个 GitHub Actions 工作流会在合并时把那条特定记录推送到 Vercel 的 DNS API,只为该名称覆盖通配符记录。
我可以把认领的名称指向哪些记录类型?CNAME、A、TXT、MX 或普通的 URL 重定向,每种都有由 schema 强制执行的共存规则——比如 CNAME 不能与 A、TXT 或 MX 并存,URL 不能与任何类型共存。
我可以在别的域名下运行自己的注册库版本吗?可以——fork 这个仓库,注册你自己的域名,把通配符 DNS 记录指向你的部署,创建你自己的 GitHub OAuth 应用,并根据自己的审核需求调整保留词和资格规则。
为什么不干脆注册一个真正的顶级域名?真正的顶级域名需要向 ICANN 申请,仅 2026 年的评估费就高达 227,000 美元,之后你才能运营注册局;而 runs-on.dev 只花每年约 10 美元,通过在运营方拥有的一个域名下发放子域名,就得到了同样独特的地址。
Creator
zordhalo
Size
5.4 MB
Stars
453
Updated
CommitOct 18
Age
1mo
Commits · 90 Days