App Service Networking
VNet integration, Private Endpoints, Access Restrictions, and Hybrid Connections.
Feature Availability by SKU
| Feature | Free | Basic | Standard | Premium | Isolated |
|---|---|---|---|---|---|
| VNet integration (outbound) | ❌ | ✅ | ✅ | ✅ | ✅ (native) |
| Private Endpoints (inbound) | ❌ | ✅ | ✅ | ✅ | ✅ |
| Access Restrictions | ✅ | ✅ | ✅ | ✅ | ✅ |
| Hybrid Connections | ❌ | 5 | 25 | 200 | 200 |
| Access to service-endpoint-protected resources | ❌ | ✅ | ✅ | ✅ | ✅ |
Note: Service endpoints are configured on VNets/subnets and downstream services (e.g., Storage, SQL). App Service accesses them via VNet integration rather than enabling service endpoints directly on the app.
VNet Integration (Outbound)
Routes outbound traffic from the app through a VNet subnet, enabling access to private resources (databases, storage, VMs).
Subnet Requirements
| Requirement | Value |
|---|---|
| Minimum subnet size | /26 (64 addresses) recommended |
| Delegation | Microsoft.Web/serverFarms |
| Dedicated | One subnet per App Service plan |
Bicep — VNet Integration
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' = {
parent: vnet
name: 'app-service-subnet'
properties: {
addressPrefix: '10.0.1.0/26'
delegations: [
{
name: 'Microsoft.Web.serverFarms'
properties: { serviceName: 'Microsoft.Web/serverFarms' }
}
]
}
}
resource webApp 'Microsoft.Web/sites@2024-11-01' = {
name: appName
location: location
properties: {
serverFarmId: appServicePlan.id
virtualNetworkSubnetId: subnet.id
outboundVnetRouting: {
allTraffic: true // route all outbound through VNet
}
}
}CLI - VNet Integration
# Configure virtual network integration
az webapp vnet-integration add --resource-group RG --name APP --vnet VNET --subnet SUBNET
# Update app configuration to route all outbound traffic through the virtual network integration
az resource update --resource-group RG --name APP --resource-type "Microsoft.Web/sites" --set properties.outboundVnetRouting.allTraffic=true💡 Tip: Set
outboundVnetRouting.allTraffic: trueto route ALL outbound traffic through the VNet. Without this, only RFC1918 traffic is routed through the VNet.
Private Endpoints (Inbound)
Expose the app on a private IP address within your VNet. Public access can be disabled entirely.
Bicep — Private Endpoint
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = {
name: '${appName}-pe'
location: location
properties: {
subnet: { id: privateEndpointSubnet.id }
privateLinkServiceConnections: [
{
name: '${appName}-connection'
properties: {
privateLinkServiceId: webApp.id
groupIds: ['sites']
}
}
]
}
}
resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.azurewebsites.net'
location: 'global'
}
resource dnsLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = {
parent: privateDnsZone
name: '${vnet.name}-link'
location: 'global'
properties: {
virtualNetwork: { id: vnet.id }
registrationEnabled: false
}
}
resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-11-01' = {
parent: privateEndpoint
name: 'default'
properties: {
privateDnsZoneConfigs: [
{
name: 'webapp-dns-zone'
properties: {
privateDnsZoneId: privateDnsZone.id
}
}
]
}
}CLI - Private Endpoint
# Retrieve web app resource id
id=$(az webapp show --name APP --resource-group RG --query id --output tsv)
# Create Private Endpoint
az network private-endpoint create --connection-name CONNECTIONNAME --name private-endpoint --private-connection-resource-id $id --resource-group RG --subnet SUBNET --group-id sites --vnet-name VNET
# Create Private DNS Zone
az network private-dns zone create --resource-group RG --name "privatelink.azurewebsites.net"
# Link the DNS Zone to virtual network
az network private-dns link vnet create --resource-group RG --zone-name "privatelink.azurewebsites.net" --name dns-link --virtual-network VNET --registration-enabled false
⚠️ Warning: Private Endpoints require Basic (B1+) or higher tier. The private DNS zone
privatelink.azurewebsites.netmust be linked to the VNet for name resolution.
Access Restrictions
Control inbound access with IP-based or service-tag rules. Available on all SKUs.
Bicep — Access Restrictions
siteConfig: {
ipSecurityRestrictions: [
{
name: 'allow-office'
priority: 100
action: 'Allow'
ipAddress: '203.0.113.0/24'
}
{
name: 'deny-all'
priority: 2147483647
action: 'Deny'
ipAddress: 'Any'
}
]
scmIpSecurityRestrictionsUseMain: true
}CLI - Access Restrictions
# Add restriction to allow traffic from set range used by the office
az webapp config access-restriction add --resource-group RG --name APP --rule-name 'allow-office' --action Allow --ip-address 203.0.113.0/24 --priority 100
# Add restriction to deny access from any other address range
az webapp config access-restriction add --resource-group RG --name APP --rule-name 'deny-all' --action Deny --ip-address Any --priority 2147483647
# Set SCM Site (Kudu) to use same access restrictions as main site
az webapp config access-restriction set -g RG -n APP --use-same-restrictions-for-scm-site true💡 Tip: Always restrict the SCM/Kudu site too. Use
scmIpSecurityRestrictionsUseMain: trueto inherit main site rules, or define separate SCM rules.
Hybrid Connections
Connect to on-premises resources without VPN. Requires Basic tier or higher. Uses Hybrid Connection Manager (HCM) agent on-premises relaying through Azure Relay.
⚠️ Warning: Each Hybrid Connection maps to a single host:port endpoint. Basic tier supports 5; Standard tier supports 25; Premium/Isolated support 200.
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Cannot reach private DB | VNet integration not enabled | Enable VNet integration; check outboundVnetRouting.allTraffic |
| DNS resolution fails | Private DNS zone not linked | Link privatelink.* DNS zone to VNet |
| Access restriction not working | Priority ordering wrong | Lower numbers = higher priority; check rule order |
| Hybrid Connection timeout | HCM not running | Verify HCM service status on-premises |
| Outbound traffic blocked | NSG rules on subnet | Allow outbound to required services in NSG |