Deploy Node.JS App to Azure Web App with continuous deployment using Azure DevOps, ACR & Docker

  • Posted on November 9, 2020
  • Estimated reading time 8 minutes

This article was originally written by Avanade alum Matt Cameron

A definitive guide on deploying your Node.JS API to Azure Web Apps with Continuous Deployment using Azure Container Registry, Docker, and Azure Pipelines.

Do first, understand later. That is the approach here. If you are new to some of these technologies, don’t worry about it. Just follow along, and dive into topics afterward.

In this guide, we will:

  • setup a basic express app and deploy it to GitHub
  • setup an Azure Container Registry (ACR)
  • set up an Azure pipeline that builds and pushes a Docker image to ACR.
  • set up an Azure Web App to host a running version of that image, with continuous deployment.

What you will need:

Create Express API

First let’s create a basic express API. On your local machine type the following commands:

$ mkdir basic-express-api

$ cd basic-express-api

$ npm init -y

$ npm i express dotenv

$ git init

This sets up an NPM project called basic-express-api, provides it with express and dotenv NPM modules, and initializes a git repo

Now open the basic-express-api directory in your favorite editor (I use VS Code), and create a file called index.js and paste in the following code, which is a basic Hello World express API:

const express = require(‘express’);

const app = express();

const port = process.env.PORT || '3000';

app.get(‘/’, (req, res) => {

res.send(‘Your Express API is up and running!’);


app.listen(port, () => {

console.log(`listening at http://localhost:${port}`);



Open the package.json file, and add replace the scripts section with:

“scripts”: {

“start”: “node index.js”


Lastly, create a .gitignore file and add node_modules to it.

Save your files, and from your command line (at the base directory) run npm start. Open localhost:3000 in a browser and confirm that it returns “Your Express API is up and running!”.

Add Dockerfile and .dockerignore file

Create a new file called Dockerfile at your project root, which should contain the following:

FROM node:12

# Create app directory

WORKDIR /usr/src/app

# Install app dependencies

COPY package*.json ./

RUN npm install

# If you are building your code for production

# RUN npm ci --only=production

# Bundle app source

COPY . .


CMD [ "node", "index.js" ]

Next, create a .dockerignore file (don’t forget the “.”), and add the following two lines to it:



Push to GitHub

Head over to GitHub, create a repository called basic-express-api, and then push our existing basic-express-api app to that repository. We will later be connecting our Pipeline to this repository.

Create a Resource Group in Azure

Go to azure portal (portal.azure.com) and create a resource group. Click Review + Create and then Create. This resource group will contain our ACR which we will create in the next step.

azure resource group

You can name your resource group whatever you want. I’m calling mine api-resource-group.

Create an Azure Container Registry (ACR)

ACR is a repository to host Docker images. Think of it as GitHub for Docker images.

  1. Navigate to your newly created Resource Group.
  2. Find and click on the + Add button.
  3. This will open up a long list of resources that you could add to your RG. Search for Container Registry and click create.
  4. Select the basic settings for your ACR, for Registry Name enter “myApiContainerRegistry”, select the standard SKU, and a region close to your location. Click Review + Create, which will bring you to a summary of your new ACR. Then click Create.

azure container registry

For resource group, select the resource group that you created earlier

You now have an ACR in a Resource Group.

Create the Pipeline

Azure DevOps has this thing called Pipelines. They automate things. We will use Azure pipelines to automate the building and pushing of a docker image based on our GitHub code.

azure devops

create a new project called express-api

  • Navigate to Azure DevOps (dev.azure.com).
  • If you don’t already have an organization, create an organization by clicking New organization.
  • Create a new project by clicking + New Project. Create a project called express-api.
  • Select your newly created project (click its card)
  • Go to Pipelines, and select Create Pipeline
  • When the Connect tab appears, select GitHub. It may prompt you to sign in and/or allow DevOps to access your GitHub.
  • When the Select tab appears, select the repository that you created/pushed earlier (I called mine basic-express-api)
  • When the Configure tab appears, click Show More and find the two Docker options. Click the Docker option that says “Build and push an image to Azure Container Registry”. After clicking, you will go through some prompts to find the ACR that you created earlier. The flow will look something like:

azure subscription

this is the general flow of popups and prompts when you

  • Click Validate + configure

select Validate and Configure, which will bring up a new YAML file

  • Review your pipeline YAML. At this point you should see an editable YAML file. These are instructions telling the pipeline what it should do and when it should do it. In the YAML file look for a task called Docker@2, ensure that it has a line for tags: ‘latest’. If it has the tags line, but a different string other than ‘latest’, change it to ‘latest’. If it is missing the tags line altogether, just add it as circled in green below. This ‘latest’ tag is a Docker convention.

docker code

  • Select Save and run
  • In the sidebar popup, change the Commit message if you’d like
  • Select Save and run. This will now take you to a page showing that the Build job is running. Wait for it to succeed until your proceed.

azure pipelines

  • When your pipeline Job Build has finished, two things have happened: 1) it pushed that new YAML file to your git repository and 2) pushed the built image to your Azure Container Registry
  • Verify that the image was pushed to ACR. Navigate to portal.azure.com. Go to resource groups, navigate into the resource group that you created before, and select the ACR that you created earlier (if you are following along it should be called myApiContainerRegistry). In your ACR, navigate to Repositories, and you should see the image that you built from DevOps pipelines! If you don’t see the image, refresh Azure portal. If you still don’t see it, try retracing your steps.

container registry

In the ACR, select the Repositories tab, which should show the image that you built and pushed from the pipeline. Yours will probably be called something different

IMPORTANT step here!!! In your ACR, under Settings, select Access Keys. For the Admin user toggle, make it Enabled. If you forget this step, you will not be able to deploy it to your web app in the following steps.

Create and deploy a web app from a Docker image

Now we will create a web app in Azure, and hook it up with the ACR image that we pushed earlier.

  • Navigate to your resource group
  • select + Add > search for and select Web App
  • Click create

Microsoft web app

  • On the Basics tab of Create Web App, follow the below guideline. If you have Azure credits, Use Basic B1 for your Sku. Otherwise, you can go with Free F1. Remember to select Docker for publishing.

docker container

Web App settings

  • Click Next: Docker >
  • In the Docker tab, use the below settings:

docker container

  • Select Review and create, and then click Create. Wait until Deployment is complete before proceeding.
  • Select Go to resource

Test the deployment

  • On your new Web App’s Overview tab, look for a section that says URL. It will look something like https://.azurewebsites.net. This is where your web app is deployed. Go to the URL by clicking it or copying pasting it in your browser.
  • It may take a while for this page to load initially (up to 5 minutes).
  • If all is well, you should eventually see something like this:

If you get an error:

  • Make sure your index.js code is using process.env.PORT and not just a static port
  • try going back to the web app in the portal and clicking Restart.
  • go to the web apps Deployment Center (Preview) section. See if you can make something out of the error log there.
  • If all else fails, you can reach me on my new Twitter, @MattBitsBytes.

Setting Up Continuous Deployment

Congrats on making it this far. The last step is to set up Continuous Deployment so that when you push to GitHub, your changes are automatically updated on your deployed Web App!

  • Go to your Web App
  • Click Container Settings under Settings in the sidebar
  • Search for Continuous Deployment, and toggle it to On. This creates what Azure calls a Webhook in your ACR. To confirm that the Webhook was created, you can go to your ACR and navigate to Webhooks in the sidebar.
  • Click Save

Test your Continuous Deployment

  • Open up your repo code on your local. Change the text returned in our app’s get method:

    app.get(‘/’, (req, res) => {

    res.send(‘We are finished with this tutorial!’);


  • Stage and commit your changes.

    git add

    git commit -m "updated the response"

  • Remember when we ran the pipeline earlier on? This committed a YAML file to your remote repo. So before you push your commit, do a quick pull to get latest repo code on your local:

    git pull

  • push your changes

    git push

  • This will trigger your pipeline to kick off again. Go back to devops.azure.com > your project > your pipeline and make sure that your push triggered a new run. Wait for the pipeline to show a success.
  • Now go to your web app in Azure, find the URL again, and navigate to the deployed URL in your browser. You should see your updated app! Note it can take up to 5 minutes for the deployment to be reflected.


devops and azure training

After pushing to GitHub, and confirming the pipeline ran successfully, you may need to wait a few minutes before the live URL reflects your changes


I hope this helps you in your journey with Node, DevOps, and Azure. If you learned anything, claps are appreciated!

If you run into any issues, either post below or reach me on Twitter, @MattBitsBytes.

Do now, understand later.

Max L

Many thanks for this informative step by step guide. Definitely helped a bunch for those trying to venture into cloud solutions like me!

March 17, 2021

Techs and Specs Newsletter

Stay up to date with our latest news.

Share this page
Modal window