Socket.io + IIS 10 + reverse proxy setup - iis

The goal is to host a socket.io server on the same port and domain as my website, hosted on IIS 10 using a reverse proxy. And Ideally configure SSL in IIS rather than the socket.io app.
From what I read, this can be achieved using a reverse proxy URL rewrite rule.
However my javascript client application is showing this error:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'serve://dist' is therefore not allowed access. The response had HTTP status code 502.
I have setup a reverse proxy URL rewrite rule to match (regex) the URL socket\.io\/(.*) and rewrite it to localhost:8001/{R:0}
My web.config contains this:
<rewrite>
<rules>
<clear />
<rule name="ReverseProxyInboundRule1" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="socket\.io\/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="localhost:8001/{R:0}" />
</rule>
</rules>
</rewrite>
I don't see anywhere where you can differentiate between http:// and ws://.
I honestly don't have a clue what I'm doing. A lot of the stuff I read online is outdated and really not very helpful.
Any help would be appreciated?

Related

IIS Reverse proxy/Global URL Rewrite for "/api/" folder for all sites

I would like to reverse proxy any requests to an IIS instance for any sites where the request is in the '/api/' folder. I set up a server farm and have the reverse proxy working for everything using the '*' wildcard, but when I want to limit the scope to a RegEx it will not rewrite/proxy to the backend server. The steps I took at the IIS INSTANCE level:
Set up a web farm - only one server in it, machine2
Set up a rewrite for '*'
Tested against 'http://machine1/site1/api/api1' - it was successfully routed to machine2/site1/api/api1
Changed inbound rule from Wildcard to Regular Expressions
Changed Pattern to '.(/./api/.*)' (without the single quotes)
Tested against 'http://sarjhennew10vm/site1/api/api1'
Request was not routed to machine 2.
Below is a snippet from my applicationHost.config [the root of IIS].
<rewrite>
<globalRules>
<rule name="ARR_Farm1_loadbalance" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*(\/.*\/api\/.*)" />
<action type="Rewrite" url="http://Farm1/{R:1}" />
</rule>
</globalRules>
</rewrite>
<proxy enabled="true" />
Is it possible to to a global URL re-write to the server farm for any site on the instance for specific folders?
Edit: It was answered below - I am including a picture in case others run into this. The test pattern isn't clear to me - and counters documentation found here.
Your pattern is incorrect, you can try below code, and change the rewrite url to https://Farm1/{R: 0}
<rule name="ARR_Farm1_loadbalance" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*(\/api\/.*)" />
<action type="Rewrite" url="https://Farm1/{R:0}" />
</rule>

IIS Url Rewrite overwriting external urls

On my development machine, I am trying to configure IIS as a reverse proxy to forward requests coming in port 443 to a nodejs application running locally.
The requests are getting forwarded fine, but sometimes the the nodejs application tries to redirect the browser to an external site and the IIS url rewrite module change that also to point to the local server.
I am accessing the site using https://localhost/test
IIS reroutes the requests to the node app http://localhost:14819/test
The node app returns an http 302 with location header set to https://example.com/someroute
IIS transforms this to https://localhost/someroute
I want the external urls to be untouched by IIS. How to do this?
Here is my Web.config content
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="ReverseProxyInboundRule1" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^test(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^localhost" />
</conditions>
<action type="Rewrite" url="http://localhost:14819/test{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
If you have any redirect coming back from the backend proxy and you do
not want to redirect the Location header coming ,You can do that by
unchecking "Reverse rewritehost in response headers" in Application
Request Routing
Select the server node in IIS manager
Go to Application Request routing Cache
Click on Server proxy Settings
UnCheck "Reverse rewritehost in response headers"

URLRewrite "Redirect" rule works, but "Rewrite" rule fails (404)

I have following rewrite rule:
<rule name="First Rule" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^Tracking/(.*)" ignoreCase="true" />
<action type="Rewrite" url="http://www.example.com/" />
</rule>
This failes, calling http://www.myserver.com/Tracking/123 returns a 404.
However, if I change the action type into Redirect, the rule suddenly works fine, performing a redirect:
<rule name="First Rule" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^Tracking/(.*)" ignoreCase="true" />
<action type="Redirect" url="http://www.example.com/" />
</rule>
But I need a rewrite rule, as I need a reverse proxy to an internal server.
I'm working on a Windows 2008R2 Server (IIS 7.5), have "IIS URL Rewrite Module 2" installed,...
What is wrong with the Rewrite rule ?
Since you mentioned that you're setting up a reverse proxy to an internal server. If a URL Rewrite destination is outside of the server performing the rewrite, you will need to install Application Request Routing to enable proxy capabilities. After installing Application Request Routing (ARR), you'll need to go to its proxy settings and check the Enable Proxy feature. A full blog on this setup can be found here. If this has already been performed, I would recommend using Failed Request Tracing on both the reverse proxy and destination server (if the destination server is IIS) in order to better understand where the HTTP 404 response is coming from.

IIS ARR Proxy WebSockets over HTTP

I have a reverse proxy in our DMZ that translates wss requests into https (at least from what I can see in the IIS logs). That is, JavaScript makes a websocket request to
wss://cname.domain.com
And the reverse proxy sends it to
https://theserver.local
IIS is running on "theserver" and has an https binding. ARR is installed and has the following rewrite rules configured:
<rule name="Rewrite ssl to non-ssl" stopProcessing="true">
<condition logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{CACHE_URL}" pattern="^(.+):// />
</condition>
<match url="the_app/(.*)" />
<action type="Rewrite" url="{MapProtocol:{C:1}}://theserver.local:8080/{R:1}" />
</rule>
<rewriteMap name="MapProtocol">
<add key="https" value="http" />
<add key="wss" value="ws" />
<rewriteMap>
This should route https and wss incoming requests to the path /the_app to http://theserver:8080/{path_and_query_string} and ws://theserver:8080/{path_and_query_string} respectively.
I also have the following rewrite set up (with the highest priority) to handle these wss requests that come in over https (since I can tell which they are based on the path):
<rule name="Rewrite https to ws" stopProcessing="true">
<match url="the_app/websockets/(%7B.+%7D)" />
<action type="Rewrite" url="ws://theserver:8080/websockets/{R:1}" />
</rule>
the rewrites works perfectly...however IIS throws a 502.2 error trying to route the websockets request from https to ws (Invalid Gateway). I have turned on failed request tracing and can't seem to find any more relevant information.
Can this be made to work?
You need to remove the "Rewrite https to ws" rule that changes the protocol to ws:. At the HTTP level, all Websocket calls start out life as an HTTP CONNECT request with an Upgrade header. You simply need to rewrite this request so that it is forwarded to the correct server as an HTTP request, which you are already doing in your "Rewrite ssl to non-ssl" rule.

IIS Reverse Proxy Re-Encoding URLs Containing Percent Sign (%)

I am trying to set up a reverse proxy for Jenkins using IIS 7.5, Application Request Routing 3.0 (ARR), and URL Rewrite 2.0.
I have the proxy mostly working, but am running into issues with URLs that contain the percent symbol (%).
No matter what I try, the proxy insists on either de-encoding or re-encoding the percent sign in the rewritten URL.
This is how I want the URLs rewritten:
http://my.proxy/a%2Fb -> http://my.host:8080/a%2Fb
This is how the URLs are actually being rewritten:
http://my.proxy/a%2Fb -> http://my.host:8080/a/b
- or -
http://my.proxy/a%2Fb -> http://my.host:8080/a%252Fb
How can I get IIS\ARR\Rewrite to stop re-encoding my rewritten URLs?
Things I've tried:
A normal reverse-proxy (rewrites the URL as http://my.host:8080/a/b):
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" ignoreCase="true" />
<action type="Rewrite" url="http://my.host:8080/{R:1}" />
</rule>
Using the UNENCODED_URL server variable (rewrites the URL as http://my.host:8080/a%252Fb):
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{UNENCODED_URL}" pattern="/(.*)" />
</conditions>
<action type="Rewrite" url="http://my.host:8080/{C:1}" />
</rule>
Just entering the URL in straight (as a test - also rewrites the URL as http://my.host:8080/a%252Fb):
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<action type="Rewrite" url="http://my.host:8080/a%2Fb" />
</rule>
All the ideas in Scott Hanselman's excellent "Experiments in Wackiness: Allowing percents, angle-brackets, and other naughty things in the ASP.NET/IIS Request URL"
<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="*,:,&,\" relaxedUrlToFileSystemMapping="true" />
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>'
Note: I ran into this behavior when my IIS reverse proxy ran afoul of Jenkins' built-in reverse proxy checking system which attempts to do an HTTP redirect to a URL of this form.
Joseph, that is a great summary of all the ways I've tried to resolve the exact same issue, having IIS with SSL routing traffic to my Gerrit instance. When I found your post I hoped that maybe someone figured out a magic way to configure it but I guess it's not possible. I have tried one more thing, I've written a custom rewrite provider for IIS so that I can undecode the percent signs before routing is done, but then I realized that the encoding takes place later and this is pointless (I forgot about your step nr 3 that shows it very good).
I couldn't however get rid of IIS like out did, so I have figured a workaround. I have implemented a simple service that acts as additional proxy between IIS and Gerrit. When you configure IIS like in step 2, requests that are forwarded will get %25 in place of percent characters in the urls. Instead of reaching Gerrit, IIS forwards the requests to the proxy service. The service changes all occurrences of %25 to % (decodes percents) and forwards it to Gerrit. Nothing needs to be done with the response. For those who want to go this way you can start from my simple implementation of the proxy in C#:
https://gist.github.com/gralin/b5edfd908a41fc7268a7757698af1e66
I was able to fix this issue using the second approach and setting useOriginalURLEncoding="false":
<rules useOriginalURLEncoding="false">
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{UNENCODED_URL}" pattern="/(.*)" />
</conditions>
<action type="Rewrite" url="http://my.host:8080/{C:1}" />
</rule>
</rules>
See also the official blog post for background information. The wording of useOriginalURLEncoding is a bit unfortunate.
I have thought using proxy with url contains % symbol has the problem, but after that i have found out it wasn't. The issue that the proxy URL too long.
I use datatable with option server-side: true and type: GET. Then when loading content from server with the proxy url too long, there is a problem. I have improve the size of url request and the issue has been fixed.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxQueryString="4000" maxUrl="2000" />
</requestFiltering>
</security>
<rewrite>...</rewrite>
...
</system.webServer>
But keep in mind that allowing long query string and url is a security risk, more over, it’s a bad design.

Resources