node.jsiisurl-rewritingreverse-proxyrocket.chat

IIS Reverse proxy get 404 from NodeJS behind it


I know there are many articles about reverse proxy, there are many thing about InBound and OutBound but I would like to know what wrong I have done.

I have NodeJs server which is available on http://192.168.0.1:3000 When I create reverse proxy by Server Farms like below

Pattern : *
Action Type: Route To Server Farm
Scheme: http , Server Farm: FarmName, Path: {R:0}
when I browse http://localhost everything works like a charm , but problem is based on sub domain or sub folder request.

I want proxy http://localhost/site/sub1 to http://192.168.0.1:3000 I established InBound and OutBound rules like below:

<rewrite>
  <globalRules>
    <rule name="ARR_testd_loadbalance" enabled="true" stopProcessing="true">
      <match url="^site/sub1(.*)" />
      <action type="Rewrite" url="http://192.168.0.1:3000/{R:1}" />
      <serverVariables>
        <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
        <set name="HTTP_ACCEPT_ENCODING" value="" />
      </serverVariables>
    </rule>
    <rule name="query" stopProcessing="true">
      <match url="^sockjs/(.*)" />
      <action type="Rewrite" url="http://192.168.0.1:3000/sockjs/{R:1}" />
    </rule>
  </globalRules>
  <outboundRules>
    <rule name="RewriteAbsoluteUrlsInResponse" preCondition="ResponseIsHtml1">
      <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://192.168.0.1(\:3000)?/(.*)" />
      <action type="Rewrite" value="/site/sub1/{R:3}" />
    </rule> 
    <rule name="RewriteRelativePaths" preCondition="ResponseIsHtml1">
      <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^/(.*)" negate="false" />
      <action type="Rewrite" value="/site/sub1/{R:1}" />
    </rule>
    <rule name="Restore-AcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
      <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)"></match>
      <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}"></action>
    </rule>
    <preConditions>
      <preCondition name="NeedsRestoringAcceptEncoding">
        <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
      </preCondition>
      <preCondition name="ResponseIsHtml1">
        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/(.+)" />
      </preCondition>
    </preConditions>
  </outboundRules>
</rewrite>

based on above rules I still see the error from NodeJs server as: When page get loaded from NodeJS it shows me the 404 error like:

Error:404
Oops, page not found
Sorry, page you requested does not exists or was deleted!

and in private Rocket server I can see

[34mI20190129-17:17:04.122(3.5) rocketchat:logger server.js:199 [34mMeteor ➔ method public-settings/get -> userId: null , arguments: [] [34mI20190129-17:17:04.125(3.5) meteor_autoupdate_clientVersions { id: 'TFhMadFtuynon7rHB', clientAddress: '192.168.0.201', httpHeaders: { referer: 'http://localhost/site/sub1', 'x-forwarded-for': '[::1]:3704,192.168.0.201', 'x-forwarded-host': '192.168.0.9:3000', 'x-forwarded-port': '3000', 'x-forwarded-proto': 'http', host: '192.168.0.9:3000', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.116', 'accept-language': 'en-US,en;q=0.9' }, userId: null }

and if RewriteAbsoluteUrlsInResponse and RewriteRelativePaths are working why I am getting the 404 error from NodeJS?


Solution

  • I don't know why it doesn't work really, When I enabled Reverse proxy on any address * wildcard everything work nice, I think there is something happened in ARR module which is violated when I want reverse works on site/sub1, after many tries like checking network packets by Wireshark on private server to find failed http requests, defining outbounds and inbounds rules and etc, it doesn't work still.

    I have to implement a workaround to do above scenario:

    Making two website on different ports 80 and 81 located to:
    C:\inetpub\wwwroot and C:\inetpub\wwwroot1 the first one is main website which is browsing by http://localhost/site and the second one is accessible by http://localhost:81/reversesite at the end defining a reverse rule in web.config of C:\inetpub\wwwroot1 (reversesite) like below:

    <rewrite>
      <rules>
        <rule name="ReverseProxyInboundRule1" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="http://192.168.0.1:3000/{R:1}" />
        </rule>
      </rules>
    </rewrite>
    

    by browsing http://localhost:81 it will proxied to http://192.168.0.1:3000 and there are no any 404 error.

    anyway in http://localhost/site I can call any api or address from http://192.168.0.1:3000 by http://localhost:81 but when I was trying to do reverse on http://localhost/site/sub1 it didn't work as described in question.