Run your app in Azure App Service directly from a ZIP package

In Azure App Service, you can run your apps directly from a deployment ZIP package file. This article shows how to enable this functionality in your app.

All other deployment methods in App Service have something in common: your files are deployed to D:\home\site\wwwroot in your app (or /home/site/wwwroot for Linux apps). Since the same directory is used by your app at runtime, it's possible for deployment to fail because of file lock conflicts, and for the app to behave unpredictably because some of the files are not yet updated.

In contrast, when you run directly from a package, the files in the package are not copied to the wwwroot directory. Instead, the ZIP package itself gets mounted directly as the read-only wwwroot directory. There are several benefits to running directly from a package:

  • Eliminates file lock conflicts between deployment and runtime.
  • Ensures only full-deployed apps are running at any time.
  • Can be deployed to a production app (with restart).
  • Improves the performance of Azure Resource Manager deployments.
  • May reduce cold-start times, particularly for JavaScript functions with large npm package trees.

Note

Currently, only ZIP package files are supported.

Create a project ZIP package

Important

When creating the ZIP package for deployment, don't include the root directory, but only the files and directories in it. If you download a GitHub repository as a ZIP file, you cannot deploy that file as-is to App Service. GitHub adds additional nested directories at the top level, which do not work with App Service.

In a local terminal window, navigate to the root directory of your app project.

This directory should contain the entry file to your web app, such as index.html, index.php, and app.js. It can also contain package management files like project.json, composer.json, package.json, bower.json, and requirements.txt.

Unless you want App Service to run deployment automation for you, run all the build tasks (for example, npm, bower, gulp, composer, and pip) and make sure that you have all the files you need to run the app. This step is required if you want to run your package directly.

Create a ZIP archive of everything in your project. For dotnet projects, this is everything in the output directory of the dotnet publish command (excluding the output directory itself). For example, the following command in your terminal to create a ZIP package of the contents of the current directory:

# Bash
zip -r <file-name>.zip .

# PowerShell
Compress-Archive -Path * -DestinationPath <file-name>.zip

Enable running from package

The WEBSITE_RUN_FROM_PACKAGE app setting enables running from a package. To set it, run the following command with Azure CLI.

az webapp config appsettings set --resource-group <group-name> --name <app-name> --settings WEBSITE_RUN_FROM_PACKAGE="1"

WEBSITE_RUN_FROM_PACKAGE="1" lets you run your app from a package local to your app. You can also run from a remote package.

Run the package

The easiest way to run a package in your App Service is with the Azure CLI az webapp deployment source config-zip command. For example:

az webapp deployment source config-zip --resource-group <group-name> --name <app-name> --src <filename>.zip

Because the WEBSITE_RUN_FROM_PACKAGE app setting is set, this command doesn't extract the package content to the D:\home\site\wwwroot directory of your app. Instead, it uploads the ZIP file as-is to D:\home\data\SitePackages, and creates a packagename.txt in the same directory, that contains the name of the ZIP package to load at runtime. If you upload your ZIP package in a different way (such as FTP), you need to create the D:\home\data\SitePackages directory and the packagename.txt file manually.

The command also restarts the app. Because WEBSITE_RUN_FROM_PACKAGE is set, App Service mounts the uploaded package as the read-only wwwroot directory and runs the app directly from that mounted directory.

Run from external URL instead

You can also run a package from an external URL, such as Azure Blob Storage. You can use the Azure Storage Explorer to upload package files to your Blob storage account. You should use a private storage container with a Shared Access Signature (SAS) or use a managed identity to enable the App Service runtime to access the package securely.

Once you upload your file to Blob storage and have an SAS URL for the file, set the WEBSITE_RUN_FROM_PACKAGE app setting to the URL. The following example does it by using Azure CLI:

az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings WEBSITE_RUN_FROM_PACKAGE="https://myblobstorage.blob.core.windows.net/content/SampleCoreMVCApp.zip?st=2018-02-13T09%3A48%3A00Z&se=2044-06-14T09%3A48%3A00Z&sp=rl&sv=2017-04-17&sr=b&sig=bNrVrEFzRHQB17GFJ7boEanetyJ9DGwBSV8OM3Mdh%2FM%3D"

If you publish an updated package with the same name to Blob storage, you need to restart your app so that the updated package is loaded into App Service.

Access a package in Azure Blob Storage using a managed identity

Azure Blob Storage can be configured to authorize requests with Microsoft Entra ID. This means that instead of generating a SAS key with an expiration, you can instead rely on the application's managed identity. By default, the app's system-assigned identity will be used. If you wish to specify a user-assigned identity, you can set the WEBSITE_RUN_FROM_PACKAGE_BLOB_MI_RESOURCE_ID app setting to the resource ID of that identity. The setting can also accept "SystemAssigned" as a value, although this is the same as omitting the setting altogether.

To enable the package to be fetched using the identity:

  1. Ensure that the blob is configured for private access.

  2. Grant the identity the Storage Blob Data Reader role with scope over the package blob. See Assign an Azure role for access to blob data for details on creating the role assignment.

  3. Set the WEBSITE_RUN_FROM_PACKAGE application setting to the blob URL of the package. This will likely be of the form "https://{storage-account-name}.blob.core.windows.net/{container-name}/{path-to-package}" or similar.

Deploy WebJob files when running from package

There are two ways to deploy WebJob files when you enable running an app from package:

  • Deploy in the same ZIP package as your app: include them as you normally would in <project-root>\app_data\jobs\... (which maps to the deployment path \site\wwwroot\app_data\jobs\... as specified in the WebJobs quickstart).
  • Deploy separately from the ZIP package of your app: Since the usual deployment path \site\wwwroot\app_data\jobs\... is now read-only, you can't deploy WebJob files there. Instead, deploy WebJob files to \site\jobs\..., which is not read only. WebJobs deployed to \site\wwwroot\app_data\jobs\... and \site\jobs\... both run.

Note

When \site\wwwroot becomes read-only, operations like the creation of the disable.job will fail.

Troubleshooting

  • Running directly from a package makes wwwroot read-only. Your app will receive an error if it tries to write files to this directory.
  • TAR and GZIP formats are not supported.
  • The ZIP file can be at most 1GB
  • This feature is not compatible with local cache.
  • For improved cold-start performance, use the local Zip option (WEBSITE_RUN_FROM_PACKAGE=1).

More resources