Build a Node.js and MongoDB app in Azure App Service on Linux

Note

This article deploys an app to App Service on Linux. To deploy to App Service on Windows, see Build a Node.js and MongoDB app in Azure.

App Service on Linux provides a highly scalable, self-patching web hosting service using the Linux operating system. This tutorial shows how to create a Node.js app, connect it locally to a MongoDB database, then deploy it to a database in Azure Cosmos DB's API for MongoDB. When you're done, you'll have a MEAN application (MongoDB, Express, AngularJS, and Node.js) running in App Service on Linux. For simplicity, the sample application uses the MEAN.js web framework.

MEAN.js app running in Azure App Service

In this tutorial, you learn how to:

  • Create a database using Azure Cosmos DB's API for MongoDB
  • Connect a Node.js app to MongoDB
  • Deploy the app to Azure
  • Update the data model and redeploy the app
  • Stream diagnostic logs from Azure
  • Manage the app in the Azure portal

If you don't have an Azure subscription, create a free account before you begin.

Prerequisites

To complete this tutorial:

  1. Install Git
  2. Install Node.js v6.0 or above and NPM
  3. Install Gulp.js (required by MEAN.js)
  4. Install and run MongoDB Community Edition

Test local MongoDB

Open the terminal window and cd to the bin directory of your MongoDB installation. You can use this terminal window to run all the commands in this tutorial.

Run mongo in the terminal to connect to your local MongoDB server.

mongo

If your connection is successful, then your MongoDB database is already running. If not, make sure that your local MongoDB database is started by following the steps at Install MongoDB Community Edition. Often, MongoDB is installed, but you still need to start it by running mongod.

When you're done testing your MongoDB database, type Ctrl+C in the terminal.

Create local Node.js app

In this step, you set up the local Node.js project.

Clone the sample application

In the terminal window, cd to a working directory.

Run the following command to clone the sample repository.

git clone https://github.com/Azure-Samples/meanjs.git

This sample repository contains a copy of the MEAN.js repository. It is modified to run on App Service (for more information, see the MEAN.js repository README file).

Run the application

Run the following commands to install the required packages and start the application.

cd meanjs
npm install
npm start

Ignore the config.domain warning. When the app is fully loaded, you see something similar to the following message:

--
MEAN.JS - Development Environment

Environment:     development
Server:          http://0.0.0.0:3000
Database:        mongodb://localhost/mean-dev
App version:     0.5.0
MEAN.JS version: 0.5.0
--

Navigate to http://localhost:3000 in a browser. Click Sign Up in the top menu and create a test user.

The MEAN.js sample application stores user data in the database. If you are successful at creating a user and signing in, then your app is writing data to the local MongoDB database.

MEAN.js connects successfully to MongoDB

Select Admin > Manage Articles to add some articles.

To stop Node.js at any time, press Ctrl+C in the terminal.

Use Azure Cloud Shell

Azure hosts Azure Cloud Shell, an interactive shell environment that you can use through your browser. Cloud Shell lets you use either bash or PowerShell to work with Azure services. You can use the Cloud Shell pre-installed commands to run the code in this article without having to install anything on your local environment.

To launch Azure Cloud Shell:

Option Example/Link
Select Try It in the upper-right corner of a code block. Selecting Try It doesn't automatically copy the code to Cloud Shell. Example of Try It for Azure Cloud Shell
Go to https://shell.azure.com or select the Launch Cloud Shell button to open Cloud Shell in your browser.
Select the Cloud Shell button on the top-right menu bar in the Azure portal. Cloud Shell button in the Azure portal

To run the code in this article in Azure Cloud Shell:

  1. Launch Cloud Shell.
  2. Select the Copy button on a code block to copy the code.
  3. Paste the code into the Cloud Shell session with Ctrl+Shift+V on Windows and Linux, or Cmd+Shift+V on macOS.
  4. Press Enter to run the code.

Create production MongoDB

In this step, you create a database account using Azure Cosmos DB's API for MongoDB. When your app is deployed to Azure, it uses this cloud database.

Create a resource group

A resource group is a logical container into which Azure resources like web apps, databases, and storage accounts are deployed and managed. For example, you can choose to delete the entire resource group in one simple step later.

In the Cloud Shell, create a resource group with the az group create command. The following example creates a resource group named myResourceGroup in the West Europe location. To see all supported locations for App Service on Linux in Basic tier, run the az appservice list-locations --sku B1 --linux-workers-enabled command.

az group create --name myResourceGroup --location "West Europe"

You generally create your resource group and the resources in a region near you.

When the command finishes, a JSON output shows you the resource group properties.

Create a Cosmos DB account

In the Cloud Shell, create a Cosmos DB account with the az cosmosdb create command.

In the following command, substitute a unique Cosmos DB name for the <cosmosdb-name> placeholder. This name is used as the part of the Cosmos DB endpoint, https://<cosmosdb-name>.documents.azure.com/, so the name needs to be unique across all Cosmos DB accounts in Azure. The name must contain only lowercase letters, numbers, and the hyphen (-) character, and must be between 3 and 50 characters long.

az cosmosdb create --name <cosmosdb-name> --resource-group myResourceGroup --kind MongoDB

The --kind MongoDB parameter enables MongoDB client connections.

When the Cosmos DB account is created, the Azure CLI shows information similar to the following example:

{
  "consistencyPolicy":
  {
    "defaultConsistencyLevel": "Session",
    "maxIntervalInSeconds": 5,
    "maxStalenessPrefix": 100
  },
  "databaseAccountOfferType": "Standard",
  "documentEndpoint": "https://<cosmosdb-name>.documents.azure.com:443/",
  "failoverPolicies":
  ...
  < Output truncated for readability >
}

Connect app to production configured with Azure Cosmos DB's API for MongoDB

In this step, you connect your MEAN.js sample application to the Cosmos DB database you just created, using a MongoDB connection string.

Retrieve the database key

To connect to the Cosmos DB database, you need the database key. In the Cloud Shell, use the az cosmosdb list-keys command to retrieve the primary key.

az cosmosdb list-keys --name <cosmosdb-name> --resource-group myResourceGroup

The Azure CLI shows information similar to the following example:

{
  "primaryMasterKey": "RS4CmUwzGRASJPMoc0kiEvdnKmxyRILC9BWisAYh3Hq4zBYKr0XQiSE4pqx3UchBeO4QRCzUt1i7w0rOkitoJw==",
  "primaryReadonlyMasterKey": "HvitsjIYz8TwRmIuPEUAALRwqgKOzJUjW22wPL2U8zoMVhGvregBkBk9LdMTxqBgDETSq7obbwZtdeFY7hElTg==",
  "secondaryMasterKey": "Lu9aeZTiXU4PjuuyGBbvS1N9IRG3oegIrIh95U6VOstf9bJiiIpw3IfwSUgQWSEYM3VeEyrhHJ4rn3Ci0vuFqA==",
  "secondaryReadonlyMasterKey": "LpsCicpVZqHRy7qbMgrzbRKjbYCwCKPQRl0QpgReAOxMcggTvxJFA94fTi0oQ7xtxpftTJcXkjTirQ0pT7QFrQ=="
}

Copy the value of primaryMasterKey. You need this information in the next step.

Configure the connection string in your Node.js application

In your local MEAN.js repository, in the config/env/ folder, create a file named local-production.js. .gitignore is configured to keep this file out of the repository.

Copy the following code into it. Be sure to replace the two <cosmosdb-name> placeholders with your Cosmos DB database name, and replace the <primary-master-key> placeholder with the key you copied in the previous step.

module.exports = {
  db: {
    uri: 'mongodb://<cosmosdb-name>:<primary-master-key>@<cosmosdb-name>.documents.azure.com:10250/mean?ssl=true&sslverifycertificate=false'
  }
};

The ssl=true option is required because Cosmos DB requires SSL.

Save your changes.

Test the application in production mode

In a local terminal window, run the following command to minify and bundle scripts for the production environment. This process generates the files needed by the production environment.

gulp prod

In a local terminal window, run the following command to use the connection string you configured in config/env/local-production.js. Ignore the certificate error and the config.domain warning.

NODE_ENV=production node server.js

NODE_ENV=production sets the environment variable that tells Node.js to run in the production environment. node server.js starts the Node.js server with server.js in your repository root. This is how your Node.js application is loaded in Azure.

When the app is loaded, check to make sure that it's running in the production environment:

--
MEAN.JS

Environment:     production
Server:          http://0.0.0.0:8443
Database:        mongodb://<cosmosdb-name>:<primary-master-key>@<cosmosdb-name>.documents.azure.com:10250/mean?ssl=true&sslverifycertificate=false
App version:     0.5.0
MEAN.JS version: 0.5.0

Navigate to http://localhost:8443 in a browser. Click Sign Up in the top menu and create a test user. If you are successful creating a user and signing in, then your app is writing data to the Cosmos DB database in Azure.

In the terminal, stop Node.js by typing Ctrl+C.

Deploy app to Azure

In this step, you deploy your Node.js application to Azure App Service.

Configure local git deployment

FTP and local Git can deploy to an Azure web app by using a deployment user. Once you configure your deployment user, you can use it for all your Azure deployments. Your account-level deployment username and password are different from your Azure subscription credentials.

To configure the deployment user, run the az webapp deployment user set command in Azure Cloud Shell. Replace <username> and <password> with a deployment user username and password.

  • The username must be unique within Azure, and for local Git pushes, must not contain the ‘@’ symbol.
  • The password must be at least eight characters long, with two of the following three elements: letters, numbers, and symbols.
az webapp deployment user set --user-name <username> --password <password>

The JSON output shows the password as null. If you get a 'Conflict'. Details: 409 error, change the username. If you get a 'Bad Request'. Details: 400 error, use a stronger password.

Record your username and password to use to deploy your web apps.

Create an App Service plan

In the Cloud Shell, create an App Service plan in the resource group with the az appservice plan create command.

The following example creates an App Service plan named myAppServicePlan in the Basic pricing tier (--sku B1) and in a Linux container (--is-linux).

az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku B1 --is-linux

When the App Service plan has been created, the Azure CLI shows information similar to the following example:

{ 
  "adminSiteName": null,
  "appServicePlanName": "myAppServicePlan",
  "geoRegion": "West Europe",
  "hostingEnvironmentProfile": null,
  "id": "/subscriptions/0000-0000/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/myAppServicePlan",
  "kind": "linux",
  "location": "West Europe",
  "maximumNumberOfWorkers": 1,
  "name": "myAppServicePlan",
  < JSON data removed for brevity. >
  "targetWorkerSizeId": 0,
  "type": "Microsoft.Web/serverfarms",
  "workerTierName": null
} 

Create a web app

Create a web app in the myAppServicePlan App Service plan.

In the Cloud Shell, you can use the az webapp create command. In the following example, replace <app-name> with a globally unique app name (valid characters are a-z, 0-9, and -). The runtime is set to NODE|6.9. To see all supported runtimes, run az webapp list-runtimes --linux.

# Bash
az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <app-name> --runtime "NODE|6.9" --deployment-local-git
# PowerShell
az --% webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <app-name> --runtime "NODE|6.9" --deployment-local-git

When the web app has been created, the Azure CLI shows output similar to the following example:

Local git is configured with url of 'https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git'
{
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "<app-name>.azurewebsites.net",
  "deploymentLocalGitUrl": "https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git",
  "enabled": true,
  < JSON data removed for brevity. >
}

You’ve created an empty web app, with git deployment enabled.

Note

The URL of the Git remote is shown in the deploymentLocalGitUrl property, with the format https://<username>@<app-name>.scm.azurewebsites.net/<app-name>.git. Save this URL as you need it later.

Configure an environment variable

By default, the MEAN.js project keeps config/env/local-production.js out of the Git repository. So for your Azure app, you use app settings to define your MongoDB connection string.

To set app settings, use the az webapp config appsettings set command in the Cloud Shell.

The following example configures a MONGODB_URI app setting in your Azure app. Replace the <app-name>, <cosmosdb-name>, and <primary-master-key> placeholders.

az webapp config appsettings set --name <app-name> --resource-group myResourceGroup --settings MONGODB_URI="mongodb://<cosmosdb-name>:<primary-master-key>@<cosmosdb-name>.documents.azure.com:10250/mean?ssl=true"

In Node.js code, you access this app setting with process.env.MONGODB_URI, just like you would access any environment variable.

In your local MEAN.js repository, open config/env/production.js (not config/env/local-production.js), which has production-environment specific configuration. The default MEAN.js app is already configured to use the MONGODB_URI environment variable that you created.

db: {
  uri: ... || process.env.MONGODB_URI || ...,
  ...
},

Push to Azure from Git

Back in the local terminal window, add an Azure remote to your local Git repository. Replace <deploymentLocalGitUrl-from-create-step> with the URL of the Git remote that you saved from Create a web app.

git remote add azure <deploymentLocalGitUrl-from-create-step>

Push to the Azure remote to deploy your app with the following command. When prompted for credentials by Git Credential Manager, make sure that you enter the credentials you created in Configure a deployment user, not the credentials you use to sign in to the Azure portal.

git push azure master

This command may take a few minutes to run. While running, it displays information similar to the following example:

Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 489 bytes | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Updating branch 'master'.
remote: Updating submodules.
remote: Preparing deployment for commit id '6c7c716eee'.
remote: Running custom deployment command...
remote: Running deployment command...
remote: Handling node.js deployment.
.
.
.
remote: Deployment successful.
To https://<app-name>.scm.azurewebsites.net/<app-name>.git
 * [new branch]      master -> master

You may notice that the deployment process runs Gulp after npm install. App Service does not run Gulp or Grunt tasks during deployment, so this sample repository has two additional files in its root directory to enable it:

  • .deployment - This file tells App Service to run bash deploy.sh as the custom deployment script.
  • deploy.sh - The custom deployment script. If you review the file, you will see that it runs gulp prod after npm install and bower install.

You can use this approach to add any step to your Git-based deployment. If you restart your Azure app at any point, App Service doesn't rerun these automation tasks. For more information, see Run Grunt/Bower/Gulp.

Browse to the Azure app

Browse to the deployed app using your web browser.

http://<app-name>.azurewebsites.net

Click Sign Up in the top menu and create a dummy user.

If you are successful and the app automatically signs in to the created user, then your MEAN.js app in Azure has connectivity to the Azure Cosmos DB's API for MongoDB.

MEAN.js app running in Azure App Service

Select Admin > Manage Articles to add some articles.

Congratulations! You're running a data-driven Node.js app in Azure App Service on Linux.

Update data model and redeploy

In this step, you change the article data model and publish your change to Azure.

Update the data model

In your local MEAN.js repository, open modules/articles/server/models/article.server.model.js.

In ArticleSchema, add a String type called comment. When you're done, your schema code should look like this:

let ArticleSchema = new Schema({
  ...,
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  comment: {
    type: String,
    default: '',
    trim: true
  }
});

Update the articles code

Update the rest of your articles code to use comment.

There are five files you need to modify: the server controller and the four client views.

Open modules/articles/server/controllers/articles.server.controller.js.

In the update function, add an assignment for article.comment. The following code shows the completed update function:

exports.update = function (req, res) {
  let article = req.article;

  article.title = req.body.title;
  article.content = req.body.content;
  article.comment = req.body.comment;

  ...
};

Open modules/articles/client/views/view-article.client.view.html.

Just above the closing </section> tag, add the following line to display comment along with the rest of the article data:

<p class="lead" ng-bind="vm.article.comment"></p>

Open modules/articles/client/views/list-articles.client.view.html.

Just above the closing </a> tag, add the following line to display comment along with the rest of the article data:

<p class="list-group-item-text" ng-bind="article.comment"></p>

Open modules/articles/client/views/admin/list-articles.client.view.html.

Inside the <div class="list-group"> element and just above the closing </a> tag, add the following line to display comment along with the rest of the article data:

<p class="list-group-item-text" data-ng-bind="article.comment"></p>

Open modules/articles/client/views/admin/form-article.client.view.html.

Find the <div class="form-group"> element that contains the submit button, which looks like this:

<div class="form-group">
  <button type="submit" class="btn btn-default">{{vm.article._id ? 'Update' : 'Create'}}</button>
</div>

Just above this tag, add another <div class="form-group"> element that lets people edit the comment field. Your new element should look like this:

<div class="form-group">
  <label class="control-label" for="comment">Comment</label>
  <textarea name="comment" data-ng-model="vm.article.comment" id="comment" class="form-control" cols="30" rows="10" placeholder="Comment"></textarea>
</div>

Test your changes locally

Save all your changes.

In the local terminal window, test your changes in production mode again.

gulp prod
NODE_ENV=production node server.js

Navigate to http://localhost:8443 in a browser and make sure that you're signed in.

Select Admin > Manage Articles, then add an article by selecting the + button.

You see the new Comment textbox now.

Added comment field to Articles

In the terminal, stop Node.js by typing Ctrl+C.

Publish changes to Azure

Commit your changes in Git, then push the code changes to Azure.

git commit -am "added article comment"
git push azure master

Once the git push is complete, navigate to your Azure app and try out the new functionality.

Model and database changes published to Azure

If you added any articles earlier, you still can see them. Existing data in your Cosmos DB is not lost. Also, your updates to the data schema and leaves your existing data intact.

Stream 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.

Manage your Azure app

Go to the Azure portal to see the app you created.

From the left menu, click App Services, then click the name of your Azure app.

Portal navigation to Azure app

By default, the portal shows your app's Overview page. This page gives you a view of how your app is doing. Here, you can also perform basic management tasks like browse, stop, start, restart, and delete. The tabs on the left side of the page show the different configuration pages you can open.

App Service page in Azure portal

Clean up resources

In the preceding steps, you created Azure resources in a resource group. If you don't expect to need these resources in the future, delete the resource group by running the following command in the Cloud Shell:

az group delete --name myResourceGroup

This command may take a minute to run.

Next steps

What you learned:

  • Create a database using Azure Cosmos DB's API for MongoDB
  • Connect a Node.js app to a database
  • Deploy the app to Azure
  • Update the data model and redeploy the app
  • Stream logs from Azure to your terminal
  • Manage the app in the Azure portal

Advance to the next tutorial to learn how to map a custom DNS name to your app.

Or, check out other resources: