Configure a Node.js app for Azure App Service
Node.js apps must be deployed with all the required npm dependencies. The App Service deployment engine automatically runs npm install --production
for you when you deploy a Git repository, or when you deploy a Zip package with build automation enabled. 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 deploy to App Service. If you've never used Azure App Service, follow the Node.js quickstart first.
Show Node.js version
To show the current Node.js version, run the following command in the Azure CLI:
az webapp config appsettings list --name <app-name> --resource-group <resource-group-name> --query "[?name=='WEBSITE_NODE_DEFAULT_VERSION'].value"
To show all supported Node.js versions, run the following command in the Azure CLI:
az webapp list-runtimes --os windows | grep NODE
To show the current Node.js version, run the following command in the Azure CLI:
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 Azure CLI:
az webapp list-runtimes --os linux | grep NODE
Set Node.js version
To set your app to a supported Node.js version, run the following command in the Azure CLI to set WEBSITE_NODE_DEFAULT_VERSION
to a supported version:
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings WEBSITE_NODE_DEFAULT_VERSION="~16"
Note
This example uses the recommended "tilde syntax" to target the latest available version of Node.js 16 runtime on App Service.
Since the runtime is regularly patched and updated by the platform, we don't recommend that you target a specific minor version/patch as these are not guaranteed to be available due to potential security risks.
Note
You should set the Node.js version in your project's package.json
. The deployment engine runs in a separate process that contains all the supported Node.js versions.
To set your app to a supported Node.js version, run the following command in the Azure CLI:
az webapp config set --resource-group <resource-group-name> --name <app-name> --linux-fx-version "NODE|14-lts"
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.
Get port number
Your Node.js app needs to listen to the right port to receive incoming requests.
In App Service on Windows, Node.js apps are hosted with IISNode, and your Node.js app should listen to the port specified in the process.env.PORT
variable. The following example shows how to do that in a simple Express app:
App Service sets the environment variable PORT
in the Node.js container, and forwards the incoming requests to your container at that port number. To receive the requests, your app should listen to that port using process.env.PORT
. The following example shows how to do that in a simple Express app:
const express = require('express')
const app = express()
const port = process.env.PORT || 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Customize build automation
If you deploy your app by using Git, or by using zip packages with build automation enabled, the App Service build automation steps through the following sequence:
- Run custom script, if one is specified by
PRE_BUILD_SCRIPT_PATH
. - Run
npm install
without any flags, which includes npmpreinstall
andpostinstall
scripts and also installsdevDependencies
. - Run
npm run build
if a build script is specified in your package.json. - Run
npm run build:azure
if a build:azure script is specified in your package.json. - Run custom script if specified by
POST_BUILD_SCRIPT_PATH
.
Note
As is noted in the 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 uses the two variables to specify 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/prebuild.sh"
az webapp config appsettings set --name <app-name> --resource-group <resource-group-name> --settings POST_BUILD_COMMAND="echo foo, scripts/postbuild.sh"
For information about 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, with npm start, or with a custom command.
Tool | Purpose |
---|---|
Run with PM2 | Recommended - Production or staging use. PM2 provides a full-service app management platform. |
Run with npm start | Development use only. |
Run with a custom command | Either development or staging. |
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 or 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
Note
Starting from Node 14 LTS, the container doesn't automatically start your app with PM2. To start your app with PM2, set the startup command to pm2 start <.js-file-or-PM2-file> --no-daemon
. Be sure to use the --no-daemon
argument because PM2 needs to run in the foreground for the container to work properly.
To add a custom start file, run the following command in the Azure CLI:
az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "<filename-with-extension>"
Run with a 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 Azure CLI:
az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "npm run start:prod"
Run with 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 Azure CLI:
az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "<filename>.json"
Debug remotely
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. Select Yes to enable remote debugging 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 select 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, App Service build automation runs npm install --production
when it recognizes that a Node.js app is deployed through Git, or through Zip deployment with build automation enabled. 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 the 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
To access the console logs generated from inside your application code in App Service, turn on diagnostics logging by running the following command in the Azure CLI:
az webapp log config --resource-group <resource-group-name> --name <app-name> --docker-container-logging filesystem --level Verbose
Possible values for --level
are: Error
, Warning
, Info
, and Verbose
. Each subsequent level includes the previous level. For example: Error
includes only error messages, and Verbose
includes all messages.
Once diagnostic logging is turned on, run the following command to see the log stream:
az webapp log tail --resource-group <resource-group-name> --name <app-name>
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.chinacloudsites.cn/api/logs/docker
.
To stop log streaming at any time, type Ctrl
+C
.
You can access the console logs generated from inside the container.
First, turn on container logging by running the following command:
az webapp log config --name <app-name> --resource-group <resource-group-name> --docker-container-logging filesystem
Replace <app-name>
and <resource-group-name>
with the names appropriate for your web app.
Once container logging is turned on, run the following command to see the log stream:
az webapp log tail --name <app-name> --resource-group <resource-group-name>
If you don't see console logs immediately, check again in 30 seconds.
To stop log streaming at any time, type Ctrl+C.
You can also inspect the log files in a browser at https://<app-name>.scm.chinacloudsites.cn/api/logs/docker
.
URL rewrites
When deploying Node.js apps on Azure App Service for Linux, you might need to handle URL rewrites directly within your application. This is particularly useful for ensuring specific URL patterns are redirected to the correct endpoints without relying on web server configurations. There are several ways to accomplish URL rewrites in Node.js. One example is through the express-urlrewrite package.
Monitor with Application Insights
Application Insights allows you to monitor your application's performance, exceptions, and usage without making any code changes. To attach the Application Insights agent, go to your web app in the portal, select Application Insights under Settings, and then select Turn on Application Insights. Next, select an existing Application Insights resource or create a new one. Finally, select Apply at the bottom. To instrument your web app using PowerShell, see these instructions
This agent will monitor your server-side Node.js application. To monitor your client-side JavaScript, add the JavaScript SDK to your project.
For more information, see the Application Insights extension release notes.
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 might be installed for production mode (
dependencies
vs.devDependencies
). - Certain web frameworks might deploy static files differently in production mode.
- Certain web frameworks might use custom startup scripts when running in production mode.
- Depending on your package.json, different packages might be installed for production mode (
- Run your app in App Service in development mode. For example, in MEAN.js, you can set your app to development mode at runtime by setting the
NODE_ENV
app setting.
You do not have permission to view this directory or page
After deploying your Node.js code to a native Windows app in App Service, you might see the message You do not have permission to view this directory or page
in the browser when navigating to your app's URL. This is most likely because you don't have a web.config file. (See the template and an example.)
If you deploy your files by using Git, or by using ZIP deployment with build automation enabled, the deployment engine generates a web.config in the web root of your app (%HOME%\site\wwwroot
) automatically if one of the following conditions is true:
- Your project root has a package.json that defines a
start
script that contains the path of a JavaScript file. - Your project root has either a server.js or an app.js.
The generated web.config is tailored to the detected start script. For other deployment methods, add this web.config manually. Make sure the file is formatted properly.
If you use ZIP deployment (through Visual Studio Code, for example), be sure to enable build automation. It's not enabled by default. az webapp up
uses ZIP deployment with build automation enabled.
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
Or, see additional resources: