How to serve a static site on a custom subdomain with GitHub Pages.

1. Static Export

Your framework must output plain HTML/CSS/JS. No server required.

Next.js:

const nextConfig = { output: "export" };

Angular:

npx ng build --base-href /

The build output goes to a folder (out/, dist/). That folder is what GitHub Pages serves.

2. CNAME File

Put a file named CNAME in your build output root. One line, your subdomain:

sub.domain.com

GitHub reads this file to know which custom domain belongs to this repo. Without it, GitHub has no way to route sub.domain.com to your repo.

For Next.js, write it into out/ after build. For Angular, add it as an asset in angular.json so it copies to dist/ automatically.

3. GitHub Pages Settings

Settings > Pages > Custom domain > enter your subdomain > Save.

If the CNAME file is already in your gh-pages branch, GitHub fills this in automatically. Either way works.

Wait for GitHub to provision an HTTPS certificate. Takes up to 15 minutes.

4. DNS Records

Add a DNS record at your domain registrar (Squarespace, Cloudflare, etc.) pointing your subdomain to GitHub.

Option A: CNAME (recommended)

One record. GitHub changes IP, you don't touch anything.

sub  CNAME  youraccount.github.io

Option B: A records (alternative)

Four records. Harder to maintain. If GitHub changes IPs, you update manually.

sub  A  185.199.108.153
sub  A  185.199.109.153
sub  A  185.199.110.153
sub  A  185.199.111.153

For apex domains (domain.com, no subdomain prefix), you must use A records. CNAME on apex breaks other records like MX (email).

5. How GitHub Routes Multiple Subdomains

One GitHub Pages server handles all your subdomains. It differentiates by HTTP Host header.

Browser requests sub1.domain.com
  -> DNS resolves to GitHub IP
  -> HTTP header: Host: sub1.domain.com
  -> GitHub finds repo with CNAME file containing "sub1.domain.com"
  -> Serves that repo

Browser requests sub2.domain.com
  -> Same GitHub IP
  -> HTTP header: Host: sub2.domain.com
  -> GitHub finds a different repo
  -> Serves that repo

Multiple CNAME records can all point to the same youraccount.github.io. The CNAME file inside each repo is what separates them.

sub.youraccount.github.io does not work as a direct URL. GitHub Pages only routes by custom domain or youraccount.github.io/repo-name.

6. DNS Propagation Gotchas

"DNS check unsuccessful" but the site loads fine?

GitHub's own DNS resolver hasn't refreshed yet. Remove the custom domain, wait a few seconds, re-add it. This forces a fresh lookup.

Site doesn't load, dig sub.domain.com returns nothing?

Your local DNS resolver cached a "not found" (negative cache) from before the record existed. Try querying Google DNS directly:

dig sub.domain.com @8.8.8.8 +short

If Google returns IPs but your local doesn't, flush your local cache:

# macOS
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

Or switch your system DNS to 8.8.8.8 (Google) or 1.1.1.1 (Cloudflare). Faster and avoids ISP caching issues.

TLS certificate provisioning messages are normal:

TLS certificate is being provisioned.
This may take up to 15 minutes to complete.

Wait it out. Once done, enable "Enforce HTTPS" in GitHub Pages settings.