Deploy Next.js app on IIS

試作紀錄。on 2022-07-21。

前言

使用Next.js框架開發React是非常易用的,且全系統都是JavaScript/TypeScript少了語言轉換的煩噪。

比較大的問題在部署。若是部署到Linux 平台就簡單多了,搭配PM2工具就行了。若是部署到Widows就要繞一大圈,官網沒有直接直達的方案,且不同時期的版本部版指令也可能不同,只能靠善心大佬協助補充了。研究了數天總結如下:

將 Next.js app 部署在 Linux

若是部署到 Linux 平台就簡單多了,搭配PM2工具就行了。

將 Next.js app 部署成 Windows Service

  • 使用qckwinsvc,成功。這套已不再維護然仍有作用。

  • 使用qckwinsvc2,失敗。部署有成功訊息卻沒有作用。(補充:還有這套qckwinsvc2_updated,應為改良版尚未測試留存參考。)

  • 使用node_windows,失敗。這是設計來部署Node.js Server 的。不過部署 Next.js app 轉換出來的 Node.js Server 卻不行。

  • 綜合結論:不建議這方式。

將 Next.js app 部署到 IIS server

如下面影片有完整流程:

deploy next js on iis web server

其它參考文件

開發環境

  • Visual Studio Code

  • Node.js平台 v16.14.0

  • next v12.1.6

  • react v17.0.2

關鍵步驟紀錄

一、建立的Next.js app。

二、轉換成Node.js Server。

Next.js app若要部署到windows,第一個步驟一定是轉換成 Node.js Server。此步驟將增加server.js檔案,這是 Node.js Server 執行的進入點。

Server.js 源碼紀錄

直接抄用即可,指令中指定啟動自sever.js,port number 預設3000。

server.js
// server.js
// ref→[Custom Server](https://nextjs.org/docs/advanced-features/custom-server)
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const port = process.env.PORT || 3000

// when using middleware `hostname` and `port` must be provided below
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  createServer(async (req, res) => {
    try {
      // Be sure to pass `true` as the second argument to `url.parse`.
      // This tells it to parse the query portion of the URL.
      const parsedUrl = parse(req.url, true)
      const { pathname, query } = parsedUrl

      if (pathname === '/a') {
        await app.render(req, res, '/a', query)
      } else if (pathname === '/b') {
        await app.render(req, res, '/b', query)
      } else {
        await handle(req, res, parsedUrl)
      }
    } catch (err) {
      console.error('Error occurred handling', req.url, err)
      res.statusCode = 500
      res.end('internal server error')
    }
  }).listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

package.json 源碼紀錄

並調整 npm run start 指令 script 從 next start 改成 node server.js。

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "node server.js",  //改用 node.js 平台執行
    //"start": "next start",    //預設用 next.js 平台執行   
    //// 下面指定port number
    //"start": "next start -p 8080", 
    //"start": "cross-env NODE_ENV=production PORT=8080 node server.js",
    //// windows 環境下語法
    //"start": "set NODE_ENV=production && set PORT=8080 && node server.js",
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    "cross-env": "^7.0.3",  // 建議安裝此工具模組,讓環境參數設定指令可跨平台。
    ...
  }
}

三、準備IIS環境

在 IIS Server 執行 node.js app 需安裝

(1) 安裝 URL Rewrite

(2) 安裝 Node.js 平台

(3) 安裝 iisnode

這個比較麻煩,不同時期版本可能不用。本期安裝位置:

Installing for IIS 7.x/8.x

  • Install iisnode for IIS 7.x/8.x: x86 or x64 - choose bitness matching your system

Hosting node.js applications in IIS on Windows

四、編寫 web.config

參考自這裡,只是多一行<add segment="node_modules"/>

此段直接抄用即可。

web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
參考自:[Next.js Server Azure Site Extension](https://github.com/MRCollective/nextjs-server-azuresiteextension)
-->
<!--
     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>
      <!-- 設定處理常式對應:引用 iisnode 模組處理 server.js。 -->
      <!-- 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>
      <!-- 設定 URL 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"/> -->
          <add segment="node_modules"/>
        </hiddenSegments>
      </requestFiltering>
    </security>

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

    <!--
      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>

五、設定 IIS 網站。

這段沒有特別之處,一樣指定網站實體位置、port等即可。順利的話就能成功啟動了。

EOF

Last updated