App Service with VNet Integration fails to resolve private DNS names
Fix DNS resolution in App Service with VNet Integration: configure Private DNS Zones, VNet links and WEBSITE_DNS_SERVER.
This runbook covers DNS resolution issues in App Service with VNet Integration and Private Endpoints. For a full guide on migrating .NET infrastructure to Azure, see Migrating .NET Workloads to Azure - App Service, AKS, Landing Zone. For network architecture and Private Link guidance, book a consulting session.
Symptoms
The connection from App Service to a resource with a Private Endpoint times out or fails. The Kudu console (Advanced Tools) shows a public IP instead of a private one:
# In Kudu console (https://<app-name>.scm.azurewebsites.net)
# Tools > Debug console > CMD or PowerShell
# nslookup returns public IP instead of private (10.x.x.x)
nameresolver mysqlserver.database.windows.net
# Problematic result: returns e.g. 52.168.112.64 (public)
# Correct result: should return e.g. 10.0.1.5 (private from Private Endpoint)
# Alternatively via PowerShell in Kudu
[System.Net.Dns]::GetHostAddresses("mysqlserver.database.windows.net") | Select IPAddressToString
# Problematic result: 52.168.112.64
# Correct result: 10.0.1.5
# Check whether WEBSITE_DNS_SERVER is set
env | grep DNS
# If no WEBSITE_DNS_SERVER entry - that is part of the problem
# TCP connectivity test to Private Endpoint
tcpping mysqlserver.database.windows.net:1433
# Problematic result: Connection timed out or connects to public IP
The application logs errors such as “Connection timed out” or “Login failed” (if the resource firewall only allows Private Endpoint access). Application Insights shows dependency failures to Azure SQL or Storage.
Cause
App Service with VNet Integration requires correct DNS configuration to resolve Private Endpoint names to private addresses. The problem occurs when:
-
Private DNS Zone is not linked to the VNet: The zone
privatelink.database.windows.net(or the appropriate zone for the resource) exists but has no VNet Link to the VNet containing the App Service integration subnet. Without the link, DNS queries from the VNet do not reach the Private DNS Zone. -
WEBSITE_DNS_SERVER is not set to 168.63.129.16: By default, App Service uses Azure’s public DNS servers. After enabling VNet Integration you must explicitly set
WEBSITE_DNS_SERVER=168.63.129.16(Azure DNS resolver) so that DNS queries traverse the VNet and reach Private DNS Zones. -
Route All (vnetRouteAllEnabled) is not enabled: Without this option, only traffic to RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) is routed through the VNet. DNS queries to 168.63.129.16 and other traffic may still exit outside the VNet.
-
DNS Zone name does not match the resource suffix: The Private DNS Zone must have a name that exactly matches the Private Link suffix for the service. For example, Azure SQL requires the zone
privatelink.database.windows.net- notdatabase.windows.netorprivatelink.sql.azuresynapse.net. An incorrect zone name means the A record is never found.
Fix
A) Link the Private DNS Zone to the App Service VNet:
# Check whether the Private DNS Zone exists
az network private-dns zone list \
--query "[].{name:name, records:numberOfRecordSets, links:numberOfVirtualNetworkLinks}" -o table
# Check existing VNet links for the zone
az network private-dns link vnet list \
--resource-group rg-dns \
--zone-name privatelink.database.windows.net \
--query "[].{name:name, vnetId:virtualNetwork.id, state:provisioningState}" -o table
# Add a link to the VNet containing the App Service subnet
az network private-dns link vnet create \
--resource-group rg-dns \
--zone-name privatelink.database.windows.net \
--name link-vnet-appservice \
--virtual-network /subscriptions/<sub-id>/resourceGroups/rg-network/providers/Microsoft.Network/virtualNetworks/vnet-production \
--registration-enabled false
# Verify that the A record exists in the zone
az network private-dns record-set a list \
--resource-group rg-dns \
--zone-name privatelink.database.windows.net \
--query "[].{name:name, ip:aRecords[0].ipv4Address}" -o table
# Expected: mysqlserver -> 10.0.1.5
B) Set WEBSITE_DNS_SERVER to 168.63.129.16:
# Check current app settings
az webapp config appsettings list \
--resource-group rg-app \
--name my-app-service \
--query "[?name=='WEBSITE_DNS_SERVER'].value" -o tsv
# Set Azure DNS resolver as the DNS server for App Service
az webapp config appsettings set \
--resource-group rg-app \
--name my-app-service \
--settings WEBSITE_DNS_SERVER=168.63.129.16
# Optionally - set WEBSITE_DNS_ALT_SERVER as a fallback
az webapp config appsettings set \
--resource-group rg-app \
--name my-app-service \
--settings WEBSITE_DNS_ALT_SERVER=168.63.129.16
C) Enable Route All (vnetRouteAllEnabled):
# Check current VNet Integration and Route All state
az webapp show \
--resource-group rg-app \
--name my-app-service \
--query '{vnetIntegration:virtualNetworkSubnetId, routeAll:vnetRouteAllEnabled}' -o json
# Enable Route All - all traffic from App Service will route through the VNet
az webapp update \
--resource-group rg-app \
--name my-app-service \
--set vnetRouteAllEnabled=true
# Alternatively via az resource update (for older CLI versions)
az resource update \
--resource-group rg-app \
--name my-app-service \
--resource-type Microsoft.Web/sites \
--set properties.vnetRouteAllEnabled=true
// Equivalent configuration in ARM template / Bicep
{
"type": "Microsoft.Web/sites",
"properties": {
"virtualNetworkSubnetId": "/subscriptions/<sub-id>/resourceGroups/rg-network/providers/Microsoft.Network/virtualNetworks/vnet-production/subnets/subnet-appservice",
"vnetRouteAllEnabled": true,
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_DNS_SERVER",
"value": "168.63.129.16"
}
]
}
}
}
D) Verify the DNS record in the Private DNS Zone is correct:
# Check the correct Private DNS Zone name for each Azure service:
# Azure SQL Database: privatelink.database.windows.net
# Azure Blob Storage: privatelink.blob.core.windows.net
# Azure Key Vault: privatelink.vaultcore.azure.net
# Azure Cosmos DB: privatelink.documents.azure.com
# Azure Service Bus: privatelink.servicebus.windows.net
# Check whether the Private Endpoint was correctly registered in the zone
az network private-endpoint dns-zone-group list \
--resource-group rg-data \
--endpoint-name pe-sqlserver \
--query "[].{zone:privateDnsZoneConfigs[0].privateDnsZoneId, records:privateDnsZoneConfigs[0].recordSets}" -o json
# If the record does not exist - add it manually (or fix the dns-zone-group)
az network private-dns record-set a add-record \
--resource-group rg-dns \
--zone-name privatelink.database.windows.net \
--record-set-name mysqlserver \
--ipv4-address 10.0.1.5
# Check that the Private Endpoint has the correct IP in the subnet
az network private-endpoint show \
--resource-group rg-data \
--name pe-sqlserver \
--query '{ip:customDnsConfigs[0].ipAddresses[0], fqdn:customDnsConfigs[0].fqdn, subnet:subnet.id}' -o json
After applying changes, the App Service may need a restart to flush the DNS cache:
# Restart App Service
az webapp restart \
--resource-group rg-app \
--name my-app-service
Verification
# 1. In Kudu console - check that DNS resolves to a private IP
# https://<app-name>.scm.azurewebsites.net > Debug console > CMD
nameresolver mysqlserver.database.windows.net
# Expected: Addresses: 10.0.1.5 (private IP from the Private Endpoint subnet)
# 2. In Kudu PowerShell - DNS resolution test
[System.Net.Dns]::GetHostAddresses("mysqlserver.database.windows.net") | Select IPAddressToString
# Expected: 10.0.1.5
# 3. TCP connectivity test to Private Endpoint
tcpping mysqlserver.database.windows.net:1433
# Expected: Connected to mysqlserver.database.windows.net:1433, time=Xms
# 4. Confirm configuration is complete via Azure CLI
az webapp show \
--resource-group rg-app \
--name my-app-service \
--query '{routeAll:vnetRouteAllEnabled, vnet:virtualNetworkSubnetId}' -o json
# Expected: routeAll=true, vnet points to the integration subnet
az webapp config appsettings list \
--resource-group rg-app \
--name my-app-service \
--query "[?name=='WEBSITE_DNS_SERVER'].{name:name, value:value}" -o table
# Expected: WEBSITE_DNS_SERVER = 168.63.129.16
If nameresolver returns a private IP (10.x.x.x) and tcpping connects successfully - the issue is resolved. Verify in Application Insights that dependency calls to Azure SQL/Storage no longer generate errors.
Private Endpoints not working despite VNet Integration?
Book a free 30-minute call. We will review your DNS configuration, Private Link and VNet Integration to ensure traffic flows securely over the Azure private network.