Cloud & infrastructure

Fix Azure private endpoint DNS from on-premises with DNS Private Resolver

Stop private endpoints resolving to public IP addresses from on-premises and VPN clients: link the privatelink zone, add a DNS Private Resolver inbound endpoint and forward the right zones.

11 min read
On this page

A private endpoint resolves to a public IP from on-premises because public DNS answers the service name with a CNAME to its privatelink name, and only a resolver inside a virtual network linked to your Azure private DNS zone can turn that name into the endpoint's private IP. The fix is to deploy an Azure DNS Private Resolver inbound endpoint in the virtual network linked to the privatelink zones, then add conditional forwarders on your on-premises DNS servers for the service's public zone, such as blob.core.windows.net, pointing at the inbound endpoint's IP. Azure virtual networks and point-to-site VPN clients that use custom DNS should point at the same inbound endpoint.

Who this is for and what you will have

This guide is for network and infrastructure administrators who have deployed private endpoints for Azure Storage, SQL Database, Key Vault or other PaaS services and find that on-premises servers, VPN users or spokes with custom DNS still connect to the public endpoint, or fail outright once public access is disabled. At the end you will have:

  • A clear picture of the CNAME chain and why each client gets the answer it gets.
  • Private DNS zones created once in the hub and populated automatically by DNS zone groups.
  • A DNS Private Resolver inbound endpoint that on-premises DNS can forward to.
  • Conditional forwarders on Windows Server DNS for the correct zones.
  • A troubleshooting checklist for the cases that still return public IPs or NXDOMAIN.

Why private endpoints resolve to public IP addresses

When you create a private endpoint, Azure publishes a CNAME in public DNS that points the service's normal name to a name in a privatelink subdomain. Your connection strings don't change; what changes is who answers the privatelink name.

contosostorage.blob.core.windows.net
  -> CNAME contosostorage.privatelink.blob.core.windows.net   (public DNS, visible to everyone)
       |
       +-- Resolver in a VNet linked to privatelink.blob.core.windows.net
       |     -> A 10.0.4.5   (private endpoint)
       |
       +-- Any other resolver (on-premises DNS, ISP, public DNS)
             -> public CNAME chain continues -> public IP address

Inside Azure, a VM using the Azure-provided DNS server (168.63.129.16) in a virtual network linked to the private zone gets the private IP. Microsoft's quickstart shows the shape of a correct answer:

Server:  UnKnown
Address:  168.63.129.16
 
Non-authoritative answer:
Name:    webapp-1.privatelink.azurewebsites.net
Address:  10.0.0.10
Aliases:  webapp-1.azurewebsites.net

On-premises DNS servers can't query 168.63.129.16, which only the Azure platform can reach, and Microsoft states that DNS queries for private endpoints must originate from the virtual network linked to the private DNS zone. So the on-premises server follows the public chain and returns the public address. A successful public lookup grants nothing: if Public network access is disabled on the resource, the service rejects those connections, which is often how the problem is noticed.

Prerequisites

  • A hub virtual network connected to on-premises over VPN or ExpressRoute; the resolver needs this path. The hub-and-spoke network with Azure Firewall post covers the topology.
  • A free IPv4 range of at least /28 for the inbound endpoint, and another /28 if you'll also forward Azure queries to on-premises.
  • The Microsoft.Network resource provider registered, and the Az.Network, Az.PrivateDns and Az.DnsResolver PowerShell modules (Install-Module Az.DnsResolver).
  • Rights to create conditional forwarders on your on-premises DNS servers.
  • The private DNS zone name and public forwarder zone for each service, from Microsoft's private endpoint DNS zone table. Common values:
ServiceSubresourcePrivate DNS zoneZone to forward from on-premises
Storageblobprivatelink.blob.core.windows.netblob.core.windows.net
Storagefileprivatelink.file.core.windows.netfile.core.windows.net
Data Lake Storage Gen2dfsprivatelink.dfs.core.windows.netdfs.core.windows.net
Azure SQL DatabasesqlServerprivatelink.database.windows.netdatabase.windows.net
Key Vaultvaultprivatelink.vaultcore.azure.netvault.azure.net and vaultcore.azure.net
Web Apps and Functionssitesprivatelink.azurewebsites.netazurewebsites.net

Use the recommended zone names exactly. Microsoft notes that automatic record creation only works with the recommended naming scheme.

Step 1: Create the private DNS zones once, in the hub

Create one zone per privatelink name, link it to the hub virtual network, and reuse it for every private endpoint of that service type. Microsoft warns that you need a single zone per name for the hub-and-spoke and hybrid scenarios; several zones with the same name for different virtual networks need manual record merging.

$hub = Get-AzVirtualNetwork -Name 'vnet-hub' -ResourceGroupName 'rg-hub'
 
$zone = New-AzPrivateDnsZone -ResourceGroupName 'rg-dns' -Name 'privatelink.blob.core.windows.net'
 
New-AzPrivateDnsVirtualNetworkLink -ResourceGroupName 'rg-dns' `
    -ZoneName 'privatelink.blob.core.windows.net' -Name 'link-vnet-hub' `
    -VirtualNetworkId $hub.Id

Spokes that keep using Azure-provided DNS need their own links to the same zone. Spokes that use the resolver as their DNS server (Step 5) don't, because the resolver answers from the hub.

Step 2: Attach private endpoints to the zone with a DNS zone group

A DNS zone group ties a private endpoint to the zone, creates its A records and deletes them when the endpoint is removed. Create the endpoint in a spoke and the zone group against the hub zone:

$sa = Get-AzStorageAccount -ResourceGroupName 'rg-data' -Name 'contosostorage'
$spoke = Get-AzVirtualNetwork -Name 'vnet-spoke1' -ResourceGroupName 'rg-spoke1'
 
$pls = New-AzPrivateLinkServiceConnection -Name 'pls-contosostorage-blob' `
    -PrivateLinkServiceId $sa.Id -GroupId 'blob'
 
New-AzPrivateEndpoint -ResourceGroupName 'rg-data' -Name 'pe-contosostorage-blob' `
    -Location 'westeurope' -Subnet ($spoke.Subnets | Where-Object Name -eq 'snet-pe') `
    -PrivateLinkServiceConnection $pls
 
$cfg = New-AzPrivateDnsZoneConfig -Name 'privatelink.blob.core.windows.net' `
    -PrivateDnsZoneId $zone.ResourceId
 
New-AzPrivateDnsZoneGroup -ResourceGroupName 'rg-data' `
    -PrivateEndpointName 'pe-contosostorage-blob' -Name 'default' `
    -PrivateDnsZoneConfig $cfg

Each private endpoint supports one zone group, each group up to five zones, and only one zone per zone name. Don't put records for different services in the same zone.

Step 3: Deploy DNS Private Resolver with an inbound endpoint

The resolver lives in the hub virtual network and can only reference a virtual network in its own region. One resolver per virtual network; multiple resolvers can't share one. The inbound endpoint gets an IP from a dedicated subnet that can only be delegated to Microsoft.Network/dnsResolvers. A dynamic address only changes if the endpoint is reprovisioned, but a static address can be specified again on reprovisioning, so on-premises forwarders never need updating.

$hub = Get-AzVirtualNetwork -Name 'vnet-hub' -ResourceGroupName 'rg-hub'
Add-AzVirtualNetworkSubnetConfig -Name 'snet-dns-inbound' -VirtualNetwork $hub -AddressPrefix '10.0.5.0/28'
$hub | Set-AzVirtualNetwork
 
New-AzDnsResolver -Name 'dnspr-hub' -ResourceGroupName 'rg-hub' -Location 'westeurope' `
    -VirtualNetworkId $hub.Id
 
$subnetId = "$($hub.Id)/subnets/snet-dns-inbound"
$ipconfig = New-AzDnsResolverIPConfigurationObject -PrivateIPAddress 10.0.5.4 `
    -PrivateIPAllocationMethod Static -SubnetId $subnetId
 
New-AzDnsResolverInboundEndpoint -DnsResolverName 'dnspr-hub' -Name 'in-hub' `
    -ResourceGroupName 'rg-hub' -Location 'westeurope' -IpConfiguration $ipconfig

Confirm the resolver reports Connected and the endpoint has the address:

(Get-AzDnsResolver -Name 'dnspr-hub' -ResourceGroupName 'rg-hub').ToJsonString()
(Get-AzDnsResolverInboundEndpoint -Name 'in-hub' -DnsResolverName 'dnspr-hub' -ResourceGroupName 'rg-hub').ToJsonString()

Microsoft lists 10,000 queries per second per endpoint and up to five inbound endpoints per resolver. The resolver doesn't support virtual networks with encryption enabled, ExpressRoute FastPath, or IPv6-enabled subnets.

Step 4: Add conditional forwarders on-premises

On each on-premises DNS server, forward the service's public zone, not the privatelink zone, to the inbound endpoint. Microsoft is explicit: conditional forwarding must be made to the recommended public DNS zone forwarder, for example database.windows.net instead of privatelink.database.windows.net. On Windows Server DNS, this creates Active Directory-integrated forwarders replicated to all DNS servers running on domain controllers in the forest:

Add-DnsServerConditionalForwarderZone -Name 'blob.core.windows.net' `
    -MasterServers 10.0.5.4 -ReplicationScope 'Forest'
 
Add-DnsServerConditionalForwarderZone -Name 'database.windows.net' `
    -MasterServers 10.0.5.4 -ReplicationScope 'Forest'

Why the public zone: the on-premises server must hand the whole chain to Azure. The resolver receives contosostorage.blob.core.windows.net, follows the CNAME to privatelink.blob.core.windows.net, finds the record in the linked private zone and returns the private IP. For storage accounts with no private endpoint anywhere, Azure resolves the public address as normal. Accounts with private endpoints in other tenants are the exception, covered under troubleshooting.

Forwarding a public zone sends every lookup in it to Azure, so the VPN or ExpressRoute path and the resolver become dependencies for those names. Point each forwarder at more than one IP if you deploy resolvers in a second region.

Step 5: Point Azure clients and VPN users at the resolver

Inside Azure there are two patterns:

  • Spokes keep Default (Azure-provided) DNS and you link every spoke to every privatelink zone.
  • Spokes set DNS servers to Custom with the inbound endpoint IP, so everything resolves through the hub and only the hub needs zone links.

The second pattern also fixes point-to-site VPN clients. VPN Gateway pushes the virtual network's DNS servers to point-to-site clients, but when the virtual network uses 168.63.129.16, clients can't resolve private zones. Setting the inbound endpoint as the virtual network's custom DNS server makes private endpoint names work for users connected with the Azure VPN Client; the point-to-site VPN with Entra ID post covers the client side. VMs pick up changed DNS server settings after a restart.

If Azure workloads also need on-premises names, add an outbound endpoint in its own /28, a DNS forwarding ruleset with rules such as corp.contoso.com. (note the trailing dot) pointing at on-premises DNS servers, and link the ruleset to the virtual networks that need it. Don't link the resolver's own virtual network to a ruleset that contains a rule targeting its own inbound endpoint; Microsoft warns that creates a resolution loop. If you add a wildcard . rule, its target must be able to resolve public names, because some Azure services depend on public resolution.

If Azure Firewall acts as a DNS proxy for your spokes, set its upstream DNS server to the inbound endpoint. Microsoft notes that queries sent to the firewall's DNS proxy are only resolved from private DNS zones if the configured upstream server has access to them.

Verification

From an on-premises server, query the normal service name:

nslookup contosostorage.blob.core.windows.net
nslookup contosostorage.blob.core.windows.net 10.0.5.4

Both answers should list contosostorage.privatelink.blob.core.windows.net as the name and the private endpoint IP as the address. If the second query is correct and the first isn't, the on-premises forwarder is the problem. If both are wrong, check the zone link and records in Azure. Repeat from a spoke VM and from a connected VPN client, then test the application connection itself with public network access disabled on the resource.

Troubleshooting

Still getting the public IP from on-premises. In order: the conditional forwarder is for the privatelink zone instead of the public zone; it points at an address that isn't the inbound endpoint; the private zone isn't linked to the resolver's virtual network; the A record is missing because the endpoint has no zone group or used a non-standard zone name; or DNS servers and clients are still serving a cached public answer until its TTL expires.

Resolves correctly in one spoke but not another. That spoke uses Azure-provided DNS and isn't linked to the zone, or it's linked to a second, separate zone with the same name that lacks the record. Consolidate to one zone per name.

NXDOMAIN for a storage account in another tenant or subscription. Once your network resolves privatelink.blob.core.windows.net privately, any account with a private endpoint connection whose record isn't in your zone returns NXDOMAIN. Select Enable fallback to internet on the zone's virtual network link (resolution policy NxDomainRedirect) so Azure retries publicly. Microsoft advises against adding manual A records with public IPs, because they won't update when the address changes.

Records disappeared after creating a second endpoint. A zone linked to one service was associated with a different service's private endpoint, which deletes the original A record. Use a separate zone per service type.

Point-to-site users can't resolve private endpoints. The virtual network still uses 168.63.129.16. Set its custom DNS server to the inbound endpoint and have users reconnect.

Azure Bastion or Azure Firewall broke after linking zones. Never create private zones named exactly blob.core.windows.net, core.windows.net, vault.azure.net, management.azure.com or azure.com; use the privatelink names. Microsoft warns that overriding these names can break both services.

Azure Files still uses the public endpoint. Microsoft notes file shares must be remounted if they were connected to the public endpoint.

Closing checklist

  • One privatelink zone per service type, using Microsoft's recommended names, linked to the hub.
  • Every private endpoint has a DNS zone group pointing at the hub zone.
  • DNS Private Resolver in the hub with a static inbound endpoint IP in a dedicated /28.
  • On-premises conditional forwarders for the public zones, pointing at the inbound endpoint.
  • Spokes and the gateway virtual network use the inbound endpoint as custom DNS, or are linked to every zone.
  • Fallback to internet enabled where you must reach other tenants' Private Link resources.
  • nslookup from on-premises, a spoke and a VPN client all return private IPs.

References

Questions people ask

Why does my private endpoint resolve to a public IP from on-premises?

Public DNS always returns a CNAME from the service name to its privatelink name. Only a resolver that can see your Azure private DNS zone answers that privatelink name with the private IP. On-premises DNS servers can't, so the public chain continues to the public address until you forward the query into Azure.

Should my conditional forwarder be for blob.core.windows.net or privatelink.blob.core.windows.net?

Forward the public zone, for example blob.core.windows.net or database.windows.net, not the privatelink zone. Microsoft states the conditional forwarding must be made to the recommended public DNS zone forwarder listed for each service.

Can on-premises DNS servers forward straight to 168.63.129.16?

No. Only the Azure platform can reach the Azure-provided DNS address 168.63.129.16, and private endpoint queries must originate from a virtual network linked to the private DNS zone. Forward to a DNS Private Resolver inbound endpoint or a DNS forwarder running in Azure instead.

What subnet does a DNS Private Resolver inbound endpoint need?

A dedicated subnet between /28 and /24 that can only be delegated to Microsoft.Network/dnsResolvers. Inbound and outbound endpoints can't share a subnet, and IPv6-enabled subnets aren't supported.

Azure Private LinkAzure Private DNSAzure DNS Private ResolverAzure StorageWindows Server DNS
  1. A practical Azure landing zone for small and mid-size companies

    Set up Azure management groups, subscriptions, hub-and-spoke networking, Azure Policy, RBAC and budgets the right way from day one, scaled down from Microsoft's landing zone architecture.

  2. Amazon S3 for Azure admins: secure buckets with IAM and bucket policies

    Map Amazon S3 buckets, IAM policies, bucket policies, Block Public Access and presigned URLs to Azure Blob Storage, Azure RBAC and SAS, then build a locked down bucket with the AWS CLI.

  3. Autopilot device preparation vs classic Autopilot: choosing the right one

    Compare Windows Autopilot device preparation and classic Windows Autopilot on join types, modes, app limits, registration, ESP and reporting, and pick the right one for each device population.