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.

Note

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.

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 run.sh. 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

Note

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:

process.env.NODE_ENV

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 deploy.sh.

Open deploy.sh 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.

Bower

This snippet runs bower install.

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

Gulp

This snippet runs gulp imagemin.

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

Grunt

This snippet runs grunt.

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

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 (req.secure) {
  // 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.

Note

You can also inspect the log files from the browser at https://<app-name>.scm.azurewebsites.net/api/logs/docker.

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:

https://<app-name>.scm.azurewebsites.net/webssh/host

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

Note

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.

Troubleshooting

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.

Next steps