Connecting a Custom Domain to GitHub Pages — 4 Steps (Cloudflare DNS · CNAME · HTTPS · Re-Indexing)
This is a write-up of how I moved taystudio.github.io over to taystudios.com back 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 alongside the steps.
Why move
To be honest, .github.io works perfectly fine. For Korean SEO specifically there's barely any difference. Even so, four things kept nagging at me, and in the end they were enough to make me move.
- Domain authority starts at zero.
.github.iois on the Public Suffix List, so browsers and search engines treat its subdomains as separate sites. That's howtaystudio.github.ioandsomeone.github.iostay isolated from one another — safe, sure, but it also means your authority never really accumulates. - English AdSense RPM is the one I cared about. In English-speaking markets a
.github.ioURL reads as "developer blog," so the general-audience CTR is low. RPM tends to sit around$1~3, whereas with a.comI've seen people report$3~8. - Press and editorial backlinks work against you too. Journalists and reputable blogs tend to skip
.github.ioURLs — they just don't read as a serious source. - And finally there's brand. Having "github" sitting in your URL weakens brand recognition all on its own.
The English market, AdSense, and brand — all three were decisive for me, so I went ahead and moved. The one thing I'd really stress, though, is timing. Once you've got hundreds of URLs and backlinks pointing at the old domain, the cost of migrating explodes. My site had around 100 URLs at the time, and in my experience that's about the sweet spot for making the move.
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)
There was zero downtime throughout. Both domains stay live and the transition happens gradually.
1. Cloudflare DNS
I bought the domain at Cloudflare Registrar, though honestly any registrar works — Namecheap, Gandi, GoDaddy, whatever you like. I kept DNS on Cloudflare too, since in my experience propagation is fastest there and it's free, so there was no reason to move it elsewhere.
UI — where to click
- Log in at dash.cloudflare.com, click your site, and go to DNS → Records in the left menu.
- Hit the
Add recordbutton and 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 the apex (taystudios.com). For www, just type www and Cloudflare expands it to www.taystudios.com.
Two traps
There are two traps here that I either hit or came close to hitting.
- Register all 4 A records. GitHub Pages load-balances across these 4 IPs, so if you only set one, the whole site goes down whenever that single IP does.
- Start with DNS only (gray cloud). If you flip the proxy on (orange cloud) too early, GitHub Pages' Let's Encrypt issuer can't reach the origin IP and cert issuance fails. It's safest to turn the proxy on only after the cert has been 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
# ...
Propagating to resolver caches around the world usually takes anywhere from 30 minutes to 24 hours. In my case it resolved within Korea inside an hour.
2. The CNAME file in your repo
This is the file that tells GitHub Pages "this repo serves this domain," and it really is the heart of the whole setup.
Make the file
At your repo root, create a file named exactly CNAME — no extension, all uppercase. Put a single line inside.
taystudios.com
The apex domain, no www. That's all it is.
GitHub UI side
- Go to your repo page and open the Settings tab at the top.
- Pick Pages in the left menu.
- In the Custom domain field, enter
taystudios.comand hit Save. - A few minutes later (5~30 min) you'll see the
✓ DNS check successfulmessage. - Once the Enforce HTTPS checkbox below it becomes enabled, tick it.
When you enter the domain into Custom domain, GitHub creates the CNAME file at your repo root for you automatically. Creating it by hand (step 1) does exactly the same thing.
Let's Encrypt cert
GitHub auto-issues an SSL cert through Let's Encrypt. It usually takes 5 to 30 minutes, and once it's issued the Enforce HTTPS checkbox, which was grayed out, becomes clickable.
It auto-renews every 90 days, costs nothing, and there's no configuration to do.
→ After the cert is issued you can head back to Cloudflare and flip the proxy on if you want (it's optional).
3. Site-wide rewrite
This is the most SEO-critical part of the migration. If even a single URL still points to the old domain, Google can end up treating that old domain as the canonical, and your authority simply 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.io → taystudios.com |
| IndexNow key file URL | same |
How I handled it
I'd written my build script (blog/scripts/build.py) so that it reads site.json's siteUrl once and rewrites everything from that single value. So I changed that one line, ran the build once, and it was done.
If you don't have a build script, sed will do the job.
# bulk-rewrite old domain → new domain
grep -rl "taystudio.github.io" . | xargs sed -i '' 's|taystudio.github.io|taystudios.com|g'
(On macOS sed is -i '', on Linux it's -i.)
Once the rewrite is done, push to GitHub and it auto-deploys from there.
4. Re-index everywhere
To Google · Naver · Bing · Daum, a .com looks like a brand new domain. The data accumulated on the old property doesn't transfer automatically, so you have to register fresh.
Google Search Console
- Go to search.google.com/search-console and click Add property in the top-left.
- Pick URL prefix and enter
https://taystudios.com. - Verify ownership. Of the various methods, the HTML tag one is easiest — grab the
<meta name="google-site-verification" content="...">line, drop it into<head>, build, and verify. - In the left menu under Sitemaps, enter
sitemap.xmland submit. - Under URL Inspection, enter the URLs of your priority pages (home · popular posts) and hit Request indexing. There's a quota of about 10 a day.
→ Bing Webmaster Tools can auto-import sitemaps from GSC, so doing GSC tends to cover Bing as well.
Naver SearchAdvisor (Korean market)
- Log in at searchadvisor.naver.com and open Site management in the top-right.
- Under Add site, enter
https://taystudios.com. - For ownership, download the HTML verification file, upload it to your site root, build, and verify.
- In the left menu, go to Request → Submit sitemap and add
sitemap.xml. - Under Request → Crawl webpage, add one URL per line (50/day).
→ Naver carries 80%+ of Korean-market traffic, so for me Naver was actually more urgent than GSC.
Bing Webmaster Tools
- Log in at bing.com/webmasters with a Microsoft account.
- Under Add site, the recommended route is to auto-import from GSC.
- If you have the old domain's property, you can use Site Move to send an explicit move signal.
Daum Webmaster Tools (Korean — Kakao)
(It's not called "SearchAdvisor." The UI menu is still labeled "Webmaster Tools," and the URL is webmaster.daum.net.)
- Log in at webmaster.daum.net with a Kakao account.
- Under Add site, enter
https://taystudios.com. - For ownership, use a meta tag, or add a verification token to the first line of
robots.txt. - In the Sitemap menu, submit
sitemap.xml. - Under Request crawl, add your individual URLs.
IndexNow (bonus)
This sends a single ping to Bing · Yandex · Naver · Seznam at once. You generate a key just once, drop the URL in robots.txt, and you're done.
curl "https://api.indexnow.org/IndexNow?url=https://taystudios.com/&key=<your-key>"
What DNS and CNAME actually are
When you're in the middle of a migration it's easy to start wondering what any of this even means, so I'll lay it out once. Once it clicks, you can see why the 4 steps above are shaped the way they are.
DNS = phonebook
People remember names (taystudios.com), but computers only know IPs (185.199.108.153). DNS is the thing that translates the name into the IP.
How browsers find the IP (5 hops)
(this is with an empty resolver cache)
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, of course, the resolver caches results based on TTL (default 1 hour), so not every lookup climbs all the way to root. But when you buy a new domain or change a record, resolver caches around the world are empty and have to walk all 5 hops — and that's exactly what DNS propagation is.
A vs CNAME
An A record points a domain directly at an IP.
taystudios.com A 185.199.108.153
A CNAME points a domain at another domain (an alias).
www.taystudios.com CNAME taystudio.github.io
When a resolver gets a CNAME, it goes and looks up the A record for that other domain. It's one extra hop, but the upside is that the alias automatically follows along whenever the target's IP changes.
CNAME at apex (zone root) — forbidden by RFC 1912
taystudios.com itself can't take a CNAME. It collides with other record types (MX · NS), so the standard forbids it.
On the other hand, www.taystudios.com · blog.taystudios.com can use CNAME just fine.
→ That's why the apex uses 4 A records and www uses a CNAME. Cloudflare can fake an apex CNAME with "CNAME flattening," but GitHub Pages' official recommendation is the 4 A records.
Host header
GitHub Pages' 4 IPs (185.199.108~111.153) are shared across millions of sites. So how does yours, of all of them, get served?
HTTP/1.1 GET /
Host: taystudios.com ← this is the key
It comes down to the Host header the browser sends, working together with GitHub looking up the repo whose CNAME file == "taystudios.com" internally and mapping to it. So in the end, that 1-line CNAME file in your repo is what really does the binding.
My measurements — 30-day sandbox window
Here's the data from the 30 days following the 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 |
You can clearly see Google enter its sandbox — expect 6~12 weeks of it. Naver, on the other hand, has no sandbox, so it recovered right away. I've written up the full retrospective on this separately in the Google Sandbox 30-day post.
If you're doing the same migration
If you're about to do the same move, these are the four things I'd keep in mind after going through it myself.
- Move early, while your URL count is still low. Before the backlinks land is the cheapest moment. Once you're past 100+ URLs, the redirect and canonical work explodes.
- Zero downtime. Both domains stay live at the same time, so even if a visitor lands on the old domain, GitHub auto-redirects them to the new one (as long as you've cleared the CNAME file in the old repo).
- Canonical consistency matters. Whether you use sed or your build script, rewrite everything in a single pass. If even one URL still points to the old domain, authority transfer fails.
- Don't panic looking at Google alone. Because of the sandbox, impressions sit near zero for about a month. Only when you look at Naver · Bing · Cloudflare together can you see that the site is actually running just fine.
The domain swap itself is about an hour of work. It's just the authority transfer that takes a 1~3 month wait.
Related posts
- Google Sandbox After 30 Days — GSC · Naver · Cloudflare tracking
- Naver SearchAdvisor — Complete Registration Guide — 80% of Korean-market traffic
- GSC vs Naver vs Cloudflare — three data sources compared
Comments