3

Good Day!

My colleague has a website node.js (next.js), his website works fine when we build and start thru console (npm run build and npm start).

We have hosted it in a Azure VM (Windows Server 2016 IIS, iisnode and urlrewrite installed), we created a pipeline and we are able to get the artifacts (".next" folder when we run the build) and deploy it to IIS however we still need a manual interaction to place the web.config. Below is the web.config

<!-- indicates that the hello.js file is a node.js application 
to be handled by the iisnode module -->

<handlers>
  <add name="iisnode" path="service-worker.js" verb="*" modules="iisnode" />
</handlers>

<!-- use URL rewriting to redirect the entire branch of the URL namespace
to hello.js node.js application; for example, the following URLs will 
all be handled by hello.js:

    http://localhost/node/express/myapp/foo
    http://localhost/node/express/myapp/bar

-->

<rewrite>
  <rules>
    <rule name="AMS" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Rewrite" url="/" />
    </rule>
  </rules>
</rewrite> 

But when we visit the website, it throws an error of 403 that need to supply the default page. (I'm lost here and not able to run his website thru IIS)

Note: His other website works fine (because it has a service-worker.js).

Anyone experience deploying the Next.JS to IIS? Thanks in Advance.

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
Chris
  • 599
  • 7
  • 23

1 Answers1

1

In the /public folder, create the following web.config to accept requests from /a/b/c and rewrite them to / where our NextJs code lives.

<?xml version="1.0"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="NextJs Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />                            
                    </conditions>
                    <action type="Rewrite" url="/" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

Just doing this should allow you to reload a page on a route like /products, but NextJs will render /, ie, the index page, because that's what our rewrite rule told it to deliver.

So, we need to create a body Component that takes a NextRouter as a prop then compare the window's url to the router's url. If they don't match, we need to change our client side route with router.push().

I'm using TypeScript so my body.tsx is

import * as React from 'react';
import { NextRouter } from 'next/router';

export default class Body extends React.Component<{router : NextRouter}>
{    
    componentDidMount()
    {        
        if (window.location.pathname == this.props.router.pathname) return;
        
        this.props.router.push(global.window.location.pathname);        
    }

    render = () => this.props.children;                
}

Then in _app.tsx, we simply need to wrap the main Component in our Body Component.

import { useRouter } from 'next/router'
import Head from 'next/head';
import Body from '../src/components/elements/body';

function MyApp({ Component, pageProps }) {

    const router = useRouter();        
        
    return (
        <>
            <Head>                
                <title>NextJs on IIS</title>
            </Head>

            <Body router={router}>                                
                <Component {...pageProps} />                                
            </Body>
        </>
    )
}

export default MyApp

Run npm run build, and copy the /out folder to your IIS server.

Matt Searles
  • 2,656
  • 2
  • 16
  • 18
  • Hi thanks for your awesome solution but I am having infinite loop page refreshing when `page is not exist or unknown pathname` because it always pushing the pathname even not exist. example: I have two pages "home & about" but I type on the url /xyzxyz then It turned into loop of refreshing page because that page not exist. I can't having solve this problem yet. have you any idea ? – SHUVO MUSA Nov 23 '21 at 10:36