Connecting a Custom Domain to GitHub Pages — 4 Steps (Cloudflare DNS · CNAME · HTTPS · Re-Indexing)

A write-up of moving taystudio.github.io to taystudios.com on 2026-05-09. As of 6/5 the first 30 days of post-migration data are in, so I'm including the actual numbers too.

Why move

.github.io works fine. For Korean SEO specifically there's barely a difference. But four things bothered me.

  • Domain authority starts at zero.github.io is on the Public Suffix List, so browsers and search engines treat subdomains as separate sites. taystudio.github.io and someone.github.io are isolated from each other — good for safety, but authority never accumulates.
  • English AdSense RPM.github.io URLs read as "developer blog" in English-speaking markets, so general-audience CTR is low. RPM lands around $1~3. With .com people report $3~8.
  • Press / editorial backlinks — journalists and reputable blogs tend to skip .github.io URLs. Not perceived as a serious source.
  • Brand — having "github" in your URL just weakens brand recognition.

English market + AdSense + brand — all three were decisive levers for me. Timing matters most, though. Once you've got hundreds of URLs and backlinks pointing at the old domain, migration cost explodes. My site had ~100 URLs at the time, which was the right moment.

4-step overview

① Cloudflare DNS         (4 A records + CNAME www)
② GitHub repo CNAME file (1 line)
③ Site-wide rewrite      (canonical · sitemap · robots)
④ Re-index everywhere    (GSC · Naver · Bing · Daum)

Zero downtime. Both domains stay live during the transition.


1. Cloudflare DNS

I bought the domain at Cloudflare Registrar (any registrar works — Namecheap, Gandi, GoDaddy, etc.). DNS is also Cloudflare — fastest and free.

UI — where to click

  1. dash.cloudflare.com → click your site → left menu DNS → Records.
  2. Add record button → add the 5 records below:
Type Name Content (Value) Proxy status
A @ 185.199.108.153 DNS only (gray cloud)
A @ 185.199.109.153 DNS only
A @ 185.199.110.153 DNS only
A @ 185.199.111.153 DNS only
CNAME www <your username>.github.io DNS only

Type @ in the Name field and it auto-resolves to apex (taystudios.com). For www, just type www — Cloudflare expands it to www.taystudios.com.

Two traps

  • Register all 4 A records. GitHub Pages load-balances across 4 IPs. If you only set one, the site goes down whenever that IP does.
  • Start with DNS only (gray cloud). If you turn the proxy on (orange cloud), GitHub Pages' Let's Encrypt issuer can't reach the origin IP, and cert issuance fails. Turn proxy on after the cert is issued.

Verify

dig taystudios.com +short
# 185.199.108.153
# 185.199.109.153
# 185.199.110.153
# 185.199.111.153

dig www.taystudios.com +short
# taystudio.github.io.
# 185.199.108.153
# ...

Global resolver cache propagation typically takes 30 minutes to 24 hours. Mine resolved in Korea within an hour.


2. The CNAME file in your repo

This is the file that tells GitHub Pages "this repo serves this domain."

Make the file

At your repo root, create a file named exactly CNAME (no extension, all uppercase). One line inside:

taystudios.com

The apex domain, no www. Done.

GitHub UI side

  1. Repo page → top Settings tab.
  2. Left menu Pages.
  3. Custom domain field → enter taystudios.comSave.
  4. A few minutes later (5~30 min) you'll see ✓ DNS check successful.
  5. The Enforce HTTPS checkbox below becomes enabled — tick it.

If you enter the domain into Custom domain, GitHub creates the CNAME file at the repo root for you automatically. Creating it manually (step 1) does the same thing.

Let's Encrypt cert

GitHub auto-issues an SSL cert via Let's Encrypt. 5 to 30 minutes. Once issued, the Enforce HTTPS checkbox becomes clickable (was grayed out).

Auto-renewed every 90 days. Cost zero. Configuration zero.

→ After the cert is issued you can flip Cloudflare proxy on (optional).


3. Site-wide rewrite

The most SEO-critical part of the migration. If a single URL still points to the old domain, Google may keep treating the old domain as the canonical, and authority won't transfer.

What needs to change

Area Change
<link rel="canonical"> taystudios.com/...
<meta property="og:url"> same
<link rel="alternate" hreflang> same
<loc> in sitemap.xml same
Sitemap: URL in robots.txt same
llms.txt (if you have one) same
schema.org JSON-LD @id · url same
Absolute internal links taystudio.github.iotaystudios.com
IndexNow key file URL same

How I handled it

My build script (blog/scripts/build.py) reads site.json's siteUrl once and rewrites everything from that. One value changed, one build run, done.

If you don't have a build script:

# bulk-rewrite old domain → new domain
grep -rl "taystudio.github.io" . | xargs sed -i '' 's|taystudio.github.io|taystudios.com|g'

(macOS sed is -i '', Linux is -i)

Push to GitHub after the rewrite — auto-deploy from there.


4. Re-index everywhere

To Google · Naver · Bing · Daum, .com is a brand new domain. Data accumulated on the old property doesn't auto-transfer, so register fresh.

Google Search Console

  1. search.google.com/search-console → top-left Add property.
  2. Pick URL prefix → enter https://taystudios.com.
  3. Ownership verification — the HTML tag method is easiest. Grab the <meta name="google-site-verification" content="..."> line, drop it in <head>, build → verify.
  4. Left menu Sitemaps → enter sitemap.xml → submit.
  5. URL Inspection → enter URLs of priority pages (home · popular posts) → Request indexing. ~10/day quota.

→ Bing Webmaster Tools can auto-import sitemaps from GSC. Doing GSC also covers Bing.

  1. searchadvisor.naver.com → login → top-right Site management.
  2. Add sitehttps://taystudios.com.
  3. Ownership — download the HTML verification file, upload to your site root. Build → verify.
  4. Left menu Request → Submit sitemapsitemap.xml.
  5. Request → Crawl webpage → one URL per line (50/day).

→ Naver carries 80%+ of Korean-market traffic. If you target Korea, Naver is more urgent than GSC.

Bing Webmaster Tools

  1. bing.com/webmasters → log in with a Microsoft account.
  2. Add site → auto-import from GSC is recommended.
  3. From the old domain's property you can use Site Move to send an explicit move signal.

Daum Webmaster Tools (Korean — Kakao)

(Not called "SearchAdvisor". The UI menu is still labeled "Webmaster Tools". URL is webmaster.daum.net.)

  1. webmaster.daum.net → Kakao login.
  2. Add sitehttps://taystudios.com.
  3. Ownership — meta tag or a verification token added to the first line of robots.txt.
  4. Sitemap menu → submit sitemap.xml.
  5. Request crawl → individual URLs.

IndexNow (bonus)

Single ping to Bing · Yandex · Naver · Seznam. Generate a key once, drop the URL in robots.txt, done.

curl "https://api.indexnow.org/IndexNow?url=https://taystudios.com/&key=<your-key>"

What DNS and CNAME actually are

Worth understanding once — then the 4 steps above make sense.

DNS = phonebook

Humans remember names (taystudios.com); computers only know IPs (185.199.108.153). DNS translates name → IP.

How browsers find the IP (5 hops)

(when resolver cache is empty)

Browser
  → ISP DNS (KT · SKB · Google 8.8.8.8 ...)
  → Root nameserver (".")
  → TLD nameserver (".com")
  → Domain nameserver (Cloudflare)
  → A record response (185.199.108.153)

In practice the resolver caches results based on TTL (default 1 hour), so every lookup doesn't hit root. When you buy a new domain or change records, resolver caches around the world are empty and have to walk all 5 hops = DNS propagation.

A vs CNAME

A record — domain → IP directly:

taystudios.com   A   185.199.108.153

CNAME — domain → another domain (alias):

www.taystudios.com   CNAME   taystudio.github.io

When a resolver gets a CNAME it looks up the A record for that other domain. One extra hop, but the alias automatically follows whenever the target's IP changes.

CNAME at apex (zone root) — forbidden by RFC 1912

taystudios.com itself = no CNAME. It collides with other record types (MX · NS), and the standard forbids it. www.taystudios.com · blog.taystudios.com = CNAME OK.

→ That's why apex uses 4 A records and www uses CNAME. Cloudflare supports "CNAME flattening" to fake apex CNAME, but GitHub Pages' official recommendation is 4 A records.

Host header

GitHub Pages' 4 IPs (185.199.108~111.153) are shared across millions of sites. How does your site get served?

HTTP/1.1 GET /
Host: taystudios.com   ← this is the key

The browser sends a Host header → GitHub looks up CNAME file == "taystudios.com" internally and maps to your repo. → The 1-line CNAME file is the actual binding.


My measurements — 30-day sandbox window

Data from the 30 days after 5/9 migration:

Date GSC impressions Naver impressions
5/9 (migration) 0 (residual on old domain)
5/14 (Week 1) 450 peak spike begins
5/24 (Week 3) 10 (dip) 7,600 peak
6/2 (Week 4) ~0 2,000~3,000/day steady

Google clearly entered sandbox. 6~12 weeks expected. Naver has no sandbox — recovers immediately. Full retrospective in the Google Sandbox 30-day post.


If you're doing the same migration

  1. Move early, while URL count is low. Pre-backlink is the cheapest time. Once you have 100+ URLs, redirect / canonical work explodes.
  2. Zero downtime — both domains stay live. Visitors landing on the old domain get auto-redirected by GitHub to the new one (as long as the old repo's CNAME file is removed).
  3. Canonical consistency — bulk-rewrite with sed or your build script in one pass. If even one URL still points to the old domain, authority transfer fails.
  4. Don't panic looking at Google alone — sandbox keeps impressions near zero for ~a month. Naver · Bing · Cloudflare together show the site is actually fine.

The domain swap itself takes about an hour. Authority transfer is the 1~3 month wait.

Share𝕏f

Comments