Skip to content

Production Baseline

This guide defines a minimum production baseline for Azure App Service workloads. Use it to establish consistent defaults before language-specific implementation and before environment-specific optimization.

Prerequisites

  • Azure subscription with permission to configure App Service resources
  • Existing resource group, App Service Plan, and Web App
  • Shared ownership between application and platform teams for baseline standards
  • Variables set:
    • RG
    • APP_NAME
    • PLAN_NAME

Main Content

Baseline intent

The goal of a production baseline is to reduce accidental risk. Teams should not negotiate core controls app-by-app. Instead, establish defaults once and apply them consistently.

flowchart TD
    A[Production Readiness Checklist] --> B[Plan Tier]
    A --> C[Runtime Safety]
    A --> D[Health]
    A --> E[Observability]
    A --> F[Configuration Discipline]
    A --> G[Identity and Secrets]
    B --> B1[B1 for development and low-risk testing]
    B --> B2[S1 or higher for production baseline]
    B --> B3[P1v3 or higher for high performance profiles]
    C --> C1[Always On enabled]
    C --> C2[HTTPS Only enabled]
    C --> C3[Minimum TLS 1.2]
    D --> D1[Health check endpoint configured]
    D --> D2[Failure criteria validated]
    E --> E1[HTTP logs enabled]
    E --> E2[Console and app logs enabled]
    E --> E3[Platform diagnostics available]
    F --> F1[App settings separated from slot settings]
    G --> G1[Managed identity enabled]
    G --> G2[Connection strings avoided where possible]

1) App Service Plan selection

Plan tier selection is a design decision, not only a cost decision.

Workload stage Recommended plan Why
Development and exploratory testing B1 Low cost for non-critical workloads, basic validation, and early iteration.
Production baseline S1 or higher Better reliability envelope and production-suitable operational posture.
High-performance or latency-sensitive workloads P1v3 or higher Improved CPU/memory characteristics and stronger performance headroom.

Do not run production on Basic tier by default

Basic tiers can be useful for development, but most production workloads require at least Standard for reliable operational behavior and growth headroom.

Assess tier choice with these criteria:

  • Peak throughput and concurrency profile
  • Response-time SLO/SLA expectations
  • Number of deployment slots required
  • Memory pressure and GC behavior of runtime
  • Dependency latency and retry amplification risk

Check current plan tier:

az appservice plan show \
  --resource-group $RG \
  --name $PLAN_NAME \
  --query "{sku:sku.name,tier:sku.tier,workers:numberOfWorkers}" \
  --output json

Sample output (PII-masked):

{
  "sku": "S1",
  "tier": "Standard",
  "workers": 2
}

2) Runtime safety defaults

Every production app should enforce these settings:

  • Always On: enabled
  • HTTPS Only: enabled
  • Minimum TLS: 1.2 or above

Apply baseline runtime settings:

az webapp config set \
  --resource-group $RG \
  --name $APP_NAME \
  --always-on true \
  --min-tls-version 1.2 \
  --output json

az webapp update \
  --resource-group $RG \
  --name $APP_NAME \
  --https-only true \
  --output json

Portal view: Configuration General settings

Configuration General settings blade for a Web App with five tabs — General settings (active), Stack settings, Health check, Path mappings, Error pages — and a Refresh action. Platform settings section lists SCM Basic Auth Publishing Credentials (unchecked), FTP Basic Auth Publishing Credentials (unchecked), WebJobs runtime (unchecked), FTP state (FTPS only), Inbound IP mode (IPv4), HTTP version (1.1), HTTP 2.0 Proxy (Off), SSH (checked), Always on (unchecked), Session affinity (checked), Session affinity proxy (unchecked), HTTPS only (unchecked), Minimum Inbound TLS Version (1.2), SCM Minimum Inbound TLS Version (1.2), Minimum Inbound TLS Cipher Suite (TLS_RSA_WITH_AES_128_CBC_SHA, Default), and End-to-end TLS encryption (unchecked). Apply and Discard buttons are at the bottom of the blade.

The Configuration General settings blade is where every runtime safety default in this baseline is read from and written to. The visible state here is the platform default for a newly created Web App and demonstrates exactly the configuration drift this section warns against: Always on and HTTPS only are both unchecked, which means background workloads can be paused on idle recycle and inbound traffic can still arrive over plain HTTP. Minimum Inbound TLS Version 1.2 is on by default, but it is not a substitute for HTTPS enforcement. Treat this blade as the authoritative verification surface after running the CLI baseline above — every checkbox that this guide marks as required should be visibly enabled here before an app is called production-ready.

Verify effective configuration:

az webapp show \
  --resource-group $RG \
  --name $APP_NAME \
  --query "{httpsOnly:httpsOnly,state:state,hostNames:hostNames}" \
  --output json

az webapp config show \
  --resource-group $RG \
  --name $APP_NAME \
  --query "{alwaysOn:alwaysOn,minTlsVersion:minTlsVersion,http20Enabled:http20Enabled}" \
  --output json

Always On matters for non-request workloads

Apps with scheduled background jobs, cache warm-up, or token refresh logic can fail unpredictably if Always On is disabled.

What Always On does and does not prevent

Always On prevents cold starts caused by idle recycle (the platform unloading an app that has received no requests for ~20 minutes on Basic and higher tiers). It does not prevent cold starts from:

  • Planned platform maintenance and worker node patching
  • Worker recycles or instance redeployment
  • Explicit restarts (az webapp restart)
  • Deployment-triggered restarts (including slot swaps)
  • Regional failover recovery

Design startup paths to be fast and idempotent even with Always On enabled.

3) Health check configuration

Health checks are required for stable traffic handling and reliable restart behavior.

Recommended health endpoint design:

  • Path: /health or /healthz
  • Response: 200 only when app is ready to serve real traffic
  • Checks: critical dependencies with bounded timeout
  • No secrets or detailed internals in response body

Configure health check path:

az webapp config set \
  --resource-group $RG \
  --name $APP_NAME \
  --generic-configurations '{"healthCheckPath":"/health"}' \
  --output json

Validate endpoint behavior:

curl --silent --show-error --fail "https://$APP_NAME.azurewebsites.net/health"

Do not make health checks too deep

Health checks should detect readiness, not run expensive full-system diagnostics. Deep checks can create cascading failures under load.

4) Diagnostic logging baseline

At minimum, production workloads should have:

  • AppServiceHTTPLogs for request-level traceability
  • AppServiceConsoleLogs for application runtime diagnostics
  • AppServicePlatformLogs for infrastructure-level events

Enable web server and application logging where relevant:

az webapp log config \
  --resource-group $RG \
  --name $APP_NAME \
  --web-server-logging filesystem \
  --detailed-error-messages true \
  --failed-request-tracing true \
  --application-logging filesystem \
  --level information \
  --output json

For centralized retention and analytics, route diagnostics to Log Analytics / Azure Monitor.

Example diagnostic settings creation:

az monitor diagnostic-settings create \
  --name "diag-$APP_NAME" \
  --resource $(az webapp show --resource-group $RG --name $APP_NAME --query id --output tsv) \
  --workspace "<log-analytics-workspace-resource-id>" \
  --logs '[{"category":"AppServiceHTTPLogs","enabled":true},{"category":"AppServiceConsoleLogs","enabled":true},{"category":"AppServicePlatformLogs","enabled":true}]' \
  --metrics '[{"category":"AllMetrics","enabled":true}]' \
  --output json

Category names can vary by API version

Validate available diagnostic categories in your environment and API version before automation. Keep your IaC and CLI commands aligned.

Check active diagnostic settings:

az monitor diagnostic-settings list \
  --resource $(az webapp show --resource-group $RG --name $APP_NAME --query id --output tsv) \
  --output json

5) App settings vs slot settings

Separate configuration by lifecycle behavior:

  • App settings: values that should move with deployment
  • Slot settings (sticky): values that must stay with a slot during swap

Typical slot-sticky settings:

  • Production-only endpoints
  • Production-only credentials
  • Monitoring destination overrides per environment

Set a normal app setting:

az webapp config appsettings set \
  --resource-group $RG \
  --name $APP_NAME \
  --settings "FEATURE_FLAG_X=true" \
  --output json

Mark selected settings as slot-specific:

az webapp config appsettings set \
  --resource-group $RG \
  --name $APP_NAME \
  --slot-settings "API_ENDPOINT=https://api.contoso.internal" "CACHE_TTL_SECONDS=60" \
  --output json

Misclassified settings break swaps

If environment-specific values are not sticky, slot swap can promote invalid endpoints or credentials into production.

6) Managed identity over connection strings

Prefer managed identity for Azure service access to remove static credential handling from applications.

Why managed identity is the default:

  • Reduces secret sprawl
  • Supports least-privilege RBAC
  • Simplifies rotation and operational burden
  • Improves auditability of access patterns

Enable system-assigned managed identity:

az webapp identity assign \
  --resource-group $RG \
  --name $APP_NAME \
  --output json

Inspect identity state:

az webapp identity show \
  --resource-group $RG \
  --name $APP_NAME \
  --query "{type:type,principalId:principalId,tenantId:tenantId}" \
  --output json

Sample output (PII-masked):

{
  "type": "SystemAssigned",
  "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "tenantId": "<tenant-id>"
}

When migration from connection strings is not immediate:

  1. Keep secrets in Key Vault references.
  2. Assign minimum required privileges.
  3. Track retirement date for each remaining secret.

Baseline verification checklist

Run this checklist before calling an app production-ready:

  • [ ] Plan tier selected with documented rationale.
  • [ ] Always On enabled.
  • [ ] HTTPS-only enabled.
  • [ ] Minimum TLS set to 1.2 or higher.
  • [ ] Health check endpoint configured and validated.
  • [ ] Diagnostic logging categories enabled and retained centrally.
  • [ ] Slot settings defined for environment-specific values.
  • [ ] Managed identity enabled and permissions scoped.

Common baseline anti-patterns

  • Treating B1 as permanent production infrastructure.
  • Enabling logs without retention or query ownership.
  • Using health checks that always return success.
  • Keeping production credentials as plain app settings.
  • Performing slot swaps without sticky setting review.

Advanced Topics

  • Create separate baselines for internet-facing APIs, internal apps, and batch-triggered web workloads.
  • Automate baseline enforcement with Azure Policy and IaC validation gates.
  • Add synthetic probes that confirm full request path behavior, not only process liveness.
  • Correlate baseline deviations with incident metrics to prioritize hardening work.

See Also

Sources