Private Endpoints¶
Connect App Service to backend services over private networking using VNet integration and private endpoints for SQL, Redis, and Key Vault.
flowchart TD
A[App Service with VNet integration] --> B[Private DNS zones]
B --> C[Private Endpoint SQL]
B --> D[Private Endpoint Redis]
B --> E[Private Endpoint Key Vault]
C --> F[Private backend connectivity]
D --> F
E --> F Prerequisites¶
- App Service Plan tier that supports VNet integration
- Virtual network with dedicated integration subnet
- Backend services configured for private endpoint support
Main Content¶
1) Networking architecture¶
Recommended layout:
snet-appservice-integration: delegated for App Service VNet integrationsnet-private-endpoints: hosts private endpoint NICs- Private DNS zones linked to the VNet
2) Enable VNet integration (Linux App Service)¶
az webapp vnet-integration add \
--resource-group "$RG" \
--name "$APP_NAME" \
--vnet "$VNET_NAME" \
--subnet "snet-appservice-integration" \
--output json
az webapp vnet-integration add | Connects the web app to a delegated subnet for outbound VNet integration. | | --resource-group "$RG" | Targets the resource group that contains the web app. | | --name "$APP_NAME" | Selects the web app that will join the VNet. | | --vnet "$VNET_NAME" | 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. | 3) Create private endpoint for Azure SQL¶
az network private-endpoint create \
--resource-group "$RG" \
--name "pe-sql-guide" \
--vnet-name "$VNET_NAME" \
--subnet "snet-private-endpoints" \
--private-connection-resource-id "/subscriptions/<subscription-id>/resourceGroups/<sql-rg>/providers/Microsoft.Sql/servers/<sql-server>" \
--group-id sqlServer \
--connection-name "pe-sql-guide-conn" \
--output json
az network private-endpoint create | Creates a private endpoint NIC for the target Azure SQL server. | | --resource-group "$RG" | Targets the resource group where the private endpoint resource will be created. | | --name "pe-sql-guide" | Names the private endpoint resource. | | --vnet-name "$VNET_NAME" | Places the private endpoint inside the specified virtual network. | | --subnet "snet-private-endpoints" | Uses the subnet reserved for private endpoint NICs. | | --private-connection-resource-id "/subscriptions/.../Microsoft.Sql/servers/<sql-server>" | Points the private endpoint at the Azure SQL server resource. | | --group-id sqlServer | Selects the SQL server private-link subresource. | | --connection-name "pe-sql-guide-conn" | Names the private-link connection object. | | --output json | Returns the created private endpoint resource as JSON. | 4) Create private endpoint for Redis¶
az network private-endpoint create \
--resource-group "$RG" \
--name "pe-redis-guide" \
--vnet-name "$VNET_NAME" \
--subnet "snet-private-endpoints" \
--private-connection-resource-id "/subscriptions/<subscription-id>/resourceGroups/<redis-rg>/providers/Microsoft.Cache/Redis/<redis-name>" \
--group-id redisCache \
--connection-name "pe-redis-guide-conn" \
--output json
az network private-endpoint create | Creates a private endpoint NIC for the target Azure Cache for Redis instance. | | --resource-group "$RG" | Targets the resource group where the private endpoint resource will be created. | | --name "pe-redis-guide" | Names the private endpoint resource. | | --vnet-name "$VNET_NAME" | Places the private endpoint inside the specified virtual network. | | --subnet "snet-private-endpoints" | Uses the subnet reserved for private endpoint NICs. | | --private-connection-resource-id "/subscriptions/.../Microsoft.Cache/Redis/<redis-name>" | Points the private endpoint at the Redis cache resource. | | --group-id redisCache | Selects the Redis private-link subresource. | | --connection-name "pe-redis-guide-conn" | Names the private-link connection object. | | --output json | Returns the created private endpoint resource as JSON. | 5) NSG and route guidance¶
Allow outbound from integration subnet to:
- SQL private endpoint IP on 1433
- Redis private endpoint IP on 6380
- Key Vault private endpoint IP on 443
Block broad internet egress only after dependencies are confirmed reachable.
6) Connection string and DNS assumptions¶
Keep service hostnames unchanged (for example, <sql-server>.database.windows.net). Private DNS resolution should map these names to private endpoint IPs within the VNet.
7) App code stays unchanged¶
Spring Boot automatically picks up connection details from environment variables or application.properties.
# application.properties
spring.datasource.url=jdbc:sqlserver://<sql-server>.database.windows.net:1433;database=<db-name>;encrypt=true;
spring.data.redis.host=<redis-name>.redis.cache.windows.net
spring.data.redis.port=6380
spring.data.redis.ssl=true
The same code can run with public or private networking if configuration and DNS are consistent.
8) GitHub Actions networking validation step¶
- name: Validate private endpoint state
run: |
az network private-endpoint list \
--resource-group "$RG" \
--output table
Private endpoint without DNS is incomplete
Most connectivity incidents are DNS-related, not code-related. Always validate private DNS zone links and effective name resolution from the app environment.
Verification¶
- Confirm VNet integration is connected.
- Confirm private endpoints are in
Approvedstate. - Confirm app can reach SQL/Redis with normal hostnames.
az webapp vnet-integration list | Lists the current VNet integration attachments for the web app. | | --resource-group "$RG" | Targets the resource group that contains the web app. | | --name "$APP_NAME" | Selects the web app whose VNet integration will be listed. | | --output table | Formats the integration list as a readable table. | Use dependency telemetry and synthetic API checks to verify end-to-end connectivity.
Troubleshooting¶
Name resolution still points to public IP¶
- Validate private DNS zone records.
- Ensure VNet links are correct.
- Confirm app is integrated with expected VNet/subnet.
Connection timeout to backend¶
- Review NSG rules and UDRs.
- Confirm backend firewall permits private endpoint traffic.
- Check TLS settings for SQL/Redis client configuration.
Intermittent connectivity during scale events¶
Use resilient retry settings (Spring Data JPA retry logic, Redis reconnect behavior) and monitor transient errors.
Run It in the Portal¶
Portal view: Networking blade (app-side precondition for backend private endpoints)¶

Purpose: Show the app's inbound and outbound network configuration on one page.
Look for: Public network access and Private endpoints under inbound traffic, and Virtual network integration, Outbound DNS, and the outbound address lists under outbound traffic.
Expected result: This capture shows the displayed configuration of a public app without VNet integration: the listed outbound addresses are the platform's potential outbound address pool (not a measured egress address for any connection), and the integration subnet settings show N/A.
This web-app Networking blade is a supporting before-state for the recipe rather than the place where the SQL, Redis, and Key Vault private endpoints themselves are listed. The visible Virtual network integration: Not configured row is the app-side prerequisite the recipe changes before private DNS for those backend services can work, while Private endpoints: 0 private endpoints also makes clear the screenshot is not showing downstream private endpoints attached to other resources. Use this capture as the pre-integration checkpoint before running the recipe's VNet integration and backend private-endpoint steps, then revisit Spring's data-access retry settings (JPA retry logic, Redis Lettuce reconnect) once the private path is live.