Gap-5: App Service Operate (B+ → A) — SKU selection, custom domains, networking#1639
Gap-5: App Service Operate (B+ → A) — SKU selection, custom domains, networking#1639
Conversation
There was a problem hiding this comment.
Pull request overview
Adds App Service “Operate (A)” reference docs covering SKU selection, custom domains/managed TLS, and networking options (VNet integration, Private Endpoints, access restrictions).
Changes:
- Introduces a SKU comparison/pricing guide plus IaC examples (Bicep/Terraform) for plan SKU selection.
- Documents custom domain DNS setup and managed TLS workflows via CLI/Bicep/Terraform.
- Adds networking guidance for VNet integration, Private Endpoints, access restrictions, and troubleshooting.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| plugin/skills/azure-prepare/references/services/app-service/sku-selection.md | New guidance to choose App Service SKUs, including feature matrix, pricing overview, and IaC examples. |
| plugin/skills/azure-prepare/references/services/app-service/custom-domains.md | New guide for custom domains and managed certificates using CLI/Bicep/Terraform. |
| plugin/skills/azure-prepare/references/services/app-service/networking.md | New networking reference covering VNet integration, Private Endpoints, access restrictions, and troubleshooting. |
| properties: { | ||
| serverFarmId: appServicePlan.id | ||
| virtualNetworkSubnetId: subnet.id | ||
| vnetRouteAllEnabled: true // route all outbound through VNet |
There was a problem hiding this comment.
vnetRouteAllEnabled is not a top-level site properties field for Microsoft.Web/sites; it belongs under siteConfig (or via a Microsoft.Web/sites/config resource). As written, this snippet will fail validation or silently not apply the setting. Move vnetRouteAllEnabled into properties.siteConfig (or add a separate config resource) while keeping virtualNetworkSubnetId on the site.
| vnetRouteAllEnabled: true // route all outbound through VNet | |
| siteConfig: { | |
| vnetRouteAllEnabled: true // route all outbound through VNet | |
| } |
| 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 | ||
| } | ||
| } |
There was a problem hiding this comment.
The Private Endpoint example sets up the zone and VNet link, but it doesn’t associate the Private Endpoint to the private DNS zone (typically via a privateDnsZoneGroups child resource under the private endpoint). Without that association (or an explicit A record), name resolution for the app hostname won’t automatically work. Add the privateDnsZoneGroup step (or call out manual DNS record creation as required).
| | Private Endpoints (inbound) | ❌ | ❌ | ✅ | ✅ | | ||
| | Access Restrictions | ✅ | ✅ | ✅ | ✅ | | ||
| | Hybrid Connections | ❌ | 25 | 200 | 200 | | ||
| | Service Endpoints | ❌ | ✅ | ✅ | ✅ | |
There was a problem hiding this comment.
The Service Endpoints row is misleading in the context of App Service, since service endpoints are a VNet/subnet feature used by downstream Azure services (Storage, SQL, etc.), not a capability you 'enable on' App Service itself. Consider removing this row, or rewording it to clarify it applies to resources the app connects to (e.g., 'Access to service-endpoint-protected resources').
| | Service Endpoints | ❌ | ✅ | ✅ | ✅ | | |
| | 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. |
| resource customDomain 'Microsoft.Web/sites/hostNameBindings@2022-09-01' = { | ||
| parent: webApp | ||
| name: 'www.contoso.com' | ||
| properties: { | ||
| siteName: webApp.name | ||
| hostNameType: 'Verified' | ||
| sslState: 'Disabled' // enable after cert is created | ||
| } | ||
| } | ||
|
|
||
| resource managedCert 'Microsoft.Web/certificates@2022-09-01' = { | ||
| name: 'www.contoso.com' | ||
| location: location | ||
| properties: { | ||
| serverFarmId: appServicePlan.id | ||
| canonicalName: 'www.contoso.com' | ||
| } | ||
| dependsOn: [customDomain] |
There was a problem hiding this comment.
This section is titled 'Custom Domain with Managed Certificate', but the Bicep example only creates the hostname binding and requests a certificate; it never binds the certificate to the hostname (i.e., enabling SNI by setting sslState and the certificate thumbprint on the hostNameBinding / or via the appropriate binding mechanism). As-is, HTTPS via the managed cert won’t be enabled. Add the missing binding step after the cert resource is created.
| resource customDomain 'Microsoft.Web/sites/hostNameBindings@2022-09-01' = { | |
| parent: webApp | |
| name: 'www.contoso.com' | |
| properties: { | |
| siteName: webApp.name | |
| hostNameType: 'Verified' | |
| sslState: 'Disabled' // enable after cert is created | |
| } | |
| } | |
| resource managedCert 'Microsoft.Web/certificates@2022-09-01' = { | |
| name: 'www.contoso.com' | |
| location: location | |
| properties: { | |
| serverFarmId: appServicePlan.id | |
| canonicalName: 'www.contoso.com' | |
| } | |
| dependsOn: [customDomain] | |
| resource managedCert 'Microsoft.Web/certificates@2022-09-01' = { | |
| name: 'www.contoso.com' | |
| location: location | |
| properties: { | |
| serverFarmId: appServicePlan.id | |
| canonicalName: 'www.contoso.com' | |
| } | |
| } | |
| resource customDomain 'Microsoft.Web/sites/hostNameBindings@2022-09-01' = { | |
| parent: webApp | |
| name: 'www.contoso.com' | |
| properties: { | |
| siteName: webApp.name | |
| hostNameType: 'Verified' | |
| sslState: 'SniEnabled' | |
| thumbprint: managedCert.properties.thumbprint | |
| } | |
| dependsOn: [ | |
| managedCert | |
| ] |
| # Create managed certificate (free) | ||
| az webapp config ssl create -n $APP -g $RG --hostname www.contoso.com | ||
|
|
||
| # Bind the certificate | ||
| az webapp config ssl bind -n $APP -g $RG \ | ||
| --certificate-thumbprint $THUMBPRINT --ssl-type SNI |
There was a problem hiding this comment.
The CLI flow references $THUMBPRINT but doesn’t show how it’s obtained from the ssl create step. Add a command to capture the thumbprint from the create output (or query the certificate after creation) so the sequence is runnable end-to-end.
| | SKU | vCPU | RAM | Storage | Approx. Monthly Cost | | ||
| |-----|------|-----|---------|---------------------| | ||
| | F1 | Shared | 1 GB | 1 GB | Free | | ||
| | B1 | 1 | 1.75 GB | 10 GB | ~$55 | | ||
| | B2 | 2 | 3.5 GB | 10 GB | ~$110 | | ||
| | S1 | 1 | 1.75 GB | 50 GB | ~$73 | | ||
| | S2 | 2 | 3.5 GB | 50 GB | ~$146 | | ||
| | P1v3 | 2 | 8 GB | 250 GB | ~$138 | | ||
| | P2v3 | 4 | 16 GB | 250 GB | ~$276 | | ||
| | P3v3 | 8 | 32 GB | 250 GB | ~$552 | | ||
| | I1v2 | 2 | 8 GB | 1 TB | ~$460 | |
There was a problem hiding this comment.
The pricing table is presented with specific monthly figures, but App Service pricing varies materially by OS (Windows vs Linux), region, commitment/offers, and sometimes plan options. The note on line 33 helps, but adding an 'as-of' date and the assumed region/OS (or explicitly labeling these numbers as a single example scenario) would prevent readers from treating them as generally applicable.
Details# 🔍 Token Analysis Report
fatal: path 'plugin/skills/azure-prepare/references/services/app-service/custom-domains.md' exists on disk, but not in 'origin/main' 📊 Token Change ReportComparing Summary
Changed Files
📊 Token Limit Check ReportChecked: 527 files
|
| File | Tokens | Limit | Over By |
|---|---|---|---|
.github/skills/analyze-test-run/SKILL.md |
2471 | 500 | +1971 |
.github/skills/file-test-bug/SKILL.md |
628 | 500 | +128 |
.github/skills/sensei/README.md |
3531 | 2000 | +1531 |
.github/skills/sensei/SKILL.md |
2382 | 500 | +1882 |
.github/skills/sensei/references/EXAMPLES.md |
3707 | 2000 | +1707 |
.github/skills/sensei/references/LOOP.md |
4181 | 2000 | +2181 |
.github/skills/sensei/references/SCORING.md |
3927 | 2000 | +1927 |
.github/skills/skill-authoring/SKILL.md |
817 | 500 | +317 |
plugin/skills/appinsights-instrumentation/SKILL.md |
908 | 500 | +408 |
plugin/skills/azure-ai/SKILL.md |
817 | 500 | +317 |
plugin/skills/azure-aigateway/SKILL.md |
1258 | 500 | +758 |
plugin/skills/azure-aigateway/references/policies.md |
2342 | 2000 | +342 |
plugin/skills/azure-cloud-migrate/references/services/functions/lambda-to-functions.md |
2600 | 2000 | +600 |
plugin/skills/azure-cloud-migrate/references/services/functions/runtimes/javascript.md |
2181 | 2000 | +181 |
plugin/skills/azure-compliance/SKILL.md |
1185 | 500 | +685 |
plugin/skills/azure-compute/SKILL.md |
755 | 500 | +255 |
plugin/skills/azure-compute/workflows/vm-recommender/vm-recommender.md |
2393 | 2000 | +393 |
plugin/skills/azure-compute/workflows/vm-troubleshooter/references/cannot-connect-to-vm.md |
7308 | 2000 | +5308 |
plugin/skills/azure-cost-optimization/SKILL.md |
3900 | 500 | +3400 |
plugin/skills/azure-deploy/SKILL.md |
1562 | 500 | +1062 |
plugin/skills/azure-diagnostics/SKILL.md |
1132 | 500 | +632 |
plugin/skills/azure-diagnostics/aks-troubleshooting/networking.md |
2147 | 2000 | +147 |
plugin/skills/azure-diagnostics/aks-troubleshooting/node-issues.md |
2003 | 2000 | +3 |
plugin/skills/azure-enterprise-infra-planner/SKILL.md |
991 | 500 | +491 |
plugin/skills/azure-enterprise-infra-planner/references/constraints/compute-apps.md |
2022 | 2000 | +22 |
plugin/skills/azure-hosted-copilot-sdk/SKILL.md |
608 | 500 | +108 |
plugin/skills/azure-kubernetes/SKILL.md |
2266 | 500 | +1766 |
plugin/skills/azure-kusto/SKILL.md |
2149 | 500 | +1649 |
plugin/skills/azure-messaging/SKILL.md |
967 | 500 | +467 |
plugin/skills/azure-prepare/SKILL.md |
2607 | 500 | +2107 |
plugin/skills/azure-prepare/references/aspire.md |
2991 | 2000 | +991 |
plugin/skills/azure-prepare/references/plan-template.md |
2559 | 2000 | +559 |
plugin/skills/azure-prepare/references/recipes/azd/terraform.md |
3012 | 2000 | +1012 |
plugin/skills/azure-prepare/references/resources-limits-quotas.md |
3322 | 2000 | +1322 |
plugin/skills/azure-prepare/references/security.md |
2092 | 2000 | +92 |
plugin/skills/azure-prepare/references/services/functions/bicep.md |
3065 | 2000 | +1065 |
plugin/skills/azure-prepare/references/services/functions/templates/SPEC-composable-templates.md |
6187 | 2000 | +4187 |
plugin/skills/azure-prepare/references/services/functions/templates/recipes/composition.md |
4649 | 2000 | +2649 |
plugin/skills/azure-prepare/references/services/functions/terraform.md |
3358 | 2000 | +1358 |
plugin/skills/azure-quotas/SKILL.md |
3445 | 500 | +2945 |
plugin/skills/azure-quotas/references/commands.md |
2644 | 2000 | +644 |
plugin/skills/azure-resource-lookup/SKILL.md |
1279 | 500 | +779 |
plugin/skills/azure-resource-visualizer/SKILL.md |
2054 | 500 | +1554 |
plugin/skills/azure-storage/SKILL.md |
1180 | 500 | +680 |
plugin/skills/azure-upgrade/SKILL.md |
1001 | 500 | +501 |
plugin/skills/azure-upgrade/references/services/functions/automation.md |
3463 | 2000 | +1463 |
plugin/skills/azure-upgrade/references/services/functions/consumption-to-flex.md |
2773 | 2000 | +773 |
plugin/skills/azure-validate/SKILL.md |
906 | 500 | +406 |
plugin/skills/entra-app-registration/SKILL.md |
2068 | 500 | +1568 |
plugin/skills/entra-app-registration/references/api-permissions.md |
2545 | 2000 | +545 |
plugin/skills/entra-app-registration/references/cli-commands.md |
2211 | 2000 | +211 |
plugin/skills/entra-app-registration/references/console-app-example.md |
2752 | 2000 | +752 |
plugin/skills/entra-app-registration/references/oauth-flows.md |
2375 | 2000 | +375 |
plugin/skills/microsoft-foundry/SKILL.md |
2870 | 500 | +2370 |
plugin/skills/microsoft-foundry/foundry-agent/create/create.md |
3016 | 2000 | +1016 |
plugin/skills/microsoft-foundry/foundry-agent/deploy/deploy.md |
5511 | 2000 | +3511 |
plugin/skills/microsoft-foundry/foundry-agent/eval-datasets/eval-datasets.md |
2342 | 2000 | +342 |
plugin/skills/microsoft-foundry/foundry-agent/eval-datasets/references/trace-to-dataset.md |
4268 | 2000 | +2268 |
plugin/skills/microsoft-foundry/foundry-agent/observe/observe.md |
2547 | 2000 | +547 |
plugin/skills/microsoft-foundry/foundry-agent/trace/references/kql-templates.md |
2701 | 2000 | +701 |
plugin/skills/microsoft-foundry/models/deploy-model/SKILL.md |
1640 | 500 | +1140 |
plugin/skills/microsoft-foundry/models/deploy-model/capacity/SKILL.md |
1739 | 500 | +1239 |
plugin/skills/microsoft-foundry/models/deploy-model/customize/SKILL.md |
2235 | 500 | +1735 |
plugin/skills/microsoft-foundry/models/deploy-model/customize/references/customize-workflow.md |
3335 | 2000 | +1335 |
plugin/skills/microsoft-foundry/models/deploy-model/preset/SKILL.md |
1226 | 500 | +726 |
plugin/skills/microsoft-foundry/models/deploy-model/preset/references/preset-workflow.md |
5534 | 2000 | +3534 |
plugin/skills/microsoft-foundry/quota/quota.md |
2129 | 2000 | +129 |
plugin/skills/microsoft-foundry/quota/references/capacity-planning.md |
2029 | 2000 | +29 |
plugin/skills/microsoft-foundry/references/sdk/foundry-sdk-py.md |
2162 | 2000 | +162 |
Consider moving content to
references/subdirectories.
Automated token analysis. See skill authoring guidelines for best practices.
Closes #1613 | Parent: #1608
3 files: sku-selection.md (Free→Isolated comparison), custom-domains.md (managed TLS via Bicep), networking.md (VNet, Private Endpoints, Access Restrictions).