GitHub Pages custom domain with Cloudflare DNS

A practical setup guide for connecting a GitHub Pages site to a Cloudflare-managed custom domain, including A records, CNAME, proxy status, HTTPS, and common Search Console errors.

Connecting GitHub Pages to a Cloudflare-managed domain looks simple until it fails. The same few symptoms keep appearing:

This guide is the checklist I would use before debugging anything else.

The short version

For an apex domain such as example.com, GitHub Pages expects the domain to be configured in the repository settings and DNS to point at GitHub Pages. GitHub documents four A records for the apex domain:

185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153

GitHub also documents optional AAAA records for IPv6, but recommends keeping A records as well because IPv6 adoption is not universal.

For www.example.com, use a CNAME that points to the GitHub Pages default domain:

www  CNAME  <username>.github.io

Do not point the CNAME to a repository path such as <username>.github.io/my-repo. GitHub’s docs call out that the CNAME should point to the user or organization Pages domain without the repository name.

The order matters

The safest order is:

  1. In GitHub, open the repository.
  2. Go to Settings → Pages.
  3. Add the custom domain.
  4. Add or confirm the CNAME file if your publishing flow needs it.
  5. Add DNS records in Cloudflare.
  6. Wait for DNS propagation.
  7. Enable Enforce HTTPS when GitHub makes it available.

GitHub’s docs recommend adding the custom domain to the Pages settings before configuring DNS. The reason is security: a domain that points to GitHub Pages but is not claimed by the intended repository may create takeover risk.

Cloudflare DNS records

For the apex domain:

Type Name Content Proxy status
A @ 185.199.108.153 Proxied or DNS only
A @ 185.199.109.153 Proxied or DNS only
A @ 185.199.110.153 Proxied or DNS only
A @ 185.199.111.153 Proxied or DNS only

For www:

Type Name Content Proxy status
CNAME www <username>.github.io Proxied or DNS only

For Google Search Console or Bing verification:

Type Name Content Proxy status
TXT @ google-site-verification=... DNS only
TXT @ msvalidate.01=... DNS only

Cloudflare explains that only A, AAAA, and CNAME records can be proxied. Other records, including TXT, are DNS-only. It also says records used for domain ownership verification should not be proxied.

Should the Cloudflare proxy be on?

For ordinary web traffic, Cloudflare recommends proxying records that serve web traffic. A proxied record routes HTTP and HTTPS traffic through Cloudflare, which enables caching, WAF rules, redirects, and Cloudflare analytics.

But there are two practical cautions:

  1. If GitHub Pages is still validating the custom domain, switching to DNS-only temporarily can make the DNS target easier to inspect.
  2. Verification records such as TXT records are not web traffic and should remain DNS-only.

For a static blog, I would start with the simplest setup that passes GitHub Pages validation. Once the domain is stable and HTTPS works, turn on the proxy if you want Cloudflare caching, redirect rules, or WAF controls.

How to verify DNS from the terminal

Use dig to check whether the apex domain points to GitHub Pages:

dig example.com +noall +answer -t A

Expected shape:

example.com.  300  IN  A  185.199.108.153
example.com.  300  IN  A  185.199.109.153
example.com.  300  IN  A  185.199.110.153
example.com.  300  IN  A  185.199.111.153

Check www:

dig www.example.com +noall +answer

Expected shape:

www.example.com.  300  IN  CNAME  <username>.github.io.

If Cloudflare proxy is enabled, you may see Cloudflare anycast IPs instead of GitHub’s IPs. That is normal for proxied records. When you need to debug the raw DNS target, temporarily switch the record to DNS-only.

Common errors

“Both domain and alternate name are improperly configured”

This usually means GitHub Pages cannot confirm that the apex domain and its alternate form resolve to the expected Pages target. Check both example.com and www.example.com, not just one.

The smallest checklist:

  1. GitHub Pages custom domain is set to the final domain.
  2. The apex domain has the four GitHub Pages A records or an equivalent ALIAS/ANAME.
  3. www points to <username>.github.io, not a repository path.
  4. No stale A, AAAA, CNAME, or wildcard records conflict with the setup.
  5. DNS has had time to propagate.

GitHub notes that DNS changes can take up to 24 hours to propagate.

Search Console says the sitemap cannot be fetched

Check the sitemap directly:

curl -I https://example.com/sitemap-index.xml
curl -Ls https://example.com/sitemap-index.xml

If the response is 200 and the content type is XML, the file itself is probably fine. Search Console can still show a temporary fetch error soon after DNS, HTTPS, or sitemap changes. Submit the child sitemap as a fallback only if the index remains unavailable:

https://example.com/sitemap-0.xml

The site redirects to /repo-name

That usually means the static site was still built with the old GitHub Pages project base path. For Astro, make sure the production config uses the custom domain site URL and does not keep a repository base path after moving to an apex domain.

For a custom domain:

export default defineConfig({
  site: "https://example.com",
});

For a project page under https://username.github.io/repo-name, a base path can be correct. For https://example.com, it is usually wrong.

My setup rule

For a static blog on GitHub Pages and Cloudflare, I would use:

That setup keeps URLs clean, lets search data accumulate on the root domain, and leaves room to migrate later without changing article URLs.

Sources

For the hosting platform decision, read Vercel vs Cloudflare Pages vs GitHub Pages: Which Free Static Hosting Is Actually Free?. For the SEO side, read GitHub Pages SEO for Blogs: Is Static Hosting Bad for Search?.