Configure a Linux Node.js app for Azure App Service

Node.js apps must be deployed with all the required NPM dependencies. The App Service deployment engine (Kudu) automatically runs npm install --production for you when you deploy a Git repository, or a Zip package with build processes switched on. If you deploy your files using FTP/S, however, you need to upload the required packages manually.

This guide provides key concepts and instructions for Node.js developers who use a built-in Linux container in App Service. If you've never used Azure App Service, follow the Node.js quickstart and Node.js with MongoDB tutorial first.

Show Node.js version

To show the current Node.js version, run the following command in the Cloud Shell:

az webapp config show --resource-group <resource-group-name> --name <app-name> --query linuxFxVersion

To show all supported Node.js versions, run the following command in the Cloud Shell:

az webapp list-runtimes --linux | grep NODE

Set Node.js version

To set your app to a supported Node.js version, run the following command in the Cloud Shell:

az webapp config set --resource-group <resource-group-name> --name <app-name> --linux-fx-version "NODE|10.14"

This setting specifies the Node.js version to use, both at runtime and during automated package restore in Kudu.


You should set the Node.js version in your project's package.json. The deployment engine runs in a separate container that contains all the supported Node.js versions.

Customize build automation

If you deploy your app using Git or zip packages with build automation turned on, the App Service build automation steps through the following sequence:

  1. Run custom script if specified by PRE_BUILD_SCRIPT_PATH.
  2. Run npm install without any flags, which includes npm preinstall and postinstall scripts and also installs devDependencies.
  3. Run npm run build if a build script is specified in your package.json.
  4. Run npm run build:azure if a build:azure script is specified in your package.json.
  5. Run custom script if specified by POST_BUILD_SCRIPT_PATH.


As described in npm docs, scripts named prebuild and postbuild run before and after build, respectively, if specified. preinstall and postinstall run before and after install, respectively.

PRE_BUILD_COMMAND and POST_BUILD_COMMAND are environment variables that are empty by default. To run pre-build commands, define PRE_BUILD_COMMAND. To run post-build commands, define POST_BUILD_COMMAND.

The following example specifies the two variables to a series of commands, separated by commas.

az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings PRE_BUILD_COMMAND="echo foo, scripts/"
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings POST_BUILD_COMMAND="echo foo, scripts/"

For additional environment variables to customize build automation, see Oryx configuration.

For more information on how App Service runs and builds Node.js apps in Linux, see Oryx documentation: How Node.js apps are detected and built.

Configure Node.js server

The Node.js containers come with PM2, a production process manager. You can configure your app to start with PM2, or with NPM, or with a custom command.

Run custom command

App Service can start your app using a custom command, such as an executable like For example, to run npm run start:prod, run the following command in the Cloud Shell:

az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "npm run start:prod"

Run npm start

To start your app using npm start, just make sure a start script is in the package.json file. For example:

  "scripts": {
    "start": "gulp",

To use a custom package.json in your project, run the following command in the Cloud Shell:

az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "<filename>.json"

Run with PM2

The container automatically starts your app with PM2 when one of the common Node.js files is found in your project:

  • bin/www
  • server.js
  • app.js
  • index.js
  • hostingstart.js
  • One of the following PM2 files: process.json and ecosystem.config.js

You can also configure a custom start file with the following extensions:

  • A .js file
  • A PM2 file with the extension .json, .config.js, .yaml, or .yml

To add a custom start file, run the following command in the Cloud Shell:

az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "<filname-with-extension>"

Debug remotely


Remote debugging is currently in Preview.

You can debug your Node.js app remotely in Visual Studio Code if you configure it to run with PM2, except when you run it using a *.config.js, *.yml, or .yaml.

In most cases, no extra configuration is required for your app. If your app is run with a process.json file (default or custom), it must have a script property in the JSON root. For example:

  "name"        : "worker",
  "script"      : "./index.js",

To set up Visual Studio Code for remote debugging, install the App Service extension. Follow the instructions on the extension page and sign in to Azure in Visual Studio Code.

In the Azure explorer, find the app you want to debug, right-click it and select Start Remote Debugging. Click Yes to enable it for your app. App Service starts a tunnel proxy for you and attaches the debugger. You can then make requests to the app and see the debugger pausing at break points.

Once finished with debugging, stop the debugger by selecting Disconnect. When prompted, you should click Yes to disable remote debugging. To disable it later, right-click your app again in the Azure explorer and select Disable Remote Debugging.

Access environment variables

In App Service, you can set app settings outside of your app code. Then you can access them using the standard Node.js pattern. For example, to access an app setting called NODE_ENV, use the following code:


Run Grunt/Bower/Gulp

By default, Kudu runs npm install --production when it recognizes a Node.js app is deployed. If your app requires any of the popular automation tools, such as Grunt, Bower, or Gulp, you need to supply a custom deployment script to run it.

To enable your repository to run these tools, you need to add them to the dependencies in package.json. For example:

"dependencies": {
  "bower": "^1.7.9",
  "grunt": "^1.0.1",
  "gulp": "^3.9.1",

From a local terminal window, change directory to your repository root and run the following commands:

npm install kuduscript -g
kuduscript --node --scriptType bash --suppressPrompt

Your repository root now has two additional files: .deployment and

Open and find the Deployment section, which looks like this:

# Deployment
# ----------

This section ends with running npm install --production. Add the code section you need to run the required tool at the end of the Deployment section:

See an example in the MEAN.js sample, where the deployment script also runs a custom npm install command.


This snippet runs bower install.

if [ -e "$DEPLOYMENT_TARGET/bower.json" ]; then
  eval ./node_modules/.bin/bower install
  exitWithMessageOnError "bower failed"
  cd - > /dev/null


This snippet runs gulp imagemin.

if [ -e "$DEPLOYMENT_TARGET/gulpfile.js" ]; then
  eval ./node_modules/.bin/gulp imagemin
  exitWithMessageOnError "gulp failed"
  cd - > /dev/null


This snippet runs grunt.

if [ -e "$DEPLOYMENT_TARGET/Gruntfile.js" ]; then
  eval ./node_modules/.bin/grunt
  exitWithMessageOnError "Grunt failed"
  cd - > /dev/null

Detect HTTPS session

In App Service, SSL termination happens at the network load balancers, so all HTTPS requests reach your app as unencrypted HTTP requests. If your app logic needs to check if the user requests are encrypted or not, inspect the X-Forwarded-Proto header.

Popular web frameworks let you access the X-Forwarded-* information in your standard app pattern. In Express, you can use trust proxies. For example:

app.set('trust proxy', 1)
if ( {
  // Do something when HTTPS is used

Access diagnostic logs

You can access the console logs generated from inside the container. First, turn on container logging by running the following command in the Cloud Shell:

az webapp log config --name <app-name> --resource-group myResourceGroup --docker-container-logging filesystem

Once container logging is turned on, run the following command to see the log stream:

az webapp log tail --name <app-name> --resource-group myResourceGroup

If you don't see console logs immediately, check again in 30 seconds.


You can also inspect the log files from the browser at https://<app-name>

To stop log streaming at any time, type Ctrl+C.

Open SSH session in browser

To make open a direct SSH session with your container, your app should be running.

Paste the following URL into your browser and replace <app-name> with your app name:


If you're not yet authenticated, you're required to authenticate with your Azure subscription to connect. Once authenticated, you see an in-browser shell, where you can run commands inside your container.

SSH connection


Any changes you make outside the /home directory are stored in the container itself and don't persist beyond an app restart.

To open a remote SSH session from your local machine, see Open SSH session from remote shell.


When a working Node.js app behaves differently in App Service or has errors, try the following:

  • Access the log stream.
  • Test the app locally in production mode. App Service runs your Node.js apps in production mode, so you need to make sure that your project works as expected in production mode locally. For example:
    • Depending on your package.json, different packages may be installed for production mode (dependencies vs. devDependencies).
    • Certain web frameworks may deploy static files differently in production mode.
    • Certain web frameworks may use custom startup scripts when running in production mode.
  • Run your app in App Service in development mode. For example, in MEAN.js, you can set your app to development mode in runtime by setting the NODE_ENV app setting.

robots933456 in logs

You may see the following message in the container logs:

2019-04-08T14:07:56.641002476Z "-" - - [08/Apr/2019:14:07:56 +0000] "GET /robots933456.txt HTTP/1.1" 404 415 "-" "-"

You can safely ignore this message. /robots933456.txt is a dummy URL path that App Service uses to check if the container is capable of serving requests. A 404 response simply indicates that the path doesn't exist, but it lets App Service know that the container is healthy and ready to respond to requests.

Next steps