---
cuppy_hub: azure
cuppy_path: reference/app-service/configuration-and-networking.md
cuppy_section: docs
cuppy_doc: 76WR-H9ZX
cuppy_doc_uuid: 3087114a-ec66-4372-aacf-3495f27696bb
cuppy_permalink: https://cuppy.io/azure/d/76WR-H9ZX
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/app-service/configuration-and-networking
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: da92a0f4a7e62a357e1743ffbb0d9838ff9d0cb0c11150fb0f61e55dbd6958ae
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# App Service configuration and networking

## Running a Node.js app on Linux

- **Listen on `process.env.PORT`.** App Service sets it and forwards requests there. (Custom containers: 80 or 8080, or `WEBSITES_PORT`.)
- **Startup.** With a `start` script, the container runs `npm start` (Microsoft calls it development use). For production, set a startup command that runs PM2 in the foreground: `az webapp config set -g <rg> -n <app> --startup-file "pm2 start dist/server.js --no-daemon"`. After Node 14 the container no longer starts PM2 on its own.
- **Runtime versions** change with Node's release cycle; read them live: `az webapp list-runtimes --os-type linux`.
- **Build automation** (Oryx) runs for Git deployments, and for zip deployments only with `SCM_DO_BUILD_DURING_DEPLOYMENT=true`: `npm install`, then `npm run build` and `npm run build:azure` if defined, with `PRE_BUILD_COMMAND` / `POST_BUILD_COMMAND` hooks. Without it, the zip must already contain `node_modules` and compiled output. App Service runs Node in production mode: test `NODE_ENV=production` locally.

## Deploying, and authenticating the deployment

- **`az webapp deploy -g <rg> -n <app> --src-path app.zip --type zip`** uses the Kudu publish API with your Entra sign-in. It's the scripted default.
- **Basic auth** (publish profiles, FTP, Web Deploy user and password) is controlled by `basicPublishingCredentialsPolicies/scm` and `/ftp`. Turn both off; deploy with Entra ID or GitHub Actions OIDC (`patterns/github-actions-to-azure.md`). FTP basic auth needs SCM basic auth on.
- **Slots** (the number allowed depends on the tier: App Service limits) let you deploy to staging, warm it, then swap. A setting marked **deployment slot setting** stays with the slot; everything else swaps with the code.

## Outbound and inbound addresses

| Need | Read it with |
|---|---|
| Addresses the app uses now | `az webapp show -g <rg> -n <app> --query outboundIpAddresses -o tsv` |
| Every address it could use, across tiers in the same deployment | `az webapp show -g <rg> -n <app> --query possibleOutboundIpAddresses -o tsv` |

- The current set changes when you scale between tier families (Basic/Standard/Premium, PremiumV2, PremiumV3); the possible set can grow when Microsoft adds tiers. Allow-list the **possible** set.
- **Premium V4 provides no stable set of outbound IPs, by design**: the portal shows "Dynamic" and the CLI and ARM return empty strings. Don't allow-list it by IP; use VNet integration with private endpoints or service endpoints (or, the hub's reading, route egress through a NAT gateway you control).
- Same-region storage accounts never see these public IPs (`reference/storage/network-and-firewall.md`).
- The app has one inbound IP. It can change if you delete and re-create the app in another resource group, delete the last app in a resource group and region and re-create it, or delete an IP-based TLS binding. Restrict inbound with **access restrictions** (a priority-ordered list of IP ranges and VNet subnets through service endpoints), or a private endpoint for the app.

## Regional VNet integration

- An **unused subnet, `/28` or larger** (`/26` or larger when several plans join it, called MPSJ), delegated to `Microsoft.Web/serverFarms`, in the **same region**. Its size can't change later: leave room for scale-out and platform upgrades.
- **Routing:** `outboundVnetRouting.allTraffic: true` (recommended) sends all outbound traffic, including image pulls and content share access, through the VNet; `applicationTraffic` covers app traffic only. The older `vnetRouteAllEnabled` site setting and `WEBSITE_VNET_ROUTE_ALL` app setting still work. Both properties exist in `Microsoft.Web` 2025-03-01.
- With route-all on and no service endpoint, private endpoint or route, calls to storage accounts in **other regions** can fail.

## Managed identity and Key Vault references

- The app reaches its identity through `IDENTITY_ENDPOINT` and `IDENTITY_HEADER`; the SDKs read them (`guides/managed-identity/use-managed-identity.md`).
- **Key Vault reference** as an app setting value: `@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/<name>)` or `@Microsoft.KeyVault(VaultName=<vault>;SecretName=<name>)`. Without a version, the app picks up new versions within 24 hours; any config change refetches at once.
- References use the system-assigned identity unless you set `keyVaultReferenceIdentity` to a user-assigned identity's resource ID (`az webapp update -g <rg> -n <app> --set keyVaultReferenceIdentity=<identity-resource-id>`). That identity needs **Key Vault Secrets User** and a network path to the vault.
- Don't depend on the app's public outbound IPs in the vault firewall: use VNet integration with route-all and a private endpoint, or a service endpoint.

## Health check

There's no default path. Set one (`healthCheckPath`) that checks the app itself quickly and without authentication. Instances are pinged every minute; after 10 failed requests (non-2xx) an instance leaves the load balancer, and returns when healthy. Run at least two instances for it to route around a bad one: a single unhealthy instance stays in rotation and is replaced after an hour of failed pings.

Errors: `reference/app-service/errors.md`. Single-tenant hosting in your VNet: `reference/app-service/app-service-environment.md`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
