DNS Resolution Problems in Azure
DNS resolution failures in Azure are nearly always silent — the connection attempt fails or routes to the wrong IP without an obvious DNS error message. This page covers the four most common Azure DNS failure patterns, the diagnostic commands to run from inside a VM, and how to fix private endpoint resolution, custom DNS server issues, and TTL-related migration problems.
The four DNS failure patterns in Azure
Before diagnosing, identify which failure pattern you are seeing:
- VM cannot resolve public DNS — the VM cannot reach external websites or resolve Azure service endpoints. Usually a custom DNS server on the VNet that is misconfigured or unreachable.
- Private endpoint resolves to public IP — a service with a private endpoint returns its public IP instead of the private IP, causing connections to fail or bypass the private network path.
- Split-horizon DNS not working — a DNS name should resolve differently from inside the VNet versus outside, but it resolves the same from both places.
- DNS caching causing stale resolution during migration — after reconfiguring DNS (changing from public to private endpoint, changing a VNet’s DNS server), VMs continue using the old cached answer until the TTL expires.
The diagnostic starting point for all four patterns is the same: run nslookup from inside the affected VM.
Testing DNS resolution from inside a VM
SSH into the VM and run basic DNS diagnostics:
# Test basic public DNS resolution
nslookup google.com
nslookup google.com 168.63.129.16 # Force Azure DNS
# Test a private endpoint resource
nslookup myaccount.blob.core.windows.net
nslookup myaccount.blob.core.windows.net 168.63.129.16
# Check which DNS server the VM is configured to use
cat /etc/resolv.conf
# or on newer Ubuntu
resolvectl status
# Verbose nslookup showing full resolution path
nslookup -debug myaccount.blob.core.windows.netOn Windows VMs:
# Test DNS resolution
Resolve-DnsName myaccount.blob.core.windows.net
Resolve-DnsName myaccount.blob.core.windows.net -Server 168.63.129.16
# Show DNS client configuration
Get-DnsClientServerAddress
ipconfig /all | findstr "DNS Servers"
# Flush DNS cache
ipconfig /flushdnsThe key question is whether the resolved IP is a private IP (10.x.x.x or 172.16.x.x or 192.168.x.x) or a public IP. For private endpoint resources, it must be a private IP.
Failure 1: VM cannot resolve public DNS
If nslookup times out for public names but other VMs in the same region work, the VNet has a custom DNS server configured that is either unreachable or misconfigured.
Check the DNS server configuration on the VNet:
az network vnet show \
--resource-group myResourceGroup \
--name myVNet \
--query "dhcpOptions.dnsServers" \
--output jsonIf this returns a list of IP addresses (e.g., ["10.1.1.4"]), the VNet is using a custom DNS server. That server must:
- Be reachable from the VNet on port 53 (UDP and TCP)
- Be running and accepting queries
- Forward unresolved queries to Azure DNS (168.63.129.16) to resolve Azure internal names
Test if the custom DNS server is reachable from the VM:
# Test UDP DNS port
nc -u -z -v 10.1.1.4 53
# Test a query against the custom server directly
nslookup google.com 10.1.1.4To fall back to Azure DNS temporarily, reset the VNet DNS configuration to default:
az network vnet update \
--resource-group myResourceGroup \
--name myVNet \
--dns-servers ""VMs must be restarted or their DHCP leases renewed to pick up the new DNS server after a VNet change.
Failure 2: Private endpoint resolving to public IP
When a service like Azure Blob Storage has a private endpoint configured but nslookup still returns the public IP, the private DNS zone is missing, not linked, or the VM is not using Azure DNS.
The resolution chain for private endpoints requires all of the following:
- A private DNS zone named
privatelink.blob.core.windows.net(for Blob Storage) - An A record in that zone pointing
myaccountto the private IP - A VNet link connecting the private DNS zone to the VNet containing the VM
- The VM using Azure DNS (168.63.129.16) directly or via a forwarder
Check if the private DNS zone exists and is linked:
# List all private DNS zones in the resource group
az network private-dns zone list \
--resource-group myResourceGroup \
--output table
# Check VNet links for the relevant zone
az network private-dns link vnet list \
--resource-group myResourceGroup \
--zone-name privatelink.blob.core.windows.net \
--output tableCheck A records in the zone:
az network private-dns record-set a list \
--resource-group myResourceGroup \
--zone-name privatelink.blob.core.windows.net \
--output tableExpected output should show myaccount with an IP in the VNet’s private range. If the A record is missing, the private endpoint’s DNS configuration was not set up when the endpoint was created. Re-create the private endpoint with automatic DNS integration enabled:
az network private-endpoint create \
--resource-group myResourceGroup \
--name myBlobPrivateEndpoint \
--vnet-name myVNet \
--subnet mySubnet \
--private-connection-resource-id "/subscriptions/$SUB_ID/resourceGroups/$RG/providers/Microsoft.Storage/storageAccounts/myaccount" \
--connection-name myBlobConnection \
--group-id blob \
--private-dns-zone-group-name "blobPrivateDnsZoneGroup" \
--private-dns-zones "privatelink.blob.core.windows.net"A VNet link on a private DNS zone can have registration enabled (auto-register VM hostnames) or disabled. For private endpoint zones, registration is typically disabled because the A records are managed by the private endpoint, not by DHCP registration. Enabling registration on these zones can create conflicting records.
Failure 3: Split-horizon DNS not resolving correctly
Split-horizon DNS serves different answers for the same name depending on whether the query comes from inside or outside the VNet. Azure achieves this with private DNS zones. If both inside and outside the VNet get the same (public) answer, the conditional forwarder on the custom DNS server is missing.
In an architecture where a custom DNS server (Windows DNS server or BIND on a VM) is used:
- The VNet’s DNS server points to the custom server (e.g., 10.1.1.4)
- The custom server must have a conditional forwarder for the private zone names
- That forwarder must point to Azure DNS at 168.63.129.16
Without the conditional forwarder, the custom server resolves public DNS names using its upstream public DNS resolvers and never consults Azure’s private DNS zones.
On a Windows DNS server (run via PowerShell):
# Add conditional forwarder for private endpoint zones
Add-DnsServerConditionalForwarderZone `
-Name "privatelink.blob.core.windows.net" `
-MasterServers 168.63.129.16
Add-DnsServerConditionalForwarderZone `
-Name "privatelink.database.windows.net" `
-MasterServers 168.63.129.16
Add-DnsServerConditionalForwarderZone `
-Name "privatelink.vaultcore.azure.net" `
-MasterServers 168.63.129.16On a BIND server (add to named.conf):
zone "privatelink.blob.core.windows.net" {
type forward;
forwarders { 168.63.129.16; };
};After adding the conditional forwarder, flush the DNS cache on the custom server and test from the VM.
Failure 4: DNS caching during migration
When you change from a public endpoint to a private endpoint, or when you change the VNet’s DNS server, existing VMs continue using the cached DNS answer until the TTL expires. Azure DNS zones have a default TTL of 3600 seconds (1 hour).
Public Azure service DNS names (like myaccount.blob.core.windows.net) resolve via CNAME to a privatelink name. The CNAME TTL on the public side is typically 60 seconds. However, the final A record answer may be cached by the OS or by an intermediate DNS resolver for its full TTL.
Force a DNS cache flush on Linux:
# If using systemd-resolved
sudo systemd-resolve --flush-caches
sudo resolvectl flush-caches
# If using dnsmasq
sudo killall -HUP dnsmasq
# Direct nscd cache flush
sudo nscd -i hostsOn Windows:
ipconfig /flushdns
Clear-DnsClientCacheDuring a migration where both public and private endpoints coexist, keep the TTL low (60 seconds) until the migration is complete, then raise it back to production levels. Change the TTL on private DNS zone records:
az network private-dns record-set a update \
--resource-group myResourceGroup \
--zone-name privatelink.blob.core.windows.net \
--record-set-name myaccount \
--set ttl=60Common mistakes
- Creating the private DNS zone but forgetting to link it to the VNet. A private DNS zone exists at the Azure resource level but only answers queries from VNets it is linked to. A zone with no VNet links is effectively invisible to all VMs regardless of their DNS configuration. Always add a VNet link for every VNet whose VMs need to resolve the zone.
- Using a custom DNS server without adding conditional forwarders for private zones. When a VNet uses a custom DNS server, that server handles all queries. Without explicit conditional forwarders pointing to 168.63.129.16 for each private zone, the custom server resolves private endpoint names using public DNS and returns the public IP. Every private zone used in the environment needs a corresponding forwarder.
- Not flushing DNS cache after switching to private endpoints. VMs cache DNS answers for the TTL duration. After creating a private endpoint and linking its DNS zone, VMs with cached public IPs continue routing to the public endpoint until the cache expires. Flush the DNS cache on affected VMs and verify with nslookup before declaring the migration complete.
- Testing DNS resolution from outside the VNet. Private DNS zones only answer queries from linked VNets. Running nslookup from your laptop or from a VM in a different VNet will always return the public IP. DNS testing for private endpoints must be done from inside the VNet (or a peered VNet with the correct zone links) to get accurate results.
Summary
- Test DNS from inside the VM using nslookup — the resolved IP must be a private IP for private endpoint resources, not a public IP.
- Private endpoint DNS requires three things: a private DNS zone, an A record in that zone, and a VNet link from the zone to the VM”s VNet.
- Custom DNS servers must have conditional forwarders to 168.63.129.16 for every private zone name, or they will return public IPs for private endpoints.
- Flush the VM”s DNS cache after DNS changes — cached answers persist until TTL expiry and will override the new configuration.
Frequently asked questions
Why does nslookup from inside a VM return the public IP for a private endpoint resource?
The private DNS zone for the service (e.g., privatelink.blob.core.windows.net) is either not created, not linked to the VNet the VM is in, or the VM's DNS server is not Azure-provided DNS (168.63.129.16). All three conditions must be met: the zone must exist, have an A record for the resource, and be linked to the VM's VNet.
What is the Azure-provided DNS server IP?
Azure-provided DNS is served from the virtual IP 168.63.129.16. This IP is reachable from any Azure VM as long as the VM's network configuration uses Azure DNS (the default). This server resolves both public DNS and private DNS zones linked to the VNet.
How do I test DNS resolution from inside an Azure VM without SSH access?
Use the Azure Bastion service for SSH-less access, or run the az network watcher test-ip-flow command to verify network-layer connectivity. For DNS-specific testing without VM access, use the Azure DNS troubleshooter in the Azure portal under Virtual Networks, or deploy a temporary test VM in the same subnet.