9

I am trying to deploy my NEXTJS app to azure. I created a webapplication with a linux OS containing Node installed. my package.json looks like this.

{
  "name": "frontend",
  "version": "1.0.0",
  "description": "This package contains all necessary depenencies for frontned",
  "main": "index.js",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start -p $PORT",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "masnad",
  "license": "ISC",
  "dependencies": {
    "@zeit/next-css": "^1.0.1",
    "next": "^8.0.3",
    "react": "^16.8.3",
    "react-dom": "^16.8.3"
  }
}

I first created an empty webapp and then used deployment service kudu where I pushed my codes from local to azure.

The git log when pushing to azure looks like this

remote: ..............................................................
remote: npm WARN rollback Rolling back fsevents@1.2.7 failed (this is probably harmless): ENOTEMPTY: directory not empty, rmdir '/home/site/wwwroot/node_modules/fsevents/node_modules/abbrev'
remote: npm WARN rollback Rolling back rc@1.2.8 failed (this is probably harmless): ENOTEMPTY: directory not empty, rmdir '/home/site/wwwroot/node_modules/fsevents/node_modules/rc/node_modules/minimist'
remote:
remote: > ax-frontend@1.0.0 postinstall /home/site/wwwroot
remote: > next build
remote:
remote: ...............
remote: Creating an optimized production build ...
remote:
remote: ...
remote: Compiled successfully.
remote:
remote:  ┌ /
remote:  ├ /_app
remote:  ├ /_document
remote:  └ /_error
remote:
remote: npm WARN unistore@3.2.1 requires a peer of preact@* but none is installed. You must install peer dependencies yourself.
remote: audited 6645 packages in 139.904s
remote: found 0 vulnerabilities
remote: npm WARN ax-frontend@1.0.0 No repository field.
remote:
remote: npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.7 (node_modules/fsevents):
remote: npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.7: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
remote:
remote:
remote: > ax-frontend@1.0.0 build /home/site/wwwroot
remote: > next build
remote:
remote: .........
remote: Creating an optimized production build ...
remote:
remote: ...
remote: Compiled successfully.
remote:
remote:  ┌ /
remote:  ├ /_app
remote:  ├ /_document
remote:  └ /_error
remote:
remote:
remote: Done.
remote: Running post deployment command(s)...
remote: Deployment successful.
remote: App container will begin restart within 10 seconds.
To https://node-ax-dev.scm.azurewebsites.net:443/node-ax-dev.git
   ec4d5ad..dcadc02  development -> master

So I am guessing that it got deployed well. I went to the https://node-ax-dev-1212.azurewebsites.net but nothing happened.

So I SSH'd inside the instance and then ran npm run dev and it instantly showed me that project running on localhost:3000.

SO I wrote https://node-ax-dev-1212.azurewebsites.net:3000 and yet it did not work as it tells in the terminal that the port is in use already and shuts down.

I am not sure what is wrong but It feels like I did most of the procedure correctly.

I did not add any specific env variables so everything is just plain new. MY directory looks like this.

enter image description here

P.S I also tried to add in the application settings runtime a start up file command npm run dev but I don't think it works.

mr aurora
  • 169
  • 1
  • 2
  • 11

4 Answers4

11

As on today(30-Oct-2021), you do not need a web.config file in Azure Linux webapp, which doesn't run on IIS. All you need is a command to start the web app from code on Linux web app with Node JS environment.

For your application, I would suggest to not use the custom port until unless it is required. In your package.json remove the port specification with next start command, that should solve the issue with the following suggested approach.

{
  "name": "frontend",
  ...
  "scripts": {
    ...
    "start": "next start",
    ...
  },
  ...
}

Azure Linux web app service (container) uses by default port 8080 and maps it to external http/https (80/443) port.

As per Microsoft documentation for deploying Node JS / Next JS application on Azure Linux web app, the recommended way is to use PM2 rather than using npm start (or) node server.js.

It is far easier to use PM2 than writing your own server.js, as PM2 is already available by default with NodeJS runtimes in azure web apps. Also PM2 provides a full-service app management platform.

To use it, just add ecosystem.config.js file to your Next JS app with following code.

module.exports = {
  apps: [
    {
      name: "my-nextJs-site",
      script: "./node_modules/next/dist/bin/next",
      args: "start -p " + (process.env.PORT || 3000),
      watch: false,
      autorestart: true,
    },
  ],
};

As per Microsoft documentation mentioned above, the deployed code will automatically start with PM2 as soon as it finds ecosystem.config.js file after deployment.

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
(or) One of the following PM2 files: process.json or ecosystem.config.js

Note: In case the the app doesn't start automatically even after this, you can start it manually with the following PM2 command as a startup command in azure webapp settings.

pm2 --no-daemon start /home/site/wwwroot/ecosystem.config.js
Ravikumar B
  • 779
  • 1
  • 14
  • 25
  • does this also apply to Azure Windows App service? Can we launch the app without `server.js` in a Windows Service? – Gangula Dec 22 '21 at 06:23
  • As per this https://stackoverflow.com/questions/66871045/pm2-not-found-on-azure-app-service-with-node-14-runtime/66880978 , windows web app will also have pm2 installed. You can give it a try, this might work. – Ravikumar B Dec 22 '21 at 08:48
  • 1
    another reason this is the ideal approach is using `node server.js` made my app really slow in production. But [`next start` helped solve this issue](https://stackoverflow.com/a/69354574/6908282). Thank you @Ravikumar – Gangula Dec 22 '21 at 09:30
  • Please do up vote the answer if it helps you. – Ravikumar B Dec 22 '21 at 09:38
  • `pm2` is not available in Azure Windows Service - [it uses IIS Server](https://github.com/Unitech/pm2/issues/4822). Check out the [following answer](https://stackoverflow.com/a/63098601/6908282) and its linked questions. – Gangula Feb 08 '22 at 04:23
  • For this solution, do we need to set WEBSITES_PORT in Azure configuration, and if so, to what value? – Andrew Gee Mar 15 '22 at 21:54
  • You don't need to set port number, it can work with default value. – Ravikumar B Mar 17 '22 at 16:55
  • any particular reason you have "--no-daemon"? Is that for testing purposes to see console output? – Ryan Pfister Jun 02 '23 at 15:41
  • @RyanPfister Please refer the note section in above mentioned Microsoft documentation link for information about `--no-deamon`. As per documentation `PM2 needs to run in the foreground for the container to work properly.` – Ravikumar B Jun 22 '23 at 13:53
7

Azure needs a web.config file and also a server.js/index.js as a starting point else it won't be able to start.

I recommend changing your folder structure. See the example below https://github.com/zeit/next.js/tree/master/examples/custom-server

Create the server.js file and copy the information from the above mentioned github repo. In the package.json file replace the dev build and start to

"dev": "node server.js",
"build": "next build",
"start": "node server.js"

Now you can just use node server.js to run your code.

While uploading it to azure, in your root directory create a file call web.config and add 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> 

After you have added and made changes to your routes depending on how you need by tweaking the server.js file.

Push it to azure, and your app will start running as azure will now run node server.js and will know where to find it. And also the web.config file will rewrite the URL so you don't have to add yoururl.azure.net:3000 you can just simply type in the URL and it will work.

Masnad Nihit
  • 1,986
  • 2
  • 21
  • 40
  • 1
    if anybody has different issue regarding nextjs deploying on Azure App service, please go through https://www.youtube.com/watch?v=Ut8KYyCOqpA – venkat Jul 02 '19 at 05:12
  • Would you be able to answer my question: https://stackoverflow.com/questions/59661715/is-the-web-config-file-required-for-a-node-next-react-app-running-on-azure-app-s – ddon-90 Jan 27 '20 at 12:08
3

I was able to get Next.js to run on Azure Appservices by making the following changes to my app. Make the following changes to your Express app and your package.json file.

// server.js

const express = require('express')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

// Your app will get the Azure port from the process.enc.PORT
const port = process.env.PORT || 3000;

app
  .prepare()
  .then(() => {
     const server = express()

     server.get('*', (req, res) => {
         return handle(req, res)
     })

     server.listen(port, err => {
        if (err) throw err
            console.log('> Ready on http://localhost:3000')
        })
     })
     .catch(ex => {
         console.error(ex.stack)
         process.exit(1)
     })

In you package.json file, you will need to make sure that you have scripts for postinstall and start. In the start you can add a port variable like the following.

"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start -p $PORT",
  "postinstall": "next build"
}

I have a blog post on how to fix at Running Next.js on Azure App Services

Gangula
  • 5,193
  • 4
  • 30
  • 59
David Fekke
  • 399
  • 2
  • 5
  • 13
0

Please do not use PM2 in azure app service in case when you are facing some problem with the next js Routing. In startup command we can use "npx install serve -g && serve " in my case my next js files were in out folder so used: "npx install serve -g && serve ./out"

Let me know if you still facing any problem.

  • When I use this, I get an index of the my server like this: https://i.stack.imgur.com/cUHrX.png. If I don't use serve, my nextjs routes dont work. Can you share a code sample or a minimum working repo please? – Yigit Alparslan May 13 '22 at 21:45