Wood Chen

Keep the Main Domain on Cloudflare and Delegate One Subdomain to DNSPod for Regional Routing

0 comments29 views3.1k words

This post was translated from Chinese by AI. If anything reads oddly, the Chinese original is authoritative. 中文原文

This was originally posted on my SunAI forum. Updates and additions will go on the forum first. If you have questions, feel free to leave a comment on the original thread.

Requirements

I want a subdomain, sub.example.com, to use different routes for traffic from mainland China and overseas:

  • Overseas: use Cloudflare CDN, with an overseas origin
  • Mainland China: use a domestic CDN (I use Tencent Cloud EdgeOne), bypassing CF

The prerequisite: keep the main domain example.com hosted on Cloudflare, without touching any other records. Delegate DNS authority for just this one subdomain.

If your domain's NS already points to DNSPod, you can skip delegation entirely—all records already support routing rules. You only need “Step 1: Configure Cloudflare for SaaS” and the record setup section in Step 2. The setup below is for domains hosted on CF.

I built a small tool for the whole workflow. If you don't want to do it manually, skip to “A Tool I Built Along the Way” at the end, or see the splitdns tutorial.

Why Cloudflare Alone Can't Do This

Two hurdles:

  1. CF authoritative DNS doesn't support returning different answers by region for ordinary records. The only native option is Geo Steering in Load Balancing, a paid add-on.
  2. Once a record is orange-clouded, CF returns anycast IPs that are the same worldwide, so there's no way to split traffic at the DNS level.

That means handing this one hostname over to a DNS provider that supports regional routing (DNSPod). But that introduces another hurdle:

After delegation, CF is no longer the authoritative DNS for this hostname, so orange-cloud proxying, caching, WAF, and Universal SSL no longer apply to it. How can overseas traffic still use CF CDN?

The answer is Cloudflare for SaaS (Custom Hostnames). It was designed to let SaaS providers proxy their customers' own domains, and its key feature is exactly what we need: “CF can proxy a hostname even when its DNS isn't hosted on CF.” It's available on the Free plan.

Overall Architecture

example.com (Cloudflare)
    ├── www / mail / 其它所有记录 ──> 照旧,完全不受影响
    └── sub  NS ──> DNSPod            ← 只有这一条被委派出去
                      │
                      ├── 境内线 ──> CNAME sub.example.com.eo.dnse2.com   (EdgeOne)
                      └── 默认线 ──> CNAME fallback.mycdn.net (CF 橙云) ──> 海外源站

Below, I'll use mycdn.net for the second domain used by SaaS and 203.0.113.10 for the overseas origin IP. Replace them with your own values.

You'll need three things: your main domain on CF, another domain also on CF (for the SaaS zone), and a DNSPod account. A custom hostname can't have the same name as the SaaS zone, so the second domain is required.


Step 1: Configure Cloudflare for SaaS (in the mycdn.net Zone)

Go to SSL/TLS → Custom Hostnames and enable Cloudflare for SaaS first.

1. Create a Fallback Origin, which must be an orange-clouded record in this zone:

Type Name Content Proxy
A fallback 203.0.113.10 Proxied

Return to the Custom Hostnames page, enter fallback.mycdn.net under “Fallback Origin,” and wait for its status to become Active. The notice in the dashboard is there for a reason: custom hostname validation won't pass until the fallback origin is Active.

2. Add a custom hostname: enter sub.example.com and choose TXT for certificate validation.

Don't choose HTTP validation. It requires the domain to already point to CF, but you haven't switched DNS yet, creating a chicken-and-egg problem.

After you add it, CF will provide several TXT records. Save all of them:

  • _cf-custom-hostname.sub.example.com —— hostname ownership verification, one record
  • _acme-challenge.sub.example.com —— certificate DCV, possibly two records (when the certificate includes a wildcard SAN, both the base domain and *.sub.example.com need a record; they have the same name but different values, and you must add both)

CF obtains the certificate on your behalf (I've received certificates from both SSL.com and Google Trust Services). It's valid for three months and renews automatically, so you don't need to manage it.

3. (Optional) Set a different origin server for an individual hostname

The fallback origin is the default destination for all custom hostnames. If a hostname needs to use another machine, you can set “Origin Server” and “Origin Server SNI” individually under “Edit”—this feature is now available on Free / Pro / Business; it used to be Enterprise-only.

⚠️ The origin server itself must be an orange-clouded DNS record in your CF account. It can't be an IP or a gray-clouded record. This is documented by CF, but the trap is that you get no warning if you violate it: the hostname and certificate statuses still show “Active” on the Custom Hostnames page. You'll only discover the origin connection fails when you actually visit it.

⚠️ Another trap: that machine must recognize this SNI name, or you'll get a 403 every time.

When CF connects to the origin, the Host header is sub.example.com, but the TLS handshake uses the origin server's name as SNI (for example, ks-5.mycdn.net). Gateways such as Traefik / Nginx that route by Host / SNI can't find a matching router and reject the request.

The fix is simple: add any router / vhost for this name on that machine. It doesn't matter which service it points to or whether it has an SSL certificate; it just needs an entry it can route to. Without one, you could spend ages troubleshooting a mysterious 403.

Also note: explicitly setting “Origin Server SNI” is only available with Enterprise SSL for SaaS. Non-Enterprise accounts will get error 1456 if they fill it in. In most cases, though, you don't need it—CF uses the origin server hostname as the origin SNI by default, so leave it blank.

Step 2: Create a Zone in DNSPod and Set Up the Records (Set It Up First, Delegate Last)

DNSPod lets you add a subdomain directly as a standalone domain: enter sub.example.com under “Add Domain” (the free plan works).

If the main domain isn't in this Tencent Cloud account, DNSPod will ask you to add a TXT record to prove ownership (with error QuhuiTxtNotMatch). Add that TXT record to the main domain, example.com, which is still on CF.

Once it's created, open the domain details and check the assigned NS (on the free plan, they're usually f1g1ns1.dnspod.net / f1g1ns2.dnspod.net; paid plans use names such as ns3.dnsv2.com. Use the values actually shown in the console).

⚠️ Newly added domains have DNS resolution paused by default. Remember to enable it in the domain list. Otherwise, delegation and records can all be correct, yet DNS returns nothing, making the issue hard to spot.

Add the records. All record names are relative to the sub.example.com zone:

Record Name Type Route Value
@ CNAME Default fallback.mycdn.net
@ CNAME Mainland China sub.example.com.eo.dnse2.com (the CNAME provided by EdgeOne)
_cf-custom-hostname TXT Default The value provided by CF
_acme-challenge TXT Default One of CF's DCV values
_acme-challenge TXT Default CF's second DCV value (for the wildcard SAN)

A few key points:

  • Put the CF record on the “Default” route, not “Overseas.” Default is the fallback, so any resolver that doesn't match mainland China gets an answer. If you only configure Mainland China + Overseas, some resolvers whose location can't be identified won't get a record.
  • Two _acme-challenge TXT records with the same name are normal. CF requires both. Don't delete one thinking it's a duplicate—the certificate can't be issued without both. If EdgeOne also requires verification, it uses its own separate set of records.
  • DNSPod's free plan only has three routes: “Default / Mainland China / Overseas.” It doesn't offer country-level routing; targeting a specific country requires the Professional plan or higher. The free plan is enough for one route for mainland China and another for overseas.
  • A CNAME at @ is nonstandard. DNSPod allows it, but it conflicts with other record types at the same name. If it rejects it, see the alternative at the end.
  • Set TTL to 600 seconds. That's the minimum on DNSPod's free plan; the API will reject anything lower.

If the mainland China route uses EdgeOne, EO manages the certificate, so there is no need to deal with it on the origin server—just follow EO's process to add the domain and complete its verification. The mainland China route can also use an optimized domain: simply add a CNAME pointing to it. Once traffic enters CF's edge through that domain, CF still uses the Host header to find your custom hostname, using the same SaaS configuration described above.

Step 3: Set Up NS Delegation on Cloudflare

Go back to the example.com zone.

1. First, handle all existing records at sub and under *.sub.

Don't cut corners. Leaving them there won't cause an error, but they will become shadowed records—still visible in the list, but none of them will take effect. They can drive you crazy during troubleshooting.

Note that I said "handle," not "delete outright": if these records are still serving traffic (for example, api.sub.example.com points to a backend), move them to the new DNSPod zone first, then delete them from CF. Deleting them outright will interrupt production traffic.

2. DNS → Records → Add record, then add two NS records:

Type Name Content TTL
NS sub f1g1ns1.dnspod.net Auto
NS sub f1g1ns2.dnspod.net Auto

It is normal for the proxy status to show "DNS only"; NS records do not have an orange-cloud toggle. The Free plan supports NS records for delegation.

This step only affects the name sub. Leave all other records, NS settings, and registrar settings for example.com unchanged.

By the way, the Enterprise-only Subdomain setup in the CF dashboard is something else—it hosts a subdomain as a separate zone on CF itself. You do not need it to delegate to a third party.

3. DNSSEC: If DNSSEC is enabled for example.com, no action is needed if the child zone is unsigned (a normal insecure delegation). Only add a DS record for sub in CF if the child zone is also signed.

4. Glue records: Not needed. Glue is only required if the NS hostname itself is under sub.example.com (for example, ns1.sub.example.com).

Step 4: Verify

Check whether the delegation has taken effect:

dig +trace sub.example.com

Query DNSPod's NS directly:

dig @f1g1ns1.dnspod.net sub.example.com

Check the certificate and whether traffic goes through CF:

curl -sIv https://sub.example.com 2>&1 | grep -E 'subject|issuer|cf-ray'

Finally, return to CF's custom hostnames page and wait for both Certificate status: Active and Hostname status: Active. Delegation + TXT records usually take a few minutes to take effect.


Pitfalls

After delegation, CF is no longer authoritative for this hostname. WAF rules, cache rules, page rules, and Universal SSL in the parent domain's zone no longer cover it. HTTPS for the overseas route uses the custom hostname's certificate, along with the SSL/TLS settings and rules in the mycdn.net zone—configure rules there, not in the parent domain's zone.

The custom origin server is not the DNS target. DNS must point to an orange-cloud record in the SaaS zone (to bring traffic into CF); the origin server is where CF forwards that traffic after receiving it. Get these backward, and CF will not recognize the hostname at all.

But the custom origin server itself must be an orange-cloud record. See item 3 in Step 1—if it is missing or gray-clouded, origin requests fail while everything looks fine in the CF dashboard. This combination is the hardest to troubleshoot: the certificate is active, the hostname is active, DNS resolution is correct, yet the site will not load.

If you use a custom origin server, add a router matching the SNI on your origin, or all you will see is 403.

The custom hostname's "Minimum TLS version" defaults to TLS 1.0. If that bothers you, remember to change it manually to 1.2.

The overseas origin's firewall must allow CF's origin-facing IP addresses, and the SSL/TLS mode must be set to Full (strict) in the mycdn.net zone.

If the mainland China route connects directly to the origin instead of using a CDN, that server must have its own certificate for sub.example.com. The _acme-challenge TXT record for DNS-01 renewal must also be added to DNSPod rather than CF, so remember to change the provider in any existing automatic renewal scripts.

Do not reverse the order: create the DNSPod zone and all its records first, then add NS records and delete the old records in CF as the final step. That way, DNS resolution is available immediately at the switchover, with no interruption.

If you ever want to undo this, remove the delegation first, not the DNSPod domain. Doing it the other way around leaves CF's delegation pointing to NS servers that no longer host the zone. Resolvers get SERVFAIL and keep retrying, which is worse than simply finding nothing.


Alternative: Skip Delegation

If DNSPod's @ CNAME does not work well, or you would rather not change NS records, there is a lighter approach:

Keep sub as a gray-cloud CNAME in the parent domain's zone, pointing to sub.geo.另一个放在DNSPod的域名, and configure the route-specific records on that name.

sub    CNAME  sub.geo.mydns.net    仅 DNS(灰云)

The result is the same (GeoDNS uses the recursive resolver's location / EDNS Client Subnet, and an extra CNAME hop does not affect that). It also avoids apex CNAME, DNSSEC, and shadowed-record complications. Switch it back to orange-cloud to roll back.

Try this first, and use NS delegation only if it really does not work.


I Also Built a Tool

The workflow above has a lot of moving parts, and every step needs time to take effect. Once you have enough domains, it becomes too much to keep track of manually, so I turned it into a tool:

Desktop versions for Windows and macOS:

  • Windows installer —— Data is stored in %APPDATA%\splitdns and left untouched by upgrades or reinstalls
  • Windows portable —— Extract and run; data is stored in data/ alongside the exe, so copying the entire folder takes all your configuration with it
  • macOS —— universal, supports both Intel and Apple Silicon; data is stored in ~/Library/Application Support/splitdns; not signed or notarized, so right-click → Open on first launch, or run xattr -dr com.apple.quarantine splitdns.app

Here is what it does:

Setup wizard—Breaks the four steps above into validated steps. Wherever possible, it calls the APIs directly (create the fallback origin, add the custom hostname, create the DNSPod domain and enable resolution, write DCV TXT records, configure route-specific records, and add NS delegation). For anything it cannot automate, it gives instructions down to the exact values to enter. The key is that a successful platform API response does not count; a step is complete only when checks confirm it has actually taken effect—so you can close the app and return the next day without losing progress, and it reassesses everything against the current live state. If someone changes a previously completed step in production, it automatically reverts to "Waiting to take effect" and explains what differs.

Two setup modes—Keep the parent domain on CF and move only one subdomain (the delegation workflow above), or use a domain whose NS records already point to DNSPod (direct-hosting mode, which also supports configuring the root domain directly). Both use the same steps and checks; direct-hosting mode simply omits the parent-zone and delegation steps. Optimized routing is not a separate feature, just a regular route pointing to an optimized domain.

Health checks—Check the actual state across all three platforms at any time, focusing on these common trouble spots:

  • Records in the parent zone shadowed by delegation (visible but ineffective)
  • Whether the custom origin's orange-cloud record exists, and whether it is gray-clouded (the pitfall above that the CF dashboard does not reveal); missing records can be recreated with one click
  • Whether any verification TXT records required by CF are missing (the two wildcard SAN records with the same name but different values are especially easy to miss)
  • Whether the CF record is on the "Default" route as a fallback
  • Whether the domain is still paused on DNSPod
  • Whether the delegated NS records match those actually assigned by DNSPod
  • Certificate status, expiration time, and whether the custom origin server matches the configuration

The cleanup step migrates records first—Shadowed does not mean disposable. It evaluates each record: records for the hostname being configured are deleted without migration (their destinations are managed by the route configuration); all others are moved unchanged to DNSPod before deletion. Orange-cloud records get a separate warning: "Migrating this record will make it a direct connection."

You can dismantle the setup step by step—Remove delegation → clear DNSPod records → delete the DNSPod domain → delete the custom hostname → clear the fallback origin → clear verification records in the parent zone. Each step lists what it will do before making changes, and every step can be skipped. It deletes only records created by this tool; if other custom hostnames still use the fallback origin, it refuses to proceed rather than offering a "confirm to delete anyway" option.

Platform credentials stay on your local machine, the application does not listen on any ports, and no domains / credentials / DNS records are uploaded. On first launch, you need to sign in once with a CZL Connect account, purely to count how many people are using it. You also need to provide your own Cloudflare API Token(Zone:Read + DNS:Edit + SSL:Edit)and Tencent Cloud SecretId / SecretKey.


Join the discussion on the forum

This post was first published on the SunAI forum: Keep the main domain on Cloudflare and delegate just one subdomain to DNSPod for split DNS routing inside and outside China

If you get stuck at any step or run into an issue not covered here, leave a comment on the original thread. I’ll reply when I see it.

SunAI is a tech community I run myself. I publish VPS reviews, network tuning tips, website setup guides, and AI tool content there first. Feel free to drop by.

Related posts

Comments 0