Deploying Next.JS App on Azure App Service
Tags: azureappservice, react, azure
Published: 2020-10-28 23:08:34

---
title: Deploying Next.JS App on Azure App Service
published: true
date: 2020-10-27 07:22:09 UTC
tags: AzureAppService, React, Azure
canonical_url: https://parveensingh.com/next-js-deployment-on-azure-app-service/
---

 ![Deploying Next.JS App on Azure App Service](https://parveensingh.com/content/images/2020/10/Web-1920---1-1.png)

_This is the fifth article in the " **Getting Started with Azure App Service**" Series where I publish in-depth tutorial and walkthrough on using Azure App Service and best practices every week_. _Last week, we talked about how you can [Setup Custom Domain for Azure App](https://parveensingh.com/custom-domain-azure-app-service/) Service._

I've been playing with React and some of it's popular web frameworks for some time to understand the capabilities and features it provides to run modern web applications. I stumbled upon Next.JS after researching and testing a demo application for few days and decided to publish it on Azure App Service to test some of its functionality.

I am not a react developer as you can tell by now if you have read my other blogs, but it was super simple and quick to get started with Next.JS official learn module. It took me only 3-4 hours to create an application that communicates with Cosmos DB to pull data out and display it on the homepage. (More on this in upcoming blogs -Work in Progress 😉 )

Unfortunately, things didn't go as planned and I spent an entire day trying to figure out the issue with the application after it was deployed on App Service. I started receiving an error " **_You do not have permission to view this directory or page_**". It turned out to be a trivial yet complicated issue with some missing files and an undefined Node version on App Service resource. I decided to give an overview and share with you the solution on how you can run your Next.JS application in Azure.

<!--kg-card-begin: markdown-->
# Table of Content

1. [What is Next.JS?](#what-is-nextjs)
2. [What is Azure App Service?](#what-is-azure-app-service)
3. [Let's Talk About the Real Issue!](#lets-talk-about-the-real-issue)
4. [Prepare Your Code for Azure App Service](#prepare-your-code-for-azure-app-service)
  - [Installing NodeJS](#installing-nodejs)
  - [Setting up a Sample Repo](#setting-up-a-sample-repo)
  - [Adding Web.config File](#adding-webconfig-file)
  - [Adding Server.js File](#adding-serverjs-file)
  - [Updating Node Version on App Service](#updating-node-version-on-app-service)
  - [Building the Code Before Deployment](#building-the-code-before-deployment)
5. [Publishing Code Directly to Azure App Service](#publishing-code-directly-to-azure-app-service)
  - [Creating App Service using VS Code](#creating-app-service-using-vs-code)
  - [Deploying Application using VS Code](#deploying-application-using-vs-code)
  - [Deploying Application using Azure DevOps](#deploying-application-using-azure-devops)
6. [Conclusion](#conclusion)

# What is Next.JS?

As per Next.js official website: _Next.js gives you the best developer experience with all the features you need for production: hybrid static & server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed._

If you are here for a solution on the error, I'd assume you already know a little bit or something about Next.JS. If you want to learn Next.js from basics, use this link and get started:

[Create Your First Next.JS Application](https://nextjs.org/learn/basics/create-nextjs-app)

# What is Azure App Service?

Azure App Service is a PaaS offering by Microsoft that hosts your web service for you in a dedicated and secure host with fully automated scaling and monitoring features.

If you need more insights or you are looking to learn more about App Service, please check out my **App Service Series** where I am covering App Service features and exploring new capabilities every week.

[Getting Started With Azure App Service Series](https://parveensingh.com/tag/app-service/)

# Let's Talk About the Real Issue!

I tried to deploy Next.JS code on my Azure App Service which of course didn't go well in the first run. Apparently, everybody is talking about running Next.js as Static Web App using GitHub Repo. Where did Azure DevOps (ADO) go?

I store all my code in ADO, so I needed some way to deploy the code using the ADO Pipeline and release it instead of storing everything in GitHub now. Looking at some GitHub and TechNet blogs under the App Service tag, I couldn't find one single fix that would work all of it.

Here's the very first issue that I encountered once the deployment was completed with out-of-box source code. Expect to see a 5xx error depending on your code and the file setup.

![01-Error01-Permission Issue](https://dev-to-uploads.s3.amazonaws.com/i/sv1wio75fj8g6d0fcmu3.png)
 <figcaption>Error while deploying Next.JS App on Azure</figcaption>

I checked my log streams on app service and saw the following detailed error.

```
Connecting... 2020-10-27T01:02:26 Welcome, you are now connected to
log-streaming service. The default timeout is 2 hours. Change the timeout with
the App Setting SCM_LOGSTREAM_TIMEOUT (in seconds).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "<http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>">
<html xmlns="<http://www.w3.org/1999/xhtml>">
  <head>
    <title>IIS Detailed Error - 403.14 - Forbidden</title>
  </head>
  <body>
    <div id="content">
      <div class="content-container">
        <h3>HTTP Error 403.14 - Forbidden</h3>
        <h4>
          The Web server is configured to not list the contents of this
          directory.
        </h4>
      </div>
      <div class="content-container">
        <fieldset>
          <h4>Most likely causes:</h4>
          <ul>
            <li>
              A default document is not configured for the requested URL, and
              directory browsing is not enabled on the server.
            </li>
          </ul>
        </fieldset>
      </div>
    </div>
  </body>
</html>

```
<figcaption>Server Error from App Diagnostic Logs</figcaption>

As you can tell this is trying to list the content of the web server but the server is not configured. Running NodeJS on IIS required you to have a `web.config` and `server.js` file that can tell the IIS server where to look for files and what port to listen on.

If you encounter any `5xx` error, the issue is likely to be the same but your **PORT** defined in the `server.js` might be incorrect. Follow through the end to fix the issue and make sure you have all the necessary files in your code to deploy the app.

# Prepare Your Code for Azure App Service

Before you start with the setup, make sure the following requirements are met in your environment.

- All the deployments are done in Azure App Service - **Windows OS** Only.
- I won't be covering how NextJS works, rather fix the error that you will face if you deploy the code without including the necessary set of files to Azure App Service.

## Installing NodeJS

The first step toward creating a Next.JS app is to download and install Node.js. Navigate to the official Node website to grab the latest package and install it on your machine.

[Node JS Installation Webpage](https://nodejs.org/en/)

## Setting up a Sample Repo

If you are setting up a new project, you can follow along in creating a brand new project using a starter template. Run the following command in terminal to create a new project from scratch using next.js template. Source Code is also available at [This GitHub Repo](https://github.com/vercel/next-learn-starter/tree/master/learn-starter).

```
PS> npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
PS> cd nextjs-blog
PS> npm run dev

```
<figcaption>Creating Sample Next.JS Project</figcaption>

This sets up the sample code that you will be using to deploy a POC application to validate and fix the permission issue. **_If you were to deploy your code directly to App Service at this point, you'd get the same permission issue that I described in the previous section._**

## Adding Web.config File

As I mentioned earlier, IIS server needs a config file that can run other necessary files to kickstart the deployment for Node application. Make sure `web.config` and `server.js` files are in the **_root of the directory_** for the webserver to trigger them during the deployment.

[GitHub: singhparveen/NextJS-AzureAppService](https://github.com/singhparveen/NextJS-AzureAppService)
<figcaption>GitHub Repo with Working Next.JS App for Azure</figcaption>

I've uploaded the sample project that I'm using at my [GitHub repo](https://github.com/singhparveen/NextJS-AzureAppService) or alternatively you can copy the code below:

```
<?xml version="1.0" encoding="utf-8"?>
<!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express. For more information, visit:

     <https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config>
-->

<configuration>
  <system.webServer>
    <!-- Visit <http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx> for more information on WebSocket support -->
    <webSocket enabled="false" />
    <handlers>
      <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
      <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
    </handlers>
    <rewrite>
      <rules>
        <!-- Do not interfere with requests for node-inspector debugging -->
        <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^server.js\\/debug[\\/]?" />
        </rule>

        <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}"/>
        </rule>

        <!-- All other URLs are mapped to the node.js site entry point -->
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
          </conditions>
          <action type="Rewrite" url="server.js"/>
        </rule>
      </rules>
    </rewrite>

    <!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
    <security>
      <requestFiltering>
        <hiddenSegments>
          <remove segment="bin"/>
        </hiddenSegments>
      </requestFiltering>
    </security>

    <!-- Make sure error responses are left untouched -->
    <httpErrors existingResponse="PassThrough" />

    <!--
      You can control how Node is hosted within IIS using the following options:
        * watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
        * node_env: will be propagated to node as NODE_ENV environment variable
        * debuggingEnabled - controls whether the built-in debugger is enabled

      See <https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config> for a full list of options
    -->
    <iisnode watchedFiles="web.config;*.js"/>
  </system.webServer>
</configuration>

```
<figcaption>Web.Config File Content</figcaption>

## Adding Server.js File

Adding `Server.js` or `App.js` is a crucial step in case of an IIS server. This ensures that the server can handle the incoming requests and you don't end up seeing any 5xx error. Use the same GitHub repo mentioned above to grab the source code for `server.js` file or copy the same code below:

```
const { createServer } = require("http");
#const express = require('express') (Only if you app uses express)
const next = require("next");

const port = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  createServer((req, res) => {
    handle(req, res);
  }).listen(port, (err) => {
    if (err) throw err;
    console.log(`> Ready on <http://localhost>:${port}`);
  });
});

```
<figcaption>Server.JS File Content</figcaption>

## Updating Node Version on App Service

Check your Node version that's running on your local computer where you built the application. Use the following code snippet in your terminal window to confirm the node version installed on your local development environment.

```
PS> node -v
v12.19.0

```
<figcaption>Checking Local Node Version</figcaption>

Before setting a value for your node version on app service, check the supported version that your App Service Server is running by navigation to the following URL while logged in to Azure. Replace the `webappname` with your app service name. If your version isn't listed in the support version list, choose one that is close.

```
https://{ ***webappname*** }.scm.azurewebsites.net/api/diagnostics/runtime

```
<figcaption>Web Address to Check App Service Plan Supported Node Version</figcaption>

Next step is to confirm if your app service is running the same or close to what version you have in dev environment. You will need to navigate to Azure Portal and check " **Configuration**" under your app service overview.

![Deploying Next.JS App on Azure App Service](https://dev-to-uploads.s3.amazonaws.com/i/6v2p43fkid2mm8uantgi.png)
 <figcaption>Adding Default Node Version for App Service</figcaption>

If you don't see any entry for Node version, Create a new application string using the following name `WEBSITE_NODE_DEFAULT_VERSION` with the value of version supported by your app service plan that is close to your development version.

## Building the Code Before Deployment

Before you push your code to the app service, Next.JS application needs to be build beforehand so that it can generate `.next` folder in the root directory after packaging the code.

Open your terminal and run the following command to build your application. This will take a few seconds and your code will be ready for production.

```
PS> npm run build

```
<figcaption>Building Code for Production</figcaption>

Results of build command should look something like this:

```
> learn-starter@0.1.0 build C:\\Users\\UserName\\Documents\\nextjs-sample
> next build

info - Creating an optimized production build  
info - Compiled successfully
info - Collecting page data  
info - Generating static pages (2/2)
info - Finalizing page optimization

Page Size First Load JS
┌ ○ / 7.26 kB 66.3 kB  
└ ○ /404 3.44 kB 62.5 kB  
+ First Load JS shared by all 59.1 kB
  ├ chunks/framework.cb05d5.js 39.9 kB
  ├ chunks/pages/_app.af1b8e.js 1.01 kB
  └ chunks/webpack.e06743.js 751 B

)
○ (Static) automatically rendered as static HTML (uses no initial props)
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)       
   (ISR) incremental static regeneration (uses revalidate in getStaticProps)

```
<figcaption>Sample Output of Build Process</figcaption>
# Publishing Code Directly to Azure App Service

At this point, your code is ready to deploy in Azure. If you already have an app service plan and app service running in your environment, feel free to skip the first step.

If you don't have any app service resource already, You can either create one using Azure Portal or follow the steps on creating one right within the VS Code environment. Make sure you have "**[Azure App Service](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice)**" extension installed already.

### Creating App Service using VS Code

Open your VS Code session and click on the Azure icon from the left panel. Make sure you have opened your project folder in VS Code as shown on the left side of the image below.

Right-click on your target Subscription and choose "**Create New Web App (Advanced)"**

![Deploying Next.JS App on Azure App Service](https://dev-to-uploads.s3.amazonaws.com/i/9htxp2tkaxe3m3r25gk1.png)
 <figcaption>Creating New App Service using VS Code</figcaption>

Fill out the following information as you are prompted.

```
**App Name** : {suggest a globally unique}
**Resource Group** : {Choose or select first option to create a new one}
**OS: Windows**
 **ASP** : {Create new App Service Plan-feel free to choose existing one if you wish to}
**Application Insights:** {Skip for now-feel free to use if you are interested}

```
<figcaption>Information to Complete New App Service Resource Creation</figcaption>
### Deploying Application using VS Code

As the app service creation is finished, you will see a prompt confirming the deployment.

Click **Deploy** to publish your code to Azure.

![Deploying Next.JS App on Azure App Service](https://dev-to-uploads.s3.amazonaws.com/i/bljpx203lfv1n4eee6hv.png)
 <figcaption>Popup to Deploy Code to Newly Created App Service</figcaption>

If you don't see any prompt, simply right click on the app service name and choose **Deploy to Web App**.

![Deploying Next.JS App on Azure App Service](https://dev-to-uploads.s3.amazonaws.com/i/9b1et0unb8q57kqm2wrr.png)
 <figcaption>Manual Deployment to App Service</figcaption>

You will be prompted to choose a folder to deploy, use the folder that contains your source code.

It'll take a minute or two to publish your code and your website will be up and running now.

## Deploying Application using Azure DevOps

If you are using Azure DevOps, I've added an `azure-pipelines.yml` file inside the same GitHub repo that you can use to create a Pipeline in Azure DevOps. You'll need to create a release for your code and target the release to your subscription for a particular app service resource.

Use the following YAML code for your ADO Pipeline or feel free to create a similar one using GUI in ADO.

```
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# <https://docs.microsoft.com/azure/devops/pipelines/languages/javascript>

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: NodeTool@0
  inputs:
    versionSpec: '10.x'
  displayName: 'Install Node.js'

- script: |
    npm install
    npm run build
  displayName: 'npm install and build'
- task: ArchiveFiles@1
  displayName: 'Archive files '
  inputs:
    rootFolder: '$(System.DefaultWorkingDirectory)'
    includeRootFolder: false

- task: CopyFiles@2
  displayName: 'Copy File to: $(TargetFolder)'
  inputs:
    SourceFolder: '$(Build.ArtifactStagingDirectory)'
    Contents: '$(Build.BuildId).zip'
    TargetFolder: '$(Build.ArtifactStagingDirectory)\\ArtifactsToBePublished'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: SampleApp'
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)\\ArtifactsToBePublished'

```
<figcaption>azure-pipelines.yml file sample</figcaption>
# Conclusion

I hope you learn something new and also gained exposure to a web framework that I'm in love with now even though I started using it only a few days ago. I'd suggest making sure you include `web.config` and `server.js` files with correct information so that the App Service Plan can interpret and execute the startup for your application.

Please leave a comment below or follow me on Twitter to stay abreast of the latest updates.

* * *

**_If it's your first time here, please check out other articles in the series:_**

Part 1: [Up and Running with Azure App Service](https://parveensingh.com/up-and-running-with-azure-app-service/)

Part 2: [Continuous Deployment for Azure App Service](https://parveensingh.com/azure-app-service-continuous-integration-github-azure-repos/)

Part 3: [Using Deployment Slots with Azure App Service](https://parveensingh.com/using-deployment-slots-with-azure-app-service/)

Part 4: [Setup Custom Domain for Azure App Service](https://parveensingh.com/custom-domain-azure-app-service/)

**Part 5:** [**Deploying Next.JS App on Azure App Service**](https://parveensingh.com/next-js-deployment-on-azure-app-service)

* * *