React Router + iis? How to enable routing

The key to getting React-Router to work with IIS is to setup URL Rewrite rules. After looking at how some others have setup AngularJS SPA apps with IIS, I have come up with the following solution.

Download and install URL Rewrite on your server (development and production)

Setup rule to catch any url routes that ARE NOT files and ARE NOT directories. Optionally, you can negate any actual directories that you want serve regularly. More info can be found here on Microsoft's Documentation

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
  <rewrite>
    <rules>
      <rule name="ReactRouter Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          <add input="{REQUEST_URI}" pattern="^/(docs)" negate="true" />
        </conditions>
        <action type="Rewrite" url="index.html" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>
</configuration>

In your base html page (index.html) add a tag with a href attribute to your app.

<base href='/path/to/my/app'/>

To expand a little bit you do need the URL rewrite package as Mohit explained but you don't need to write your own web.config file, you can do it straight from IIS Manager if you want.

Once you have URL Rewrite installed, you may have to reboot or restart IIS, you should see it on the dashboard for the sites. I do it at the site level and not the server level.

In there you are going to add a rule. It must Match the pattern for the request URL using regular expressions with the pattern .* This will match all urls sent by the browser.

In the conditions you will need two conditions that must Match All. There are two inputs you need:

  • {REQUEST_FILENAME} is Not a File
  • {REQUEST_FILENAME} is NOT a Directory

No pattern is needed on these.

Finally in the Action section you need to Rewrite with the rewrite url to be / appending the query string. This will keep everything being sent to react-router and not absorbed by the server.

At this point you might want to stop processing more rules unless you have other unrelated business logic that also needs to run.

This will configure IIS to send all requests to the root of the site which should be one of the default documents as setup in IIS, most likely index.html. From there React-router will pick it up.


Some remarks to Mohit Tilwani answer

say your url is http://localhost/mySubDir

  1. in web.config add rules to prevent rewrite of js, css files:
 <system.webServer>
  <rewrite>
        <rules>
          <rule name="ReactRouter Routes" stopProcessing="true">
            <match url=".*" />
            <conditions logicalGrouping="MatchAll">
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              <add input="{REQUEST_URI}" pattern="^/(docs)" negate="true" />
              <add input="{URL}" negate="true" pattern="\.js$" />
              <add input="{URL}" negate="true" pattern="\.css$" />
            </conditions>
            <action type="Rewrite" url="index.html" />
          </rule>
        </rules>
      </rewrite>
 </system.webServer>
  1. in index.html
<base href="%PUBLIC_URL%/" /> 
  1. in package.json add the line:
 "homepage": "http://localhost/mySubDir",
  1. in index.js you add the subDir part
const baseUrl = '/mySubDir/';
const rootElement = document.getElementById('root');
ReactDOM.render(
        <BrowserRouter basename={baseUrl}>
            <App />        
        </BrowserRouter>
        </ThemeProvider>
        </Suspense>
    </StoreContext.Provider>
    ,
    rootElement);