Use a free runs-at.dev subdomain with GitHub Pages
Your Pages site already lives at a github.io address. This guide gives it a shorter, memorable one on runs-at.dev instead, at no cost, with a certificate issued by GitHub.
What you'll end up with
Suppose your GitHub account is octo-dev and your site currently loads at https://octo-dev.github.io. When you finish, https://octo.runs-at.dev shows the same site. GitHub keeps hosting and building it exactly as before; the only thing that changes is the address visitors type. That is the whole idea of a free subdomain for GitHub Pages: a custom-looking address without buying and renewing a domain of your own.
Two settings make it work, one on each side. runs-at.dev publishes a DNS record that sends octo.runs-at.dev to GitHub, and GitHub Pages is told that it should answer for that name. If either half is missing, the address will not show your site.
Before you start
- A GitHub Pages site that already works at its github.io address. Fix that first; a custom address cannot repair a site that is not publishing.
- A runs-at.dev name claimed with the same GitHub sign-in you will manage it with. If you do not have one yet, the quickstart covers claiming. Every account includes one free name, and the administrator can grant more if you need a separate address for another project.
- Admin access to the repository that publishes the site, since the custom-domain setting lives in that repository.
You do not need a Cloudflare account or a DNS provider of your own. runs-at.dev runs the DNS for every name under it and publishes your record for you.
Add the DNS record
GitHub Pages expects a custom subdomain to be a CNAME pointing at your account's github.io host. Use your user or organization name followed by .github.io, with no https:// and no path after it. This is true for project sites as well: a repository published at octo-dev.github.io/portfolio still takes octo-dev.github.io as its CNAME target, because GitHub routes by the requested hostname, not by the path.
domains/octo.json
"records": { "CNAME": "octo-dev.github.io" }There are two ways to save it. Both end in the same commit to the registry.
- From the dashboard. Sign in at runs-at.dev/manage, choose the name if you own more than one, open
Point to my hosting, pickGitHub Pages, and save. The target is prefilled from your GitHub login; change it if the site belongs to an organization. - By pull request. Fork the registry, set the
recordsblock indomains/octo.jsonas shown above, and open a pull request. Automated checks confirm you own the file before it can be merged, and the record is published to DNS once it lands.
A CNAME has to be the only record on the name, so it replaces a URL redirect or any A, AAAA, TXT or MX records you had set. The record reference explains which records can share a name.
Configure GitHub Pages
- Open the repository that publishes the site and go to Settings → Pages.
- Under Custom domain, type
octo.runs-at.dev(your full name, including.runs-at.dev) and press Save. - Wait for the DNS check on that page to finish. GitHub looks up your name and expects to find the CNAME you published in the previous step.
If the site publishes from a branch, GitHub records the custom domain by committing a file named CNAME to the root of that publishing source. Keep it; deleting or overwriting it removes the custom domain. If the site is built and deployed by a GitHub Actions workflow instead, the setting in Settings → Pages is what counts and a CNAME file is not needed.
Note
The order does not matter. You can save the Pages setting before or after the runs-at.dev record goes live; GitHub simply keeps re-checking until the two agree.
Enable HTTPS
GitHub requests a certificate for octo.runs-at.dev on its own once the DNS check passes. While that is in progress the Enforce HTTPS checkbox is unavailable. When it becomes clickable, tick it so that plain http:// requests are sent to the secure address.
Nothing needs to be done on the runs-at.dev side. The record is published as plain DNS, not behind a proxy, so the certificate request reaches GitHub directly.
Check that it works
- Settings → Pages reports a successful DNS check and shows your runs-at.dev address as the live site.
- runs-at.dev/manage has a status panel under each name. It reads
Livewith your page's title once visitors get your site, andNot working yetwhile they still get the profile card. - runs-at.dev/debug/octo (with your own name) is a public diagnosis page. It shows the record, what DNS answers right now, what the name serves, and which step is missing if it is stuck. It is a link you can paste into an issue.
- From a terminal, the CNAME should name your github.io host:
dig +short octo.runs-at.dev CNAME
# octo-dev.github.io.Common problems
- The address still shows the runs-at.dev profile card
- DNS reaches GitHub, but GitHub has not been told to answer for this name. Check that Settings → Pages lists
octo.runs-at.devexactly, in the repository that publishes the site. Right after saving, the record may also still be spreading; the status panel says so while it waits. - The dashboard refuses the target
- Enter the host only, like
octo-dev.github.io, withouthttps://or anything after the address, and not your own runs-at.dev name. - GitHub's DNS check fails
- Confirm the CNAME targets your github.io host, with the account name spelled exactly as it appears in your github.io address. A target that includes a repository path or a typo in the account name will not pass.
- Enforce HTTPS stays unavailable
- The certificate is only requested after the DNS check succeeds, so resolve that first. If DNS is correct and the option is still greyed out, removing the custom domain in Settings → Pages and adding it again makes GitHub start over.
- Nothing loads at all
- The status panel reports
Not answeringwhen the address the record points at does not respond. Open the github.io address directly; if that fails too, the problem is with the Pages deployment rather than the domain.
Warning
Moving the name to another host later means changing this record. GitHub will keep the custom domain in Settings → Pages until you remove it there as well.