App Service
Azure App Service for hosting web apps, REST APIs, and mobile backends
You are an expert in Azure App Service for hosting production web applications, REST APIs, and mobile backends on a fully managed platform.
## Key Points
- **Ignoring SIGTERM for graceful shutdown** -- When scaling in or swapping slots, App Service sends SIGTERM. Applications that do not handle it drop in-flight requests, causing errors for users.
- **App Service Plan**: The compute resources (VM instances) that host your apps. Defines SKU, region, and scale.
- **Web App**: The application running on the plan. Multiple apps can share a plan.
- **Deployment Slots**: Staging environments that can be swapped with production for zero-downtime deployments.
- **SKU Tiers**: Free, Shared, Basic, Standard, Premium v3, Isolated v2 (for VNET isolation).
1. **Always use deployment slots**: Deploy to a staging slot, validate, then swap to production. This gives zero-downtime deployments and instant rollback.
2. **Enable health checks**: Configure the health check path so App Service can automatically replace unhealthy instances.
3. **Use managed identity**: Access Azure services (Key Vault, SQL, Storage) with managed identity instead of connection strings.
4. **Set Always On**: On Basic tier and above, enable "Always On" to prevent the app from being unloaded after idle periods.
5. **Configure startup commands for Linux apps**:
6. **Use ZIP deploy or Run From Package**: Faster and more reliable than FTP or local Git.
7. **Scale out, not up**: Prefer horizontal scaling (more instances) over vertical scaling (larger instances) for better resilience.
## Quick Example
```bash
az webapp config set \
--name mywebapp \
--resource-group myResourceGroup \
--always-on true
```
```bash
az webapp config set \
--name mywebapp \
--resource-group myResourceGroup \
--startup-file "node dist/server.js"
```skilldb get azure-services-skills/App ServiceFull skill: 374 linesAzure App Service — Cloud Services
You are an expert in Azure App Service for hosting production web applications, REST APIs, and mobile backends on a fully managed platform.
Core Philosophy
App Service is a platform, not just hosting. It provides deployment slots, managed certificates, auto-scaling, health checks, and VNET integration out of the box. The value proposition is that you focus on application code while Azure handles OS patching, load balancing, and TLS termination. If you find yourself SSHing into instances, installing system packages, or configuring reverse proxies, you are fighting the platform instead of using it.
Deployment slots are the most important App Service feature that most teams underuse. Every production deployment should go through a staging slot first. Deploy to staging, run smoke tests against the staging URL, then swap to production for zero-downtime deployment. If something goes wrong, swap back immediately. This pattern eliminates "deploy and pray" and gives you instant rollback with no cold start penalty because the staging slot is already warmed up.
Scale horizontally, not vertically. When your application needs more capacity, add more instances (scale out) rather than moving to a larger SKU (scale up). Horizontal scaling provides better fault tolerance -- losing one of ten instances degrades performance by 10%, while losing one large instance takes down the entire application. Configure auto-scale rules based on CPU percentage or request count, and set both scale-out and scale-in rules to avoid flapping.
Anti-Patterns
- Deploying directly to production without slots -- Every failed deployment becomes a production outage. Use staging slots with swap-based deployments for zero-downtime releases and instant rollback.
- Using Free or Shared tier for production workloads -- These tiers share infrastructure, have no SLA, and lack critical features like deployment slots, custom domains with SSL, auto-scaling, and Always On.
- Forgetting to enable Always On -- Without Always On, App Service unloads the application after idle periods. The next request triggers a cold start that can take 10+ seconds. Enable Always On for any user-facing application.
- Not configuring slot-sticky settings -- Database connection strings and environment-specific flags must be marked as slot settings. Without this, swapping a slot to production also swaps its configuration, pointing production at the staging database.
- Ignoring SIGTERM for graceful shutdown -- When scaling in or swapping slots, App Service sends SIGTERM. Applications that do not handle it drop in-flight requests, causing errors for users.
Overview
Azure App Service is a fully managed platform-as-a-service (PaaS) for building, deploying, and scaling web applications. It supports .NET, Node.js, Python, Java, PHP, Ruby, and custom containers. App Service handles infrastructure maintenance, security patching, and scaling.
Key concepts:
- App Service Plan: The compute resources (VM instances) that host your apps. Defines SKU, region, and scale.
- Web App: The application running on the plan. Multiple apps can share a plan.
- Deployment Slots: Staging environments that can be swapped with production for zero-downtime deployments.
- SKU Tiers: Free, Shared, Basic, Standard, Premium v3, Isolated v2 (for VNET isolation).
Setup & Configuration
Create an App Service with Azure CLI
# Create an App Service Plan (Linux, Premium v3)
az appservice plan create \
--name myAppServicePlan \
--resource-group myResourceGroup \
--is-linux \
--sku P1V3 \
--location eastus
# Create a Node.js web app
az webapp create \
--name mywebapp \
--resource-group myResourceGroup \
--plan myAppServicePlan \
--runtime "NODE:18-lts"
# Create a Python web app
az webapp create \
--name mypythonapp \
--resource-group myResourceGroup \
--plan myAppServicePlan \
--runtime "PYTHON:3.11"
# Create a .NET web app
az webapp create \
--name mydotnetapp \
--resource-group myResourceGroup \
--plan myAppServicePlan \
--runtime "DOTNETCORE:8.0"
# Configure app settings (environment variables)
az webapp config appsettings set \
--name mywebapp \
--resource-group myResourceGroup \
--settings \
NODE_ENV=production \
DATABASE_URL="@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/DbUrl/)"
# Configure connection strings
az webapp config connection-string set \
--name mywebapp \
--resource-group myResourceGroup \
--connection-string-type SQLAzure \
--settings DefaultConnection="Server=tcp:myserver.database.windows.net..."
# Enable system-assigned managed identity
az webapp identity assign \
--name mywebapp \
--resource-group myResourceGroup
Configure custom domain and TLS
# Map a custom domain
az webapp config hostname add \
--webapp-name mywebapp \
--resource-group myResourceGroup \
--hostname www.example.com
# Create a managed certificate (free)
az webapp config ssl create \
--name mywebapp \
--resource-group myResourceGroup \
--hostname www.example.com
# Bind the certificate
az webapp config ssl bind \
--name mywebapp \
--resource-group myResourceGroup \
--certificate-thumbprint <thumbprint> \
--ssl-type SNI
# Enforce HTTPS
az webapp update \
--name mywebapp \
--resource-group myResourceGroup \
--https-only true
# Set minimum TLS version
az webapp config set \
--name mywebapp \
--resource-group myResourceGroup \
--min-tls-version 1.2
Core Patterns
Deployment with GitHub Actions
# .github/workflows/deploy.yml
name: Deploy to Azure App Service
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci
- run: npm run build
- run: npm test
- uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- uses: azure/webapps-deploy@v3
with:
app-name: mywebapp
slot-name: staging
package: .
# Run smoke tests against staging
- run: curl -f https://mywebapp-staging.azurewebsites.net/health
# Swap staging to production
- run: |
az webapp deployment slot swap \
--name mywebapp \
--resource-group myResourceGroup \
--slot staging \
--target-slot production
Deployment slots for blue-green deploys
# Create a staging slot
az webapp deployment slot create \
--name mywebapp \
--resource-group myResourceGroup \
--slot staging
# Configure slot-specific settings (sticky to the slot)
az webapp config appsettings set \
--name mywebapp \
--resource-group myResourceGroup \
--slot staging \
--slot-settings \
SLOT_NAME=staging
# Deploy to staging
az webapp deploy \
--name mywebapp \
--resource-group myResourceGroup \
--slot staging \
--src-path ./app.zip \
--type zip
# Swap staging to production (zero-downtime)
az webapp deployment slot swap \
--name mywebapp \
--resource-group myResourceGroup \
--slot staging \
--target-slot production
# Swap back if issues arise
az webapp deployment slot swap \
--name mywebapp \
--resource-group myResourceGroup \
--slot production \
--target-slot staging
Auto-scaling configuration
# Enable autoscale on the App Service Plan
az monitor autoscale create \
--resource-group myResourceGroup \
--resource myAppServicePlan \
--resource-type Microsoft.Web/serverFarms \
--name myAutoscaleSettings \
--min-count 2 \
--max-count 10 \
--count 2
# Add a scale-out rule (CPU > 70% for 10 minutes)
az monitor autoscale rule create \
--resource-group myResourceGroup \
--autoscale-name myAutoscaleSettings \
--condition "CpuPercentage > 70 avg 10m" \
--scale out 2
# Add a scale-in rule (CPU < 30% for 10 minutes)
az monitor autoscale rule create \
--resource-group myResourceGroup \
--autoscale-name myAutoscaleSettings \
--condition "CpuPercentage < 30 avg 10m" \
--scale in 1
Health check and diagnostics
# Enable health check endpoint
az webapp config set \
--name mywebapp \
--resource-group myResourceGroup \
--generic-configurations '{"healthCheckPath": "/health"}'
# Enable Application Insights
az monitor app-insights component create \
--app mywebapp-insights \
--location eastus \
--resource-group myResourceGroup
az webapp config appsettings set \
--name mywebapp \
--resource-group myResourceGroup \
--settings \
APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=..."
ApplicationInsightsAgent_EXTENSION_VERSION="~3"
# Stream live logs
az webapp log tail \
--name mywebapp \
--resource-group myResourceGroup
# Enable detailed logging
az webapp log config \
--name mywebapp \
--resource-group myResourceGroup \
--application-logging filesystem \
--level information \
--web-server-logging filesystem
VNET Integration and private endpoints
# Integrate the app with a VNET (outbound traffic)
az webapp vnet-integration add \
--name mywebapp \
--resource-group myResourceGroup \
--vnet myVnet \
--subnet app-subnet
# Route all traffic through VNET
az webapp config appsettings set \
--name mywebapp \
--resource-group myResourceGroup \
--settings WEBSITE_VNET_ROUTE_ALL=1
# Create a private endpoint (inbound traffic)
az network private-endpoint create \
--name mywebapp-pe \
--resource-group myResourceGroup \
--vnet-name myVnet \
--subnet pe-subnet \
--private-connection-resource-id $(az webapp show --name mywebapp --resource-group myResourceGroup --query id -o tsv) \
--group-id sites \
--connection-name mywebapp-connection
Best Practices
-
Always use deployment slots: Deploy to a staging slot, validate, then swap to production. This gives zero-downtime deployments and instant rollback.
-
Enable health checks: Configure the health check path so App Service can automatically replace unhealthy instances.
-
Use managed identity: Access Azure services (Key Vault, SQL, Storage) with managed identity instead of connection strings.
-
Set Always On: On Basic tier and above, enable "Always On" to prevent the app from being unloaded after idle periods.
az webapp config set \ --name mywebapp \ --resource-group myResourceGroup \ --always-on true -
Configure startup commands for Linux apps:
az webapp config set \ --name mywebapp \ --resource-group myResourceGroup \ --startup-file "node dist/server.js" -
Use ZIP deploy or Run From Package: Faster and more reliable than FTP or local Git.
az webapp deploy \ --name mywebapp \ --resource-group myResourceGroup \ --src-path ./deploy.zip \ --type zip -
Scale out, not up: Prefer horizontal scaling (more instances) over vertical scaling (larger instances) for better resilience.
-
Enable diagnostic logging and Application Insights: Captures request traces, exceptions, dependencies, and custom telemetry.
Common Pitfalls
-
Using Free/Shared tier for production: These tiers share infrastructure, have no SLA, and lack features like deployment slots, custom domains with SSL, and autoscaling.
-
Not configuring slot-sticky settings: Database connection strings and feature flags that differ between staging and production must be marked as "slot settings" to avoid swapping them.
-
Cold start after swap: Pre-warm the staging slot before swapping. App Service sends synthetic requests to the app root, but if your app needs specific warm-up paths, add them in
web.configor use the health check endpoint. -
Exceeding the plan's memory/CPU: All apps on a plan share resources. An overloaded plan degrades all apps. Monitor per-app metrics.
-
Hardcoded file paths: On Linux App Service, the app runs in a container. Use
/homefor persistent storage, not/tmp. -
Missing CORS configuration: For SPAs calling an API on App Service, configure CORS in the portal or code. App Service has built-in CORS support that runs before your app code.
az webapp cors add \ --name mywebapp \ --resource-group myResourceGroup \ --allowed-origins "https://myfrontend.com" -
Not handling graceful shutdown: When swapping or scaling in, App Service sends SIGTERM. Handle it to complete in-flight requests.
process.on("SIGTERM", () => { console.log("SIGTERM received, shutting down gracefully..."); server.close(() => process.exit(0)); });
Install this skill directly: skilldb add azure-services-skills
Related Skills
Azure Functions
Azure Functions serverless compute for event-driven applications
Blob Storage
Azure Blob Storage for scalable object storage and data lake scenarios
Cosmos Db
Azure Cosmos DB globally distributed multi-model database service
Adversarial Code Review
Adversarial implementation review methodology that validates code completeness against requirements with fresh objectivity. Uses a coach-player dialectical loop to catch real gaps in security, logic, and data flow.
API Design Testing
Design, document, and test APIs following RESTful principles, consistent
Architecture
Design software systems with sound architecture — choosing patterns, defining boundaries,