You are reading this on kepakisan.co.nz. This site. The one I built, deployed to Azure Static Web Apps, then spent an entire day trying to connect to a domain I had just paid for, before finally getting it working. This is the story of that day, written for anyone who has ever stared at a DNS configuration panel and felt that quiet panic of not knowing what any of it means.
I came from accounting. I know what a balance sheet is, what a reconciliation looks like, how to trace an error back to source. DNS is, in theory, not that different. There are records, there are lookups, there is a correct answer and a wrong one. But the abstractions are unfamiliar, the error messages are cryptic, and the feedback loop is measured in hours rather than seconds. That combination is genuinely disorienting, even for someone who now works in data engineering.
So let me save you the panic. Here is what happened, what went wrong, what I learned, and most importantly, why it works the way it does.
A Simple Plan
I had a freshly deployed Azure Static Web App sitting at its default URL: gray-moss-0678f2900.6.azurestaticapps.net.
The site worked. It looked fine. But that URL is not something you hand to anyone. So I bought
kepakisan.co.nz on GoDaddy and figured I would spend an afternoon connecting them.
Reader, it was not an afternoon.
Azure's custom domain setup looks easy. You type your domain, it asks you to add a TXT record to your DNS provider as proof of ownership, you add it, Azure says "Validated." You think you are done. You are not done. Not even close.
Before We Go Further: The Jargon, Explained Plainly
If you are a business person who has spent time in spreadsheets rather than server rooms, the language of DNS is a wall of abbreviations that all seem to mean the same thing until they suddenly do not. Let me break them down the way I wish someone had explained them to me.
The internet runs on IP addresses, long numbers like 20.2.51.235. But nobody types those. You type kepakisan.co.nz. DNS (Domain Name System) is the phone book that translates one into the other. When you type a domain name, your computer asks a DNS server "what is the address for this name?" and gets an IP back. It is the same as looking up a business name in a phone directory to find their number.
The apex (also called the root domain) is simply the bare domain with nothing in front of it: kepakisan.co.nz. When you add "www" in front, you get a subdomain: www.kepakisan.co.nz. Think of it like a building address vs a specific floor. The apex is the whole building. www is floor 1. blog is floor 2. And so on. The distinction matters technically because the rules for apex domains are stricter than for subdomains.
An A record is the most direct type of DNS record. It maps a domain name directly to an IP address. "kepakisan.co.nz goes to 20.2.51.235." Simple. The problem with Azure Static Web Apps is that it does not give you a static IP address to point to. It gives you a hostname, which is why A records alone are not enough, and why you need the next thing.
A CNAME (Canonical Name) record is an alias. Instead of saying "this domain goes to this IP", it says "this domain goes wherever that other domain goes." So I can say "www.kepakisan.co.nz goes wherever gray-moss-0678f2900.6.azurestaticapps.net goes." Azure handles what IP that resolves to. The practical use: if Azure ever moves my site to a different IP, I do not need to update anything. The CNAME follows automatically.
The catch: CNAME records cannot exist at the apex. It is a rule baked into DNS itself, not a GoDaddy or Azure decision. The apex must have NS and SOA records, and a CNAME conflicts with them. This is the wall I hit.
A TXT record is just a text string attached to a domain. It has no routing purpose. Services like Azure use it to verify ownership: "Add this specific string to your DNS, and if it appears, we know you control this domain." It is like a landlord asking you to place a specific coloured sticker in your window before they hand over the keys. Proof of control, nothing else.
TTL (Time to Live) is how long a DNS answer gets cached. If your TTL is 3600 (one hour), anyone who looked up your domain gets the old answer for up to an hour before their DNS resolver fetches a fresh one. This is why DNS changes feel slow. You made the change instantly. But the old answer is still cached everywhere. Lower TTLs mean faster propagation, but more DNS queries. It is a trade-off.
That padlock in your browser's address bar means the connection is encrypted. The SSL/TLS certificate is what makes that padlock appear. It proves the server you are talking to actually owns the domain it claims to be. Azure Static Web Apps automatically provisions and renews these certificates for custom domains, but only after the domain binding is fully configured. If you skip a step, Azure never issues the cert, and visitors see a red error screen instead of a padlock.
Remember that CNAMEs cannot exist at the apex? CNAME flattening is a clever workaround some DNS providers (notably Cloudflare) use. When you create a CNAME at the apex, Cloudflare quietly resolves the chain behind the scenes and serves the resulting IP address, so the outside world sees a normal A record, but behind the scenes it is following a CNAME. The rule is technically satisfied. Your apex works. Nobody is the wiser. GoDaddy does not support this. Cloudflare does. That difference is what drove the whole second half of this story.
The First Wave of Errors
My first symptom was this:
A big red SSL error screen. Then, if I somehow bypassed it, I landed on something even more confusing:
Custom domain has not been configured inside Azure.
Which was baffling, because I had configured it inside Azure. Or at least I thought I had. What I did not know was the difference between validating ownership and creating a domain binding. These are two completely separate steps. Adding that TXT record proved to Azure I owned the domain. It did not tell Azure to serve my app when someone actually visited it.
I had only added kepakisan.co.nz
(the apex). I had a CNAME pointing www
to Azure in GoDaddy, but I had never added www.kepakisan.co.nz
as its own domain binding inside Azure. So traffic arrived at Azure's infrastructure and Azure shrugged. Nobody
home.
Azure requires an explicit binding per hostname
Adding a CNAME in GoDaddy is not enough. Azure Static Web Apps needs you to explicitly register every hostname it should respond to, both apex and www separately. TXT validation proves ownership. The binding tells Azure to route traffic.
The Apex Problem Nobody Warned Me About
While sorting out the www issue, I ran nslookup on my apex domain and got back two mysterious IPs:
Name: kepakisan.co.nz
Addresses: 76.223.105.230, 13.248.243.5
/* Not Azure. These are GoDaddy parking servers. */
GoDaddy had silently injected a parking record when I deleted their default WebsiteBuilder A record. The domain was not pointing at Azure at all. It was pointing at GoDaddy's "this domain is parked" infrastructure. Every visitor would see a GoDaddy placeholder page, not my site.
The natural instinct was: just add a CNAME at the apex pointing to Azure. But this is where DNS bites back. You cannot use a CNAME at the apex of a domain. Not in GoDaddy, not in most DNS providers. It is a fundamental DNS specification rule: the apex must have NS and SOA records, and a CNAME conflicts with those. Azure does not give you a static IP either (unlike App Service), so you cannot just add an A record. You are stuck.
CNAME at the apex is illegal DNS
This is not a GoDaddy limitation or an Azure limitation. It is baked into how DNS works. The apex must have NS and SOA records. A CNAME at the same level conflicts. No standard DNS provider will allow it, which is why a workaround is needed for apex domains with services that only provide hostnames, not IPs.
Getting Mostly Working: The GoDaddy Approach
The quickest workaround without leaving GoDaddy: use GoDaddy's domain forwarding to redirect the apex to www, and make www the real domain. It is not perfect, but it works for most visitors.
The steps: Add www.kepakisan.co.nz as a custom domain in Azure SWA. Wait for the TLS certificate to provision (~30 minutes). Set up GoDaddy domain forwarding: kepakisan.co.nz → https://www.kepakisan.co.nz. Set www as the default domain in Azure.
This got https://www.kepakisan.co.nz working with a valid green padlock. Progress. But https://kepakisan.co.nz
remained broken. GoDaddy's forwarder only handles HTTP (port 80). HTTPS requests to the apex hit GoDaddy's
infrastructure, which does not hold a certificate for my domain, and the connection fails silently. The browser
gives up.
I also hit a trap I did not see coming: the redirect loop.
The default domain redirect loop
Azure's "default domain" setting means it canonically redirects all other custom domains to it. I briefly set kepakisan.co.nz as the Azure default while GoDaddy forwarding was pointing the apex to www. The result: Azure redirected www → apex → GoDaddy forwarded apex → www → Azure redirected www → apex. Infinite loop. The fix was ensuring the Azure default and the GoDaddy forwarding direction agreed with each other.
Moving to Cloudflare: What It Actually Means
The broken HTTPS apex was not something I could live with. So I moved DNS to Cloudflare. And here is the thing that confused me most when people suggested this: moving to Cloudflare does not mean transferring my domain.
Your domain registrar is who you bought the domain from and who holds the legal registration. GoDaddy is my registrar. I pay them annually to keep kepakisan.co.nz registered in my name. This does not change.
Your DNS provider is who answers the phone when someone asks "where does this domain live?" These are your nameservers. GoDaddy defaults to using their own nameservers. But I can tell GoDaddy "when someone asks about my domain, ask Cloudflare instead." GoDaddy stays the registrar. Cloudflare just answers DNS queries. It is like keeping the same landlord but hiring a different concierge to answer the door.
The migration was a nameserver change (one setting in GoDaddy) plus cleaning up DNS records in Cloudflare. The whole thing took about 30 minutes of clicking. The propagation (waiting for the change to spread globally) took about an hour.
Why does Cloudflare fix the apex problem? Because Cloudflare supports CNAME flattening. When I
create a CNAME at @
(the apex), Cloudflare quietly resolves the chain behind the scenes and serves the resulting IP address. From
outside, it looks like an A record. DNS spec technically satisfied. Azure receives the request. Certificate
provisioned. Both https://kepakisan.co.nz and https://www.kepakisan.co.nz work natively, with valid padlocks, no
redirects, no hacks.
Critical Cloudflare gotcha: Both CNAME records must be set to "DNS only" (grey cloud), NOT "Proxied" (orange cloud). Cloudflare's proxied mode intercepts all traffic including TLS. If you leave it on, Azure cannot perform its HTTP certificate challenge because the request never reaches Azure. The managed cert will never provision, and you will be back to SSL errors.
When "It's Working" Isn't Working Yet
After the Cloudflare migration, I flushed my DNS cache, opened incognito, visited the site, and got... GoDaddy's parking page again. I genuinely thought I had broken something. Then I ran this:
Name: kepakisan.co.nz
Address: 20.2.51.235
/* Azure IP. Cloudflare sees the correct answer. */
/* My ISP's resolver is still caching the old GoDaddy answer. */
The configuration was correct. But I had made an assumption that tripped me up: I thought ipconfig /flushdns
would fix it. It did not. And this brings me to what I think is the most interesting thing I learned from the
whole day.
When you run ipconfig /flushdns,
you clear the DNS cache on your own computer. Your computer then asks your ISP's DNS resolver
for a fresh answer. But your ISP's resolver has its own cache too, and you cannot flush that. It holds onto
old answers until the TTL expires, regardless of what you do on your end.
This is why DNS changes feel slow even after you have made them correctly. The change is live at the authoritative source (Cloudflare). But every DNS resolver in the world is working through its own cached copy. Your ISP resolver might take another hour or two before it fetches the new answer.
The test: query Cloudflare's public resolver directly with nslookup kepakisan.co.nz 1.1.1.1.
If that returns an Azure IP, your config is correct and you are just waiting for your ISP to catch up. The
fix: change your machine's DNS server to 1.1.1.1 in your network settings, bypassing your ISP resolver
entirely.
I confirmed this by disconnecting my phone from WiFi and testing on mobile data. Different network, different ISP, different resolver, and the site loaded perfectly. Same domain, same configuration, different DNS resolver. It is one of those internet mechanics that most people never see, because it usually resolves before you notice it.
Then I realised something else: my router is not my ISP. My laptop talks to my router (192.168.1.1,
a Netgear RBR760). But my router just forwards DNS queries upstream to my ISP (in my case,, 2degrees). The
stale cache was not sitting in my router. It was sitting at 2degrees' DNS servers. Which meant every 2degrees
customer in New Zealand with about 30% of the market was potentially seeing GoDaddy's parking page instead of my
site. I could not fix that for them. I just had to wait.
Your router is the box in your house. Your ISP (Internet Service Provider,
like 2degrees, Spark, or Vodafone) is the company providing your internet connection. When your laptop wants
to look up a domain, it asks your router. Your router doesn't usually know the answer itself; it forwards the
question to your ISP's DNS resolver. Your ISP's resolver is where the real caching happens. ipconfig /flushdns
clears your laptop's own tiny cache. It does not touch your router's cache, and it definitely does not touch
your ISP's resolver. That is why it feels like it does nothing.
Public Resolvers: And Why They Disagree
Discovering that nslookup kepakisan.co.nz 1.1.1.1
returned the correct Azure IP while my ISP did not raised a question I hadn't thought about before: what
exactly is 1.1.1.1? And if 1.1.1.1 is a resolver I can query directly, are there others?
Yes, and this is a genuinely useful thing to know. There are several major public DNS resolvers, all free, all queryable by anyone:
| Resolver IP | Provider | Known for |
|---|---|---|
1.1.1.1 |
Cloudflare | Fastest globally, strong privacy |
8.8.8.8 |
Most widely used public resolver | |
9.9.9.9 |
Quad9 | Privacy-focused, blocks malicious domains |
208.67.222.222 |
OpenDNS (Cisco) | Long-established, enterprise-friendly |
192.168.1.1 |
Your router → your ISP | Default for most home users, slowest to update |
You can query any of them directly with nslookup to see what they currently believe about your domain. During propagation, they may all return different answers, and that is completely normal. They are not coordinating. They are not calling each other. Each one independently fetches, caches, and serves DNS answers on its own schedule.
Address: 20.247.40.175 ← Azure. Cloudflare knows.
> nslookup kepakisan.co.nz 8.8.8.8
Address: 20.247.40.175 ← Azure. Google knows.
> nslookup kepakisan.co.nz
Addresses: 3.33.130.190, 15.197.148.33 ← GoDaddy. 2degrees still caching.
Imagine you update your phone number and tell the official directory about it. Three different people have your old number written in their personal notebooks. One of them checks the official directory every day (Cloudflare). One checks it every few days (Google). One checks it only when their notebook is full (your ISP). For a while, they'll give different people different answers when asked for your number. Nobody is wrong, exactly. They're just working from different versions of the truth at different points in time.
When resolvers disagree, nothing breaks. There is no conflict, no error. Some visitors get your new site. Some temporarily get GoDaddy's parking page. They are completely unaware of each other. The internet is deliberately designed to tolerate this inconsistency during transitions. It is expected, temporary, and invisible to almost everyone.
This is also why the advice "just wait" is genuinely correct and not a cop-out. You cannot force a global cache flush. You cannot call 2degrees and ask them to refresh their DNS resolver. All you can do is confirm your configuration is correct (using 1.1.1.1 as your test) and let time do the rest. The TTL you set on your records is the contract. Once it expires at each resolver, they fetch the new answer and the old one is gone.
I know what a trial balance is. I can trace an error back through five layers of ledger. DNS turned out to work the same way, once I learned the vocabulary.
Maha KepakisanWhere It Ended Up
The site you are reading this on kepakisan.co.nz, is the result of that day. Here is what the final architecture looks like:
| URL | Path | Result |
|---|---|---|
https://kepakisan.co.nz
|
Cloudflare CNAME flattening → Azure SWA | ✓ Works natively |
https://www.kepakisan.co.nz
|
Cloudflare CNAME → Azure SWA → redirects to apex | ✓ Works natively |
http://kepakisan.co.nz |
Azure upgrades to HTTPS automatically | ✓ Works |
GoDaddy is still the registrar. Cloudflare is the DNS provider. Azure holds the TLS certificates and serves the content. Three services, each doing one job, none of them overlapping.
The Accountant's Summary
If you have an accountant's brain like me, here is the version that will stick:
DNS validation ≠ traffic routing
Proving domain ownership to Azure and telling Azure to serve your app are different operations. You need both, separately, for each hostname (apex and www are separate).
Apex domains need special handling
CNAME at the root is illegal DNS. GoDaddy forwarding works for HTTP only. Cloudflare CNAME flattening is the clean solution, and it is free.
Registrar ≠ DNS provider
Moving nameservers to Cloudflare is not a domain transfer. GoDaddy stays your registrar. You are just outsourcing the phone book to a better provider. Nothing else changes.
ipconfig /flushdns is not enough
It clears your local cache, not your ISP's resolver cache. Use nslookup against 1.1.1.1 to test the true DNS state. If 1.1.1.1 returns the right answer, your config is correct and you are just waiting.
Start with Cloudflare
If I had moved nameservers to Cloudflare from day one, the whole day would have been about two hours. The GoDaddy-only path gets you mostly working but leaves a broken edge case (HTTPS apex) that will bother you. Cloudflare free tier handles everything cleanly.
Coming from accounting, I am used to systems where the answer is right or wrong and the error message tells you which. DNS is subtler than that. The error message says "certificate invalid" when the real problem is a missing domain binding. The site shows a GoDaddy page when the real problem is your ISP resolver is caching old data. The symptoms do not point cleanly at the cause. That takes some getting used to.
But once you understand the vocabulary, once you know what apex, CNAME, TTL, flattening and propagation actually mean, it clicks. And like most technical things that once seemed impenetrable, it turns out to be quite logical once you see it clearly.
The site works. The padlock is green. And I learned something real.
