Azure DNS: Public and Private DNS Zones

An Azure private DNS zone lets servers in your virtual networks find each other by name, like app.saat.internal, instead of by IP addresses that change. Public DNS zones do the same job for names the whole internet uses, like www.example.com.

DNS problems look like everything else: “the app can’t connect”, “the site is down”, “storage says 403”. In Phase 4 you’ll see that half of private endpoint troubles are DNS. So it’s worth knowing exactly how Azure answers a name lookup.

In this lab you create a private zone, link it to vnet-saat, watch a VM register itself automatically, add your own records, and look up a public zone directly on Azure’s name servers.

TimeYou needCostBy the end you can
About 45 minutesvnet-saat, the CLIAbout USD 0.05 (two DNS zones for a day; the VM uses free hours)Create and link private DNS zones, add records, and explain why a name does or doesn’t resolve

What it is, in one line

A DNS zone is a list of names and the addresses they point to; private zones answer only inside linked VNets, public zones answer the whole internet.

In Simple Words

The school phone book

Nobody remembers phone numbers any more. You look up “Ravi” in your phone, and it dials the number for you. If Ravi changes his number, you update one entry and everyone who calls “Ravi” still gets through.

DNS is that phone book for computers. A private zone is the phone book on the staff-room wall: only people inside the school can read it. A public zone is the phone book printed for the whole city.

And the staff-room book only helps rooms that have a copy. If a new building has no copy, nobody there can find Ravi. That’s a VNet without a link to the zone.

Engineer's View

How Azure answers a name lookup

  • Every VM in a VNet uses Azure’s resolver at 168.63.129.16 by default (unless you set custom DNS servers on the VNet).
  • That resolver checks private DNS zones linked to the VM’s VNet first. If a linked zone owns the name, the answer comes from the zone, even if the same name exists on the internet.
  • Otherwise it does a normal public lookup on the internet.
  • A virtual network link connects a zone to a VNet. A zone can be linked to many VNets (up to 1,000). With auto-registration on, VMs in that VNet get A records automatically when they start and lose them when they’re deleted. A VNet can have only one zone with auto-registration, but many resolution-only links.
  • Public zones get four Azure name servers (ns1-xx.azure-dns.com, .net, .org, .info). They only answer the internet after you delegate the domain at your registrar by setting those NS records there.

Common record types: A (name to IPv4), AAAA (IPv6), CNAME (name to another name; not allowed at the zone apex), TXT, MX. Each record set has a TTL: how long resolvers may cache the answer.

.internal is reserved by ICANN for private use, so it will never clash with a real internet domain. That’s why the course uses saat.internal. Zones are charged per zone per month, counted daily, the same for public and private.

How it works, step by step

When vm-saat-l14 looks up api.saat.internal, this happens:

Azure private DNS zone resolution through 168.63.129.16
  1. The VM asks its resolver, 168.63.129.16.
  2. The resolver sees that saat.internal is linked to vnet-saat, so it answers from that zone.
  3. api is a CNAME pointing to app.saat.internal, so the resolver follows it in the same zone.
  4. app is an A record for 10.30.2.10. The resolver returns both the CNAME and the A record.
  5. The VM caches the answer for the TTL, then asks again next time.

If the VNet isn’t linked, step 2 never happens. The resolver asks the internet, which has never heard of saat.internal, and the answer is “no such name”. Nothing errors loudly; the app just can’t find its server.

Azure private DNS zone compared with a public DNS zone

The same logic explains private endpoints later: Azure creates zones like privatelink.blob.core.windows.net, and if a VNet isn’t linked, storage names resolve to public IPs and requests get blocked.

Hands-on lab: private names, public names

You create a private zone with a VM that registers itself, add records, test from the VM with Run Command, then create a public zone and ask Azure’s name servers directly.

$v = Get-Content C:\azure-lab\vnet-saat.json | ConvertFrom-Json
az group create --name rg-saat-l14 --tags course=saatvedha-azure lesson=14 -o none

1Create a private zone and link it with auto-registration

Run this:

az network private-dns zone create --resource-group rg-saat-l14 --name saat.internal --tags course=saatvedha-azure lesson=14 -o none
az network private-dns link vnet create --resource-group rg-saat-l14 --zone-name saat.internal --name link-vnet-saat --virtual-network $v.VnetId --registration-enabled true --tags course=saatvedha-azure lesson=14 -o none
az network private-dns link vnet list --resource-group rg-saat-l14 --zone-name saat.internal --query "[].{name:name, autoRegister:registrationEnabled, state:virtualNetworkLinkState}" -o table

You should see something like this:

Name            AutoRegister    State
--------------  --------------  ---------
link-vnet-saat  True            Completed

2Create a VM and watch it register itself

Run this (about two minutes):

az vm create --resource-group rg-saat-l14 --name vm-saat-l14 --image Canonical:ubuntu-24_04-lts:server:latest --size Standard_B2ats_v2 --subnet $v.'snet-mgmt' --public-ip-address '""' --nsg '""' --admin-username azureuser --generate-ssh-keys --os-disk-size-gb 64 --tags course=saatvedha-azure lesson=14 -o none
az network private-dns record-set a list --resource-group rg-saat-l14 --zone-name saat.internal --query "[].{name:name, ip:aRecords[0].ipv4Address, auto:isAutoRegistered}" -o table

You should see something like this:

Name         Ip          Auto
-----------  ----------  ------
vm-saat-l14  10.30.10.4  True

You didn’t create that record. Azure did it when the VM’s network card came up in a VNet with an auto-registration link.

3Add your own records

Run this:

az network private-dns record-set a add-record --resource-group rg-saat-l14 --zone-name saat.internal --record-set-name app --ipv4-address 10.30.2.10 -o none
az network private-dns record-set a add-record --resource-group rg-saat-l14 --zone-name saat.internal --record-set-name db --ipv4-address 10.30.3.10 -o none
az network private-dns record-set cname set-record --resource-group rg-saat-l14 --zone-name saat.internal --record-set-name api --cname app.saat.internal -o none
az network private-dns record-set list --resource-group rg-saat-l14 --zone-name saat.internal --query "[].{name:name, type:type, ttl:ttl}" -o table

You should see something like this:

Name         Type                                TTL
-----------  ----------------------------------  -----
@            Microsoft.Network/privateDnsZones/SOA  3600
api          Microsoft.Network/privateDnsZones/CNAME  3600
app          Microsoft.Network/privateDnsZones/A  3600
db           Microsoft.Network/privateDnsZones/A  3600
vm-saat-l14  Microsoft.Network/privateDnsZones/A  10

Records you add get a TTL of 3600 seconds (one hour) by default; auto-registered ones get 10 seconds, because VMs come and go. For records you may change during a migration, lower the TTL a day before.

4Look the names up from inside the VNet

Run this:

az vm run-command invoke --resource-group rg-saat-l14 --name vm-saat-l14 --command-id RunShellScript --scripts "getent hosts app.saat.internal api.saat.internal vm-saat-l14.saat.internal; resolvectl dns eth0" --query "value[0].message" -o tsv

You should see something like this:

Enable succeeded:
[stdout]
10.30.2.10      app.saat.internal
10.30.2.10      app.saat.internal api.saat.internal
10.30.10.4      vm-saat-l14.saat.internal
Link 2 (eth0): 168.63.129.16

[stderr]

getent hosts uses the same lookup path as applications do. The CNAME shows up as an alias of app.saat.internal. The last line confirms the VM asks Azure’s resolver, 168.63.129.16.

5Create a public zone and ask Azure’s name servers

Run this on your laptop:

$zone = 'saatlab' + (Get-Random -Maximum 99999) + '.com'
az network dns zone create --resource-group rg-saat-l14 --name $zone --tags course=saatvedha-azure lesson=14 -o none
az network dns record-set a add-record --resource-group rg-saat-l14 --zone-name $zone --record-set-name www --ipv4-address 203.0.113.10 -o none
$ns = az network dns zone show --resource-group rg-saat-l14 --name $zone --query "nameServers[0]" -o tsv
Resolve-DnsName -Name "www.$zone" -Type A -Server $ns.TrimEnd('.') | Select-Object Name, IPAddress

You should see something like this:

Name                  IPAddress
----                  ---------
www.saatlab41827.com  203.0.113.10

203.0.113.10 is a documentation address, safe to use in labs. Azure’s name server answered, because you asked it directly. In “Break It” you’ll see why the rest of the internet doesn’t know this name yet.

Azure private DNS zone lab: auto-registered VM and getent lookups
Example output. Your IPs and zone name will be different.

✅ Checkpoint: Your private zone answers inside vnet-saat (including the auto-registered VM), and Azure’s public name server answers for www in your public zone.

Break It, Then Fix It

Both of these are “nothing is wrong, it just doesn’t resolve” problems, which are the hardest kind on a busy day.

1Break it: a public zone nobody has delegated

Run this on your laptop, without naming a server:

Resolve-DnsName -Name "www.$zone" -Type A

You’ll get an error like this:

Resolve-DnsName : www.saatlab41827.com : DNS name does not exist
At line:1 char:1
+ Resolve-DnsName -Name "www.$zone" -Type A
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (www.saatlab41827.com:String) [Resolve-DnsName], Win32Exception
    + FullyQualifiedErrorId : DNS_ERROR_RCODE_NAME_ERROR,Microsoft.DnsClient.Commands.ResolveDnsName

Your normal resolver asks the .com servers, and they’ve never been told that Azure hosts this domain. Creating a zone in Azure doesn’t publish it.

Fix it (for a real domain): copy the four name servers and set them as the NS records at your domain registrar:

az network dns zone show --resource-group rg-saat-l14 --name $zone --query nameServers -o tsv

You should see something like this:

ns1-07.azure-dns.com.
ns2-07.azure-dns.net.
ns3-07.azure-dns.org.
ns4-07.azure-dns.info.

You don’t own this made-up domain, so you stop here. With a real domain, delegation can take from minutes to a couple of days, depending on the TTLs at the registrar and the TLD.

2Break it: remove the VNet link

Delete the link and look up the names again:

az network private-dns link vnet delete --resource-group rg-saat-l14 --zone-name saat.internal --name link-vnet-saat --yes
Start-Sleep -Seconds 30
az vm run-command invoke --resource-group rg-saat-l14 --name vm-saat-l14 --command-id RunShellScript --scripts "getent hosts app.saat.internal || echo NOT-FOUND" --query "value[0].message" -o tsv

You should see something like this:

Enable succeeded:
[stdout]
NOT-FOUND

[stderr]

The zone and its records still exist, but vnet-saat no longer has a copy of the phone book, so Azure’s resolver asks the internet and gets nothing. At work this happens when a new spoke VNet is created and nobody links the shared private zones to it.

Fix it: link the zone again (resolution only this time is fine), then test:

az network private-dns link vnet create --resource-group rg-saat-l14 --zone-name saat.internal --name link-vnet-saat --virtual-network $v.VnetId --registration-enabled false -o none
az vm run-command invoke --resource-group rg-saat-l14 --name vm-saat-l14 --command-id RunShellScript --scripts "getent hosts app.saat.internal || echo NOT-FOUND" --query "value[0].message" -o tsv

You should see something like this:

Enable succeeded:
[stdout]
10.30.2.10      app.saat.internal

[stderr]
Azure private DNS zone errors: undelegated public zone and missing VNet link
Example output of both problems.

3Clean up

Run this:

az group delete --name rg-saat-l14 --yes
C:\azure-lab\Find-LabResources.ps1 -Lesson 14

You should see this:

Nothing tagged course=saatvedha-azure is left.

✅ Checkpoint: Both problems reproduced and understood, and nothing from Lesson 14 is left.

This happened at work

The 24-hour TTL on migration night

A pharmacy chain moved its stock system from an old VM to a new one in Azure. The plan was simple: at 10 p.m. change stock.corp.internal from the old IP to the new one in the private DNS zone.

The record had a TTL of 86,400 seconds, one full day, set years earlier “to reduce DNS traffic”. After the change, about half of the store servers kept using the cached old IP. They wrote sales to the old system all night, while the other half used the new one.

The next morning stock counts didn’t match in 300 stores, and two days of reconciliation followed.

What they changed: a migration checklist now lowers the TTL to 60 seconds at least one full old-TTL period before cutover, and raises it back afterwards. The old system is set to read-only at cutover, so stale clients fail loudly instead of writing to the wrong place. Normal TTLs for internal app records are now one hour.

Common mistakes and troubleshooting

MistakeWhat you seeWhat to do
New VNet not linked to the private zoneNames don’t resolve only in that VNetLink every VNet that needs the zone; check links during network builds.
Expecting a new public zone to work at onceDNS name does not existDelegate at the registrar with the four Azure NS records.
Long TTL during a changeSome clients keep the old IP for hoursLower the TTL well before a change, raise it after.
CNAME at the zone apexThe record can’t be createdUse an A record or an alias record at the apex.
Two zones with auto-registration on one VNetThe second link is refusedOnly one auto-registration zone per VNet; other links resolve only.
Custom DNS servers on the VNet that don’t forwardPrivate zones stop resolvingForward unknown names to 168.63.129.16, or use Azure DNS Private Resolver.

Interview questions

Click a question to open it. Each one is written the way an interviewer would ask it. Under it you will see why they ask it and one way you could answer, in your own words.

Fresher level

1. What is the difference between a public and a private DNS zone in Azure?

Why they ask this: A basic concept check.

How you might answer: A public zone answers queries from anywhere on the internet once the domain is delegated to Azure’s name servers. A private zone answers only for VNets that are linked to it, so internal names never leak outside.

2. What does 168.63.129.16 do for DNS?

Why they ask this: They want to see you know the Azure resolver.

How you might answer: It’s the Azure-provided DNS resolver that every VM uses by default. It answers from linked private zones first, then resolves public names on the internet.

3. What is auto-registration in a private DNS zone?

Why they ask this: A feature check with a useful limit.

How you might answer: When a VNet link has auto-registration on, VMs in that VNet automatically get A records in the zone and lose them when they’re deleted. A VNet can have only one zone with auto-registration.

2–5 years experience

4. An app in a new VNet can’t resolve db.corp.internal, but it works everywhere else. What do you check?

Why they ask this: They want the most likely cause first.

How you might answer: First whether the private zone is linked to the new VNet; that’s the usual reason. Then whether the VNet uses custom DNS servers that don’t forward to Azure. I’d test with getent hosts or nslookup from a VM in that VNet.

5. How do you plan a DNS change during a migration?

Why they ask this: They’re checking TTL awareness.

How you might answer: I’d lower the record’s TTL to a minute or so at least one full old-TTL period before the change, so caches expire quickly. After the cutover is stable, I raise it back. I’d also make the old system read-only so stale clients fail clearly.

6. You created a public zone in Azure but the domain doesn’t resolve on the internet. Why?

Why they ask this: They want delegation understanding.

How you might answer: The domain isn’t delegated yet. The registrar still points to the old name servers. I’d copy the four Azure name servers from the zone and set them as the NS records at the registrar, then wait for the TLD’s TTLs.

Senior level

7. How would you design DNS for a hub-and-spoke network with on-premises servers?

Why they ask this: They want a scalable, hybrid DNS design.

How you might answer: I’d keep private zones, including privatelink zones, in a central subscription and link them to the hub and every spoke. Azure DNS Private Resolver in the hub handles on-premises lookups for Azure names, with an inbound endpoint, and forwards Azure workloads’ lookups for on-premises names to the company DNS servers through an outbound endpoint.

Spokes use Azure DNS, and a policy or pipeline step links new spokes to the zones automatically.

8. What are the risks of every team creating their own private DNS zones?

Why they ask this: They’re testing governance thinking.

How you might answer: Duplicate zones for the same name, especially privatelink zones, cause split answers depending on which VNet asks. Links get forgotten, and nobody knows who owns which record.

I’d centralise shared zones, give teams write access to their own records, and use Azure Policy to stop duplicate privatelink zones.

9. Why is .internal a good choice for private zones?

Why they ask this: They want awareness of naming risks.

How you might answer: ICANN reserved .internal for private use, so it won’t ever become a public top-level domain and clash with real internet names. Made-up suffixes like .corp or .local have caused problems in the past.

Quick quiz

Q1. Which VNets can resolve names in a private DNS zone?

  1. Every VNet in the subscription
  2. Only VNets linked to the zone
  3. Only the VNet in the same resource group
  4. Any VNet in the region
Show answer

B — Only linked VNets get answers from the zone.

Q2. What is the default DNS resolver address for Azure VMs?

  1. 8.8.8.8
  2. 10.30.0.1
  3. 168.63.129.16
  4. 127.0.0.53 only
Show answer

C — 168.63.129.16 is the Azure-provided resolver.

Q3. A new public zone answers on Azure’s name servers but not on the internet. Why?

  1. TTL too long
  2. The domain isn’t delegated at the registrar
  3. Private zone conflict
  4. Wrong record type
Show answer

B — You must set Azure’s NS records at the registrar.

Q4. How many private zones with auto-registration can one VNet have?

  1. One
  2. Two
  3. Ten
  4. Unlimited
Show answer

A — Only one zone can auto-register a VNet’s VMs.

Q5. Why lower a TTL before a migration?

  1. To save money
  2. So caches expire quickly and clients pick up the new IP
  3. To make DNS more secure
  4. Azure requires it
Show answer

B — Short TTLs mean old answers don’t live long in caches.

Quick recap

You can now make names work inside Azure, and you know the two quiet reasons they stop working.

  • Private zones answer only in linked VNets; public zones answer the internet after delegation.
  • VMs ask 168.63.129.16, which checks linked private zones first.
  • Auto-registration adds VM records for you; one such zone per VNet.
  • Lower TTLs before a change; CNAMEs aren’t allowed at the apex.
  • Missing VNet links cause many private endpoint and app problems later.

Next lesson

Lesson 15: Create your first Azure VM (Linux) → You build a proper Linux VM, connect to it safely and learn what each choice in az vm create means.

Further reading: Azure private DNS zone

Want to go deeper into Azure private DNS zone? See Microsoft’s What is an Azure private DNS zone? and Delegate a domain to Azure DNS. You can also see the full plan for this course on the Azure Cloud Administration course page.

Scroll to Top