Skip to content

VNet Integration

Enable VNet Integration so your App Service app can reach private backend services through controlled outbound networking.

Prerequisites

  • App Service Plan tier that supports VNet Integration
  • Existing virtual network and empty delegated subnet for App Service
  • Permissions to configure networking resources (VNet, NSG, private endpoints)

Main Content

Networking pattern

flowchart TD
    A[App Service] --> B[VNet Integration Subnet]
    B --> C[Private Endpoint: SQL]
    B --> D[Private Endpoint: Key Vault]
    B --> E[Private Endpoint: Redis]
    B --> F[NSG + UDR Controls]

Step 1: create delegated subnet

az network vnet subnet create \
  --resource-group "$RG" \
  --vnet-name "vnet-appservice" \
  --name "snet-appservice-integration" \
  --address-prefixes "10.10.1.0/24" \
  --delegations "Microsoft.Web/serverFarms" \
  --output json
| Flag | Description | |---|---| | az network vnet subnet create | Creates the subnet that App Service will use for VNet integration. | | --resource-group "$RG" | Targets the resource group that contains the virtual network. | | --vnet-name "vnet-appservice" | Selects the virtual network where the subnet will be created. | | --name "snet-appservice-integration" | Names the delegated integration subnet. | | --address-prefixes "10.10.1.0/24" | Allocates the subnet address range for integration instances. | | --delegations "Microsoft.Web/serverFarms" | Delegates the subnet to App Service plans for VNet integration. | | --output json | Returns the created subnet resource as JSON. |

Step 2: connect web app to subnet

az webapp vnet-integration add \
  --resource-group "$RG" \
  --name "$APP_NAME" \
  --vnet "vnet-appservice" \
  --subnet "snet-appservice-integration" \
  --output json
| Flag | Description | |---|---| | az webapp vnet-integration add | Connects the web app to the delegated subnet for outbound private networking. | | --resource-group "$RG" | Targets the resource group that contains the web app. | | --name "$APP_NAME" | Selects the web app that will join the subnet. | | --vnet "vnet-appservice" | Uses the specified virtual network for the integration. | | --subnet "snet-appservice-integration" | Attaches the app to the delegated integration subnet. | | --output json | Returns the VNet-integration configuration as JSON. |

Step 3: route all outbound traffic through VNet (optional)

az webapp config appsettings set \
  --resource-group "$RG" \
  --name "$APP_NAME" \
  --settings WEBSITE_VNET_ROUTE_ALL=1 \
  --output json
| Flag | Description | |---|---| | az webapp config appsettings set | Creates or updates app settings on the web app. | | --resource-group "$RG" | Targets the resource group that contains the web app. | | --name "$APP_NAME" | Selects the web app whose routing behavior will change. | | --settings WEBSITE_VNET_ROUTE_ALL=1 | Forces outbound traffic from the app through the integrated VNet path. | | --output json | Returns the updated app-settings payload as JSON. |

This enforces stricter egress control but requires proper route and DNS design.

Step 4: NSG baseline rules

Apply NSG to integration subnet with least privilege:

  • allow required backend ports (for example 1433, 6380, 443)
  • deny broad outbound destinations where possible
  • log NSG flow events for troubleshooting

Step 5: private endpoints for backend services

Create private endpoints for SQL/Key Vault/Redis in dedicated subnets, then link private DNS zones so app can resolve private FQDNs.

Example private DNS zones:

  • privatelink.database.windows.net
  • privatelink.vaultcore.azure.net
  • privatelink.redis.cache.windows.net

Step 6: verify DNS from app runtime

Use Kudu SSH/console and run name resolution checks to confirm private IP resolution for backend hostnames.

Inbound vs outbound

VNet Integration controls outbound from app to private services. It does not place App Service itself inside your VNet for inbound traffic.

Bicep integration concept

When codifying networking, split into modules:

  • vnet/subnet module
  • private endpoint module per backend
  • appservice integration module

Keep app and network lifecycle loosely coupled for safer operations.

App setting patterns for private dependencies

az webapp config appsettings set \
  --resource-group "$RG" \
  --name "$APP_NAME" \
  --settings \
    SPRING_DATASOURCE_URL="jdbc:sqlserver://<sql-private-fqdn>:1433;database=<db>;encrypt=true;hostNameInCertificate=*.database.windows.net;authentication=ActiveDirectoryManagedIdentity" \
    SPRING_DATA_REDIS_HOST="<redis-private-fqdn>" \
  --output json
| Flag | Description | |---|---| | az webapp config appsettings set | Creates or updates app settings on the web app. | | --resource-group "$RG" | Targets the resource group that contains the web app. | | --name "$APP_NAME" | Selects the web app whose private dependency settings will be updated. | | --settings SPRING_DATASOURCE_URL=... SPRING_DATA_REDIS_HOST=... | Stores the private SQL JDBC URL and private Redis hostname as Spring environment variables. | | --output json | Returns the updated app-settings payload as JSON. |

Plan subnet capacity

Integration subnet size impacts scaling headroom. Start with a subnet range that supports expected instance growth.

Platform architecture

For platform architecture details, see Platform: How App Service Works.

Verification

  • az webapp vnet-integration list shows configured integration
  • Backend FQDN resolves to private IPs from app runtime tools
  • App successfully accesses private SQL/Key Vault/Redis endpoints

Troubleshooting

App cannot reach private backend

Validate NSG rules, private endpoint approval state, and private DNS zone links.

DNS resolves public endpoint instead of private

Check VNet DNS settings and private DNS zone association to the integration VNet.

Connectivity broke after enabling route-all

Review route table (UDR) and ensure required Azure service endpoints are reachable through your forced egress path.

Run It in the Portal

Portal view: Networking blade (Virtual network integration not yet configured)

Networking blade for the `app-appsvc-guide-recap` Web App split into an Inbound traffic configuration card and an Outbound traffic configuration card, with the command bar Refresh, Troubleshoot, and Send us your feedback. The Inbound card shows Public network access "Enabled with no access restrictions (Using default behavior)", App assigned address "Not configured", Private endpoints "0 private endpoints", Inbound IPv4 addresses `192.0.2.1`, and Inbound IPv6 addresses `2001:db8::1`; an Optional inbound services subsection lists Azure Front Door with a "View details" link. The Outbound card shows Virtual network integration "Not configured", Hybrid connections "Not configured", Outbound DNS "Default (Azure-provided)", and long comma-separated Outbound IPv4 (`192.0.2.1`) and Outbound IPv6 (`2001:db8::1`) address lists; an Integration subnet configuration subsection shows NAT gateway, Network security group, and User defined route all "N/A". The left navigation shows Networking highlighted under Settings.

The Networking blade is the Portal surface where this recipe's outbound VNet connection becomes visible. In the pre-recipe state shown here, Virtual network integration: Not configured is the key row; after az webapp vnet-integration add, this is the row to revisit to confirm the Spring Boot app is attached to the delegated subnet. The Inbound traffic configuration card remains separate, which matches the recipe's point that VNet integration changes outbound connectivity rather than inbound exposure on its own.

See Also

Sources