CloudBrum
CloudBrum · Cloud decision-support platform
Azure App modernization

Azure App ServiceLast reviewedReading time~12 minLevelBeginner to advanced

Microsoft Azure · App modernization · Platform for web apps and APIs

Web apps on Azure without managing the servers. You pick a runtime such as .NET, Java, Node.js, Python or PHP, or bring a container, and App Service hosts it behind HTTPS with scaling, deployment slots and sign-in built in. The thing to understand first is the plan. An App Service plan is the set of virtual machines your apps run on, and you pay for the plan by the hour whether it hosts one app or ten. So the tier you choose and how many apps you put on it decide the bill far more than any single app does.

On this page (17 sections)

    Mind map: Azure App Service at a glance

    Azure App Service mind map Azure App Service at a glance: Plans: Free, Shared, Basic, Standard, Premium, Isolated (ASE); Runtimes: .NET, Java, Node.js, Python, PHP, Custom containers; Deploying: Zip deploy, GitHub Actions, Git, Container images; Slots: Staging slots, Swap with warm-up, Slot settings; Scaling: Scale up, scale out, Autoscale rules, Per-app scaling; Networking: VNet integration, Private endpoints, Access restrictions; Identity: Managed identity, Key Vault references, Built-in auth; Pricing: Per plan instance, Reservations, Savings plans. Azure App Service at a glance A platform for web apps on Azure: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Free, Shared, Basic Standard, Premium Isolated (ASE) Plans .NET, Java, Node.js Python, PHP Custom containers Runtimes Zip deploy GitHub Actions, Git Container images Deploying Staging slots Swap with warm-up Slot settings Slots Scale up, scale out Autoscale rules Per-app scaling Scaling VNet integration Private endpoints Access restrictions Networking Managed identity Key Vault references Built-in auth Identity Per plan instance Reservations Savings plans Pricing App Service17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum App Service at a glance · 17-point analysis Plans Free, Shared, Basic Standard, Premium Isolated (ASE) Runtimes .NET, Java, Node.js Python, PHP Custom containers Deploying Zip deploy GitHub Actions, Git Container images Slots Staging slots Swap with warm-up Slot settings Scaling Scale up, scale out Autoscale rules Per-app scaling Networking VNet integration Private endpoints Access restrictions Identity Managed identity Key Vault references Built-in auth Pricing Per plan instance Reservations Savings plans CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • Platform for the usual runtimesRun .NET, Java, Node.js, Python or PHP on Windows or Linux, or bring your own container. Microsoft patches the operating system and the runtime stacks, and you deploy code.
    • Plans share computeAn App Service plan defines the region, the machine size and the instance count. Several apps can share one plan, which is the main way to save money on small apps.
    • Deployment slotsFrom the Standard tier up, you can create a staging slot, deploy there, warm it up and swap it into production. A bad release is a swap back.
    • Scale up and outScale up to a bigger machine, or scale out to more instances by hand or with autoscale rules on CPU, memory, queue length or a schedule.
    • Identity without secretsAn app gets a managed identity, so it can reach Azure SQL, Storage or Key Vault with no password. Settings can reference Key Vault secrets instead of holding them.
    • Networking optionsRegional virtual network integration sends outgoing traffic into your network, private endpoints take incoming traffic privately, and access restrictions limit who can call the app.
    • Built-in authenticationApp Service can require sign-in with Microsoft Entra ID or other providers before a request reaches your code, with no authentication code in the app.
    • Health checks and diagnosticsA health check path lets the platform take unhealthy instances out of rotation, and diagnostics, logs and Application Insights show what’s wrong.

    Basic concepts

    App Service plan
    The set of virtual machines that run your apps. It has a region, an operating system, a tier and size, and an instance count, and it’s what you’re billed for.
    Web app
    One app that runs on a plan. It has its own URL, settings and deployments, and shares the plan’s CPU and memory with the other apps on it.
    Pricing tier
    Free, Shared, Basic, Standard, Premium or Isolated. The tier decides which features exist, such as slots and autoscale, and how much each instance costs.
    Scale up and scale out
    Scale up changes the size of each instance. Scale out changes how many instances there are.
    Deployment slot
    A live copy of the app with its own host name, used for staging. Slots share the plan, and a swap exchanges what each one serves.
    Slot setting (sticky)
    A setting that stays with the slot during a swap, such as a connection string for a test database.
    Always On
    A setting that keeps the app loaded so the first request after a quiet period doesn’t wait for a start-up. It needs the Basic tier or above.
    Managed identity
    An Entra identity for the app. It’s the way to reach Azure services without credentials.
    Key Vault reference
    An app setting whose value is @Microsoft.KeyVault(...). App Service reads the secret at run time with the app’s identity.
    VNet integration
    Lets the app send outgoing traffic into a subnet of your virtual network, for example to a private database.
    Private endpoint
    A private IP address for the app inside your network, used for incoming traffic that must not cross the internet.
    Autoscale
    Rules that add or remove instances based on metrics or a schedule. They’re set on the plan, from the Standard tier up.
    Kudu (SCM site)
    The management site of an app, used for deployments, logs and a console. It has its own access rules, which you should restrict.
    App Service Environment
    An isolated, single-tenant deployment of App Service inside your virtual network, for strict isolation and large scale, at a higher price.

    How to create & configure it

    Create a web app with the Azure CLI

    1. Choose the region, the system and the tierPick a region near your users (Central India or South India). Use Linux unless you need Windows features, and Premium for production. Standard is the first tier with slots and autoscale.
    2. Create the planRun az appservice plan create with the tier, the operating system and the number of instances. Two instances is the sensible minimum for production.
    3. Create the web appCreate it on the plan with a runtime such as PYTHON:3.13. Turn on HTTPS only, set the minimum TLS version and disable FTP.
    4. Give it an identityAssign a system-assigned managed identity, give it the smallest role on the storage account, and put secrets in Key Vault with references in the app settings.
    5. Set the startup and health settingsSet the startup command if the default isn’t right, turn on Always On and set a health check path that returns 200 quickly.
    6. Create a staging slotMake a slot that copies the production settings, and mark settings that must not move with the swap as slot settings.
    7. Deploy to the slot and swapDeploy the zip package to the staging slot, test it on its own URL, and swap it with production. The swap warms up the new code first.
    8. Add scale and network rulesCreate autoscale rules on the plan, integrate the app with a virtual network subnet if it needs private resources, and restrict who can reach the app and the Kudu site.
    9. Watch itSend logs and metrics to Log Analytics and Application Insights, and alert on failed requests, response time and instance count.

    Tip: az webapp up creates a plan and an app and deploys the current folder in one command, which is fine for a first try. For anything shared, write the plan, app, slot and autoscale rules as Bicep or Terraform (see the code references).

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    Service Unavailable (503) right after a deploymentThe app failed to start, or the process listens on a port the platform doesn’t forward toRead the log stream and the container logs, check the startup command, and for custom containers set WEBSITES_PORT to the port the process listens on.
    502 or 504 after about four minutes of waitingThe platform’s front end times out requests that take longer than about 230 secondsReturn quickly and move slow work to a background job, WebJob, queue or a durable function, and send a status URL back.
    The first request after a quiet period is slowAlways On is off, or the plan scaled in and a new instance must startTurn on Always On (Basic and above), use a health check, and keep a minimum of two instances for production.
    ModuleNotFoundError or build errors on Linux deploymentsDependencies were not installed because build during deployment is off, or the runtime version doesn’t matchSet SCM_DO_BUILD_DURING_DEPLOYMENT=true or build in your pipeline, and match the runtime to the one you developed against.
    A Key Vault reference shows as unresolvedThe app’s identity has no Key Vault Secrets User role, or the vault firewall blocks the appGrant the role to the identity, allow the app’s outbound address or integrated subnet in the vault firewall, and check the reference syntax.
    The app can’t reach a private databaseNo virtual network integration, or the subnet or its network security group blocks the trafficAdd regional VNet integration with a delegated subnet, route all traffic through it if needed and open the port on the database side.
    A slot swap leaves production brokenA setting that should have been sticky moved with the swap, or the new code needs a different configurationMark environment-specific settings as slot settings, test on the staging URL with the production configuration, and swap back if needed.
    Autoscale doesn’t add instancesThe rule’s metric, window or cool-down doesn’t match the load, or the plan is below the Standard tierCheck the autoscale run history, shorten the window, check the maximum count, and use a tier that supports autoscale.
    Everything on the plan slows down at onceApps on the same plan share CPU and memory, and one of them is using most of itLook at per-app metrics, move the heavy app to its own plan, or scale up or out.
    ERR_TOO_MANY_REDIRECTS or mixed content after enabling HTTPS onlyA proxy or the app itself redirects based on the wrong scheme, because TLS ends at the front endHonour the X-Forwarded-Proto header in the framework, and don’t redirect again inside the app.
    Unexpected cost for a test appThe plan is a paid tier that runs all day regardless of traffic, and extra instances or slots add to itUse the Free or Basic tier for tests, scale in out of hours, delete unused plans, and put small apps on a shared plan.

    Use cases: when and where to use it

    Good fit

    • Web sites, APIs and back ends for mobile apps in .NET, Java, Node.js, Python or PHP
    • Teams that want deployment slots and a managed runtime without running Kubernetes
    • Line-of-business web apps that need Entra sign-in and private network access
    • Moving an existing IIS or Tomcat style application from a server to a managed platform
    • Several small apps that can share one plan and one bill
    • Containerised web apps that don’t need an orchestrator

    Consider something else

    Pros: why consider it?

    Why teams choose it

    • Very little to run: Microsoft patches the operating system and runtimes
    • Deployment slots with warm-up swap make releases safer
    • Managed identity, Key Vault references and built-in authentication
    • Several apps can share one plan and its cost
    • Autoscale and scale-up are a setting, not a project
    • Works for code and for containers, on Windows and on Linux

    Trade-offs to weigh

    • You pay for the plan around the clock, and the service doesn’t scale to zero
    • Slots and autoscale need the Standard tier or above
    • Apps on one plan compete for the same CPU and memory
    • Less control than virtual machines or Kubernetes, with some platform limits and a request time limit of about 230 seconds
    • The pricing tiers and sizes change over time, and the names take effort to follow
    • Isolated environments give the strongest isolation but cost a lot

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    Public SCM (Kudu) site and FTP left openHighManagement endpoints reachable from the internet are a favourite target.Disable FTP and basic authentication, restrict the SCM site by IP or private endpoint, and use Entra-based deployment credentials.
    Secrets in app settings or in the repositoryHighThey leak through the portal, logs and source control.Use Key Vault references with a managed identity, and keep secrets out of Git.
    HTTP allowed and old TLS versionsMediumTraffic can be read or downgraded.Turn on HTTPS only, set the minimum TLS version to 1.2 or higher and use managed certificates.
    Production without a second instanceMediumA restart, a platform update or a failing instance takes the app down.Run at least two instances, and use zone redundancy on tiers that offer it.
    Staging slots exposed to the publicMediumUnfinished code and test data are reachable on a predictable URL.Apply access restrictions to slots and keep test data out of them.
    Noisy neighbours on a shared planMediumOne busy app slows the others and makes problems hard to trace.Give important apps their own plan, and watch per-app metrics.
    Unreviewed autoscale rulesMediumA wrong rule can scale out without limit or fail to scale when needed.Set a maximum, test with load, and alert on the instance count.
    Old runtime versionsLow–MedRetired runtimes lose security fixes and may be blocked later.Track runtime support dates and upgrade through a slot.
    Forgotten plans and slotsLow–MedIdle paid plans bill every hour.Tag plans by owner, review monthly and delete what nobody uses.

    Performance optimisation

    • Run at least two instances and turn on Always On, so the app isn’t cold and a single failure doesn’t stop it.
    • Pick the tier and size from measurements: a CPU-bound app wants more cores, a memory-hungry one needs a bigger size, and Premium sizes give faster disks and more memory.
    • Use autoscale rules on CPU or request metrics, with a sensible cool-down, and keep a scheduled rule for known peaks.
    • Put static files on a CDN or Storage and keep the plan for dynamic work.
    • Use the health check path so slow or broken instances leave rotation, and keep that endpoint cheap.
    • Keep the app and its data in the same region, and use VNet integration and private endpoints for private data stores.
    • Turn on HTTP/2 and compression where the framework doesn’t already do it.
    • Use Application Insights to find slow dependencies and queries before you buy more compute.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Azure App Service.

    • Know that you pay for the plan instance-hours, not per app, and that an idle plan still bills.
    • Put small apps on a shared plan until one of them needs isolation, and watch the plan’s CPU and memory.
    • Use the Free or Basic tier for development and tests, and delete plans you aren’t using.
    • Scale in at night and weekends with scheduled autoscale for internal apps.
    • Buy reserved instances or a savings plan for the production plans that run all year.
    • Choose Linux where the stack allows it, since the same size is often cheaper than Windows.
    • Don’t pay for Isolated tiers unless you need single-tenant isolation or very large scale.
    • Watch Application Insights and Log Analytics ingestion, which can cost more than a small app.
    • Remember that slots share the plan. They don’t add instance cost, but they use its CPU and memory.
    • Tag plans and apps by team, and set a budget alert in Cost Management.

    Tier names, sizes and prices change, and sources disagree on current figures (for example the newest Premium generation and slot limits). Check the live pricing page before you plan around anything (see Pricing).

    Security optimisation

    • Turn on HTTPS only, set the minimum TLS version to 1.2 or higher, and use App Service managed certificates or Key Vault certificates.
    • Use a managed identity for Azure services and Key Vault references for secrets, and don’t put credentials in app settings.
    • Enable built-in authentication with Microsoft Entra ID for apps that serve people, and validate tokens for APIs.
    • Disable FTP and basic authentication for deployment, and restrict the Kudu site by IP address or private endpoint.
    • Add access restrictions or a private endpoint, and put Front Door or Application Gateway with WAF in front of public apps.
    • Use VNet integration for outgoing traffic to private resources, and network security groups on the integration subnet.
    • Protect staging slots with the same restrictions as production.
    • Turn on Defender for App Service and review its recommendations.
    • Send HTTP, application and audit logs to Log Analytics, and alert on failed sign-ins, 5xx rates and configuration changes.
    • Use Azure Policy to enforce HTTPS, TLS version, managed identity and diagnostic settings across subscriptions.

    Governance & compliance

    Guardrails

    • Tagging policies for plans and apps (owner, environment, cost centre)
    • An Azure Policy that denies apps without HTTPS only, with FTP enabled or with public network access in production subscriptions
    • A shared Bicep or Terraform module for plans and apps, with managed identity, health check and diagnostics already set
    • A list of approved runtime versions with a retirement date for each

    Continuous checks (Azure Policy and Defender for Cloud)

    • “App Service apps should only be accessible over HTTPS”
    • “App Service apps should use the latest TLS version”
    • “App Service apps should have remote debugging turned off”
    • “App Service apps should use managed identity”
    • “App Service apps should disable public network access”

    The Azure Activity Log records who created or changed plans and apps, Azure Policy applies and reports on the rules above, Defender for Cloud gives recommendations, and the Service Trust Portal holds compliance material. Microsoft runs the hosts, the operating system updates and the platform, while you own the application code, its identity and secrets, network exposure, the plan size and the runtime upgrades.

    Reduce carbon footprint

    • Right-size the plan, and scale in when traffic is low.
    • Share a plan between small apps instead of running one lightly used plan for each.
    • Use Linux and efficient runtimes where they fit, since they often use less compute for the same work.
    • Serve static content from a CDN, so instances do less work.
    • Delete unused plans, slots and test apps.
    • Choose a region with a cleaner grid for workloads that aren’t tied to a place, as far as data rules allow.
    • The Azure Emissions Impact Dashboard reports a subscription’s footprint. Check how it treats App Service before you quote a figure.

    Pricing

    Purchase options

    App Service plan Per instance-hour

    You pay for each instance of the plan at the tier’s rate for as long as the plan exists, whatever the traffic. Several apps and slots share that cost.

    Tiers Varies by tier

    Free and Shared run on shared machines with limits. Basic and above use dedicated machines, Standard adds slots and autoscale, Premium adds faster hardware and more scale, and Isolated runs in your network at a higher price.

    Discounts Commitment

    Reserved instances and savings plans lower the price of plans that run all the time.

    Everything around it Varies

    Custom domains and certificates beyond the free ones, data transfer out, Application Insights and Log Analytics ingestion, private endpoints and Front Door or Application Gateway.

    What you actually pay for

    • Every plan instance, per hour, at the tier you chose
    • Extra instances added by scale out or autoscale
    • Isolated environments and their stamp fee, if you use them
    • Monitoring, private endpoints, Front Door or Application Gateway
    • Data transfer out and the services your app talks to

    Prices differ by region, operating system and tier, and change over time. See the official Azure App Service pricing page, the Azure pricing calculator and Microsoft's page on App Service plans for what each tier includes.

    Important code references

    The orders-api web app on a Premium Linux plan: two instances, HTTPS only, a managed identity that can write receipts to Blob Storage, a Key Vault reference for the database password, a health check, a staging slot, virtual network integration and CPU-based autoscale. The Azure CLI tab builds it and deploys through the slot, and Terraform builds the same set. The Python tab checks the staging slot and swaps it into production, and the C# tab reports on apps that have weak settings. Replace the names, vault, subnet and subscription with your own. A plan bills from the moment it exists, so delete the test one when you’re done.

    # Placeholders: replace the names, the vault and the virtual network (vnet-orders, subnet snet-webapps in rg-orders) with your own.
    RG=rg-orders-web
    LOC=centralindia
    PLAN=plan-orders
    APP=orders-api-example          # must be unique: it becomes orders-api-example.azurewebsites.net
    STORAGE=storordersexample
    VAULT=kv-orders-example
    
    az group create --name $RG --location $LOC
    
    # The plan is the thing you pay for: two Premium instances on Linux.
    az appservice plan create --name $PLAN --resource-group $RG --location $LOC --is-linux --sku P1V3 --number-of-workers 2
    
    az webapp create --name $APP --resource-group $RG --plan $PLAN --runtime "PYTHON:3.13"
    az webapp update --name $APP --resource-group $RG --https-only true
    az webapp config set --name $APP --resource-group $RG --always-on true --min-tls-version 1.2 --ftps-state Disabled --http20-enabled true \
      --startup-file "gunicorn --bind=0.0.0.0 --workers=3 app:app" --generic-configurations '{"healthCheckPath": "/healthz"}'
    
    # An identity for the app: no passwords for storage, and the database secret comes from Key Vault.
    az webapp identity assign --name $APP --resource-group $RG
    PRINCIPAL_ID=$(az webapp identity show --name $APP --resource-group $RG --query principalId -o tsv)
    az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
      --role "Storage Blob Data Contributor" --scope $(az storage account show --name $STORAGE --query id -o tsv)
    az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
      --role "Key Vault Secrets User" --scope $(az keyvault show --name $VAULT --query id -o tsv)
    
    az webapp config appsettings set --name $APP --resource-group $RG --settings \
      RECEIPT_ACCOUNT_URL=https://$STORAGE.blob.core.windows.net \
      "DB_PASSWORD=@Microsoft.KeyVault(SecretUri=https://$VAULT.vault.azure.net/secrets/orders-db-password/)" \
      SCM_DO_BUILD_DURING_DEPLOYMENT=true
    
    # Outgoing traffic goes through the virtual network, so the app can reach private databases.
    az webapp vnet-integration add --name $APP --resource-group $RG --vnet vnet-orders --subnet snet-webapps
    
    # A staging slot that starts from the production settings. Deploy there first.
    az webapp deployment slot create --name $APP --resource-group $RG --slot staging --configuration-source $APP
    az webapp deploy --name $APP --resource-group $RG --slot staging --src-path orders-1.5.0.zip --type zip
    
    # Test https://$APP-staging.azurewebsites.net, then put it live. The swap warms the slot up first.
    az webapp deployment slot swap --name $APP --resource-group $RG --slot staging --target-slot production
    
    # Add an instance when average CPU stays above 70 percent for 10 minutes, remove one below 30 percent.
    az monitor autoscale create --resource-group $RG --resource $PLAN --resource-type Microsoft.Web/serverfarms \
      --name autoscale-orders --min-count 2 --max-count 6 --count 2
    az monitor autoscale rule create --resource-group $RG --autoscale-name autoscale-orders --condition "CpuPercentage > 70 avg 10m" --scale out 1
    az monitor autoscale rule create --resource-group $RG --autoscale-name autoscale-orders --condition "CpuPercentage < 30 avg 10m" --scale in 1
    # Placeholders: pass in your own resource group, subnet, storage account and vault.
    variable "resource_group_name" {
      type    = string
      default = "rg-orders-web"
    }
    
    variable "location" {
      type    = string
      default = "centralindia"
    }
    
    variable "integration_subnet_id" {
      type = string
    }
    
    variable "storage_account_id" {
      type = string
    }
    
    variable "vault_id" {
      type = string
    }
    
    variable "vault_uri" {
      type    = string
      default = "https://kv-orders-example.vault.azure.net"
    }
    
    resource "azurerm_service_plan" "orders" {
      name                = "plan-orders"
      resource_group_name = var.resource_group_name
      location            = var.location
      os_type             = "Linux"
      sku_name            = "P1v3"
      worker_count        = 2
    }
    
    resource "azurerm_linux_web_app" "orders" {
      name                      = "orders-api-example"
      resource_group_name       = var.resource_group_name
      location                  = var.location
      service_plan_id           = azurerm_service_plan.orders.id
      https_only                = true
      virtual_network_subnet_id = var.integration_subnet_id
    
      identity {
        type = "SystemAssigned"
      }
    
      site_config {
        always_on           = true
        http2_enabled       = true
        ftps_state          = "Disabled"
        minimum_tls_version = "1.2"
        health_check_path   = "/healthz"
        app_command_line    = "gunicorn --bind=0.0.0.0 --workers=3 app:app"
    
        application_stack {
          python_version = "3.13"
        }
      }
    
      app_settings = {
        RECEIPT_ACCOUNT_URL            = "https://storordersexample.blob.core.windows.net"
        DB_PASSWORD                    = "@Microsoft.KeyVault(SecretUri=${var.vault_uri}/secrets/orders-db-password/)"
        SCM_DO_BUILD_DURING_DEPLOYMENT = "true"
      }
    }
    
    resource "azurerm_linux_web_app_slot" "staging" {
      name           = "staging"
      app_service_id = azurerm_linux_web_app.orders.id
      https_only     = true
    
      identity {
        type = "SystemAssigned"
      }
    
      site_config {
        always_on           = true
        ftps_state          = "Disabled"
        minimum_tls_version = "1.2"
        health_check_path   = "/healthz"
    
        application_stack {
          python_version = "3.13"
        }
      }
    }
    
    resource "azurerm_role_assignment" "blob_writer" {
      scope                = var.storage_account_id
      role_definition_name = "Storage Blob Data Contributor"
      principal_id         = azurerm_linux_web_app.orders.identity[0].principal_id
    }
    
    resource "azurerm_role_assignment" "vault_reader" {
      scope                = var.vault_id
      role_definition_name = "Key Vault Secrets User"
      principal_id         = azurerm_linux_web_app.orders.identity[0].principal_id
    }
    
    resource "azurerm_monitor_autoscale_setting" "orders" {
      name                = "autoscale-orders"
      resource_group_name = var.resource_group_name
      location            = var.location
      target_resource_id  = azurerm_service_plan.orders.id
    
      profile {
        name = "default"
    
        capacity {
          default = 2
          minimum = 2
          maximum = 6
        }
    
        rule {
          metric_trigger {
            metric_name        = "CpuPercentage"
            metric_resource_id = azurerm_service_plan.orders.id
            time_grain         = "PT1M"
            statistic          = "Average"
            time_window        = "PT10M"
            time_aggregation   = "Average"
            operator           = "GreaterThan"
            threshold          = 70
          }
          scale_action {
            direction = "Increase"
            type      = "ChangeCount"
            value     = "1"
            cooldown  = "PT5M"
          }
        }
    
        rule {
          metric_trigger {
            metric_name        = "CpuPercentage"
            metric_resource_id = azurerm_service_plan.orders.id
            time_grain         = "PT1M"
            statistic          = "Average"
            time_window        = "PT10M"
            time_aggregation   = "Average"
            operator           = "LessThan"
            threshold          = 30
          }
          scale_action {
            direction = "Decrease"
            type      = "ChangeCount"
            value     = "1"
            cooldown  = "PT10M"
          }
        }
      }
    }
    # Checks the staging slot and, only if it answers, swaps it into production.
    # pip install azure-identity azure-mgmt-web requests. Usage: swap.py <subscription> <group> <app>
    import sys
    import time
    
    import requests
    from azure.identity import DefaultAzureCredential
    from azure.mgmt.web import WebSiteManagementClient
    from azure.mgmt.web.models import CsmSlotEntity
    
    
    def slot_is_healthy(host, tries=6):
        url = "https://%s/healthz" % host
        for attempt in range(tries):
            try:
                if requests.get(url, timeout=10).status_code == 200:
                    return True
            except requests.RequestException:
                pass
            time.sleep(5 * (attempt + 1))
        return False
    
    
    def swap_to_production(client, group, app):
        slot = client.web_apps.get_slot(group, app, "staging")
        host = slot.default_host_name
        if not slot_is_healthy(host):
            raise SystemExit("staging slot at %s did not answer /healthz, not swapping" % host)
        # preserve_vnet keeps the virtual network integration of each slot where it is
        client.web_apps.begin_swap_slot(group, app, "staging", CsmSlotEntity(target_slot="production", preserve_vnet=True)).result()
        print("swapped: production now runs what was in staging")
    
    
    if __name__ == "__main__":
        subscription, group, app = sys.argv[1:4]
        swap_to_production(WebSiteManagementClient(DefaultAzureCredential(), subscription), group, app)
    // dotnet add package Azure.ResourceManager.AppService
    // dotnet add package Azure.Identity
    // Lists the web apps in a resource group and flags the ones with HTTP allowed or a stopped state.
    using Azure.Identity;
    using Azure.ResourceManager;
    using Azure.ResourceManager.AppService;
    using Azure.ResourceManager.Resources;
    
    if (args.Length < 2) { Console.Error.WriteLine("Usage: webapps <subscription> <resource-group>"); return 2; }
    
    var arm = new ArmClient(new DefaultAzureCredential());
    ResourceGroupResource group = await arm.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(args[0], args[1])).GetAsync();
    
    int weak = 0;
    await foreach (WebSiteResource app in group.GetWebSites().GetAllAsync())
    {
        var d = app.Data;
        var problems = new List<string>();
        if (d.IsHttpsOnly != true) problems.Add("HTTP allowed");
        if (d.State != "Running") problems.Add("state " + d.State);
        if (d.Identity is null) problems.Add("no managed identity");
        if (problems.Count > 0) weak++;
        Console.WriteLine($"{d.Name,-28} {d.Kind,-14} {d.DefaultHostName}  {(problems.Count == 0 ? "ok" : string.Join(", ", problems))}");
    }
    return weak == 0 ? 0 : 1;

    Best videos to explore

    Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.

    Introduction to Azure App ServiceVideo coming soon · Beginner
    App Service plans, tiers and scalingVideo coming soon · Intermediate
    Deployment slots and swaps in App ServiceVideo coming soon · Intermediate
    Securing an App Service app: identity, network and secretsVideo coming soon · Advanced

    Interview questions

    BasicWhat is Azure App Service?

    It’s Microsoft’s managed platform for hosting web apps, APIs and mobile back ends. You choose a runtime such as .NET, Java, Node.js, Python or PHP (or a container), and App Service runs it on virtual machines it looks after, with HTTPS, scaling, deployment slots and sign-in built in.

    BasicWhat is an App Service plan, and why does it matter for cost?

    The plan is the set of virtual machines your apps run on. It has a region, an operating system, a tier and size and an instance count. You’re billed for the plan by the hour whether it hosts one app or several, so putting small apps on a shared plan is the main saving, and an idle plan still costs money.

    BasicWhich tiers have deployment slots and autoscale?

    Slots and autoscale start at the Standard tier and are also in the Premium tiers. The Free, Shared and Basic tiers don’t have slots, and Basic has manual scaling only. Exact slot counts and tier names change, so check Microsoft’s current documentation.

    IntermediateHow does a deployment slot swap work?

    You deploy to a staging slot, which is a live copy of the app on its own host name, test it, and then swap. App Service warms up the staging slot with the target slot’s settings, and then exchanges the routing so that production serves the new code. Settings marked as slot settings stay with the slot. If something is wrong, you swap back.

    IntermediateHow do you keep secrets out of App Service settings?

    Give the app a managed identity, store the secrets in Key Vault, grant the identity the Key Vault Secrets User role, and put references such as @Microsoft.KeyVault(SecretUri=...) in the app settings. App Service resolves them at run time. For Azure data services, use the identity directly with no secret at all.

    IntermediateWhy do requests fail after about four minutes on App Service?

    The platform’s front end closes requests that take longer than about 230 seconds with a 502 or 504, whatever your app does. Keep requests short, return quickly and do the slow work in a background job or a queue, and give the client a status URL.

    AdvancedHow would you design a safe release process on App Service?

    Deploy the build artefact to a staging slot, run smoke tests against its URL with production-like settings, warm it up, then swap and watch metrics. Keep sticky settings for environment-specific values, use the health check to remove bad instances, and keep the swap-back ready. Run at least two instances so the platform can roll updates without downtime.

    AdvancedHow do you give an App Service app private access to a database and keep inbound traffic private too?

    Use regional virtual network integration with a delegated subnet for outgoing traffic to the database, and a private endpoint or access restrictions for incoming traffic, with Front Door or Application Gateway and WAF in front if the app is public. Check DNS for the private endpoints and route settings so that traffic really goes through the network.

    AdvancedWhen would you move from App Service to Container Apps or AKS?

    When you need scale to zero or event-driven scaling, many small services with revisions and traffic splitting, or full Kubernetes features. Container Apps suits spiky and event-driven containers, and AKS suits teams that need Kubernetes itself. App Service stays a good fit for conventional web apps that want slots, easy scaling and little else to run.

    AdvancedWhat are the trade-offs of putting many apps on one App Service plan?

    It’s cheaper, because the instances are shared, but the apps compete for the same CPU and memory, scale together and can hide each other’s problems. Keep apps with similar load patterns together, give critical or noisy apps their own plan, use per-app scaling carefully and watch the plan’s metrics.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAWS Elastic BeanstalkAzure App ServiceGoogle App Engine
    What you pay forThe EC2 instances and the load balancer it creates, nothing for the serviceThe plan, per instance-hour, shared by its appsInstance hours, with a free daily allowance on standard
    Scale to zeroNoNoYes on the standard environment
    Staging and swapsCNAME swap between environmentsDeployment slots with a warm-up swapVersions with traffic splitting
    AutoscaleAuto Scaling group rulesAutoscale rules on the plan, Standard and aboveAutomatic scaling settings in app.yaml
    Identity for the appInstance profileManaged identityService account
    Private networkingVPC, private subnetsVNet integration and private endpointsVPC connector or Direct VPC egress
    Request time limitSet on the load balancerAbout 230 secondsMinutes on automatic scaling, longer on manual scaling

    For containers that scale to zero, look at Azure Container Apps. For event-driven code use Azure Functions, and for Kubernetes use Azure Kubernetes Service. App Service apps usually keep their data in Azure SQL Database and their files in Azure Blob Storage.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.