App Service is PaaS: the platform handles the OS, patches, load balancing and scaling. A web app has a unique name <name>.azurewebsites.net (custom domains can be mapped), publishes code (pick a runtime stack: .NET, Java, Node.js, Python, PHP) or a container, on Linux or Windows. API/Mobile Apps are now part of Web Apps; Functions is a separate service built on App Service.
Runtimes use the FRAMEWORK:VERSION format listed by az webapp list-runtimes (for example NODE:22-lts, PYTHON:3.12).
Continuous deployment: connect GitHub, Bitbucket or Azure Repos (or GitHub Actions/Azure Pipelines) — a push makes the app pick up the new build.
flowchart LR
G["GitHub push"] --> ST["Slot staging<br/>app-devops-lab-01-staging.azurewebsites.net"]
ST -- "test, warm-up" --> SW{"Swap"}
SW --> PR["Production<br/>app-devops-lab-01.azurewebsites.net"]
PR -. "rollback: swap back" .-> ST
Deployment slots
- A slot is a running app with its own hostname; deploy to
staging, test it, then swap with production: instances are already warm, so there is no downtime, and rolling back is just swapping again. Auto Swap exists too. - Slot counts: Free/Shared/Basic 0, Standard 5, Premium 20.
- On swap most configuration moves with the content; settings marked deployment slot setting ("sticky") stay with the slot. Mark staging-only connection strings as sticky, or production will point at the staging DB after the swap. Custom domains, certificates and scale settings are not swapped.
| Command | Meaning |
|---|---|
az webapp create -g rg-devops-lab -p plan-lab -n app-devops-lab-01 --runtime "NODE:22-lts" |
Create a web app |
az webapp deployment slot create -g rg-devops-lab -n app-devops-lab-01 --slot staging |
Create a slot |
az webapp deployment slot swap -g rg-devops-lab -n app-devops-lab-01 --slot staging --target-slot production |
Swap |
Ways to deploy
| Method | Command or setting | Notes |
|---|---|---|
| ZIP deploy | az webapp deploy -g rg-devops-lab -n app-devops-lab-01 --src-path app.zip --type zip |
Simple and scriptable |
| Container image | az webapp config container set ... --container-image-name acrdevopslab.azurecr.io/web:1.4 |
Pull from ACR with a managed identity |
| GitHub Actions or Azure Pipelines | Deployment Center | Build, test, then deploy to a slot |
| Local Git or FTP | Deployment Center | FTP should be disabled when not needed |
Run from package (WEBSITE_RUN_FROM_PACKAGE=1) mounts the ZIP read-only instead of extracting it, which makes deployments atomic and startup faster. Every app also has a Kudu site at <name>.scm.azurewebsites.net with deployment logs, a file browser, and a console.
Safer swaps
- Swap with preview applies the target slot's settings to the source first, lets you check it, then completes the swap; you can cancel in between.
- Warm-up: App Service calls the site's root (or a path set with
WEBSITE_SWAP_WARMUP_PING_PATH) on every instance before switching traffic, so users do not hit a cold start. - Keep the same plan for all slots; slots share the plan's instances, so a heavy test in staging can slow production.
Testing in production
Traffic routing sends a percentage of production users to another slot:
az webapp traffic-routing set -g rg-devops-lab -n app-devops-lab-01 --distribution staging=10
Users are pinned to a slot by a cookie, so their session stays consistent. Watch error rates in Application Insights, then swap fully or set the share back to zero.
Containers on App Service
For a custom container, set WEBSITES_PORT when the app listens on a port other than 80 or 8080, and enable continuous deployment for the image tag so a new push in ACR restarts the app with the new image.