I am trying to setup a reverse proxy with IIS 7.5. I want an incoming request that matches a certain URL pattern to be served by Tomcat. I have used the tutorial here to configure it.
http://www.iis.net/learn/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing
My settings are as below:
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url=".*/(Locations|FacetedSearch|LocationPage)/.*" />
<action type="Rewrite" url="http://search.xxx.com/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" replace="true" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://search.xxx.com/(.*)" />
<action type="Rewrite" value="http{R:1}://dev.xxx.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<tracing>
HTTP Error 500.52 - URL Rewrite Module Error.
Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("deflate").
I just hit this issue as well, and I found this solution helpful: https://www.saotn.org/iis-outbound-rules-with-gzip-compression/
Basically, on inbound requests the HTTP_ACCEPT_ENCODING header gets stashed into a temporary header, and then gets restored back on the outbound rewrite rule.
In the case the link goes dead, here's the steps:
Through the IIS Manager GUI on the server node in the left pane, navigate to URL Rewrite
Click View Server Variables in the right pane
Add two Allowed Server Variables:
HTTP_ACCEPT_ENCODING
HTTP_X_ORIGINAL_ACCEPT_ENCODING
Back in URL Rewrite options for the Server, click on View Preconditions in the right pane. Add a new precondition (I named it NeedsRestoringAcceptEncoding)
Set the Condition Input to {HTTP_X_ORIGINAL_ACCEPT_ENCODING} and the Pattern to ".+" (no quotes).
On the inbound rewrite rule that is causing the error, add the following to Server Variables (you'll find it underneath the Conditions section):
Server Variable Name: HTTP_X_ORIGINAL_ACCEPT_ENCODING
Value: {HTTP_ACCEPT_ENCODING}
Server Variable Name: HTTP_ACCEPT_ENCODING
Value: ""
On the outbound rewrite rule, add the precondition created from steps 4-5 to the Precondition section of the rule (it should be populated in the drop-down box)
In the case that you only need this functionality on a single site, you can add the precondition at the site-level instead of the server-level.
Add this to your web config
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
or disable dynamic compression in iis
find "compress" in IIS,then remove the dynamic content compression and static content compression.
Disabling dynamic and static content compression from the site responsible for reverse proxying the requests AND the site that is being proxied fixed this error for me.
To put it in other words - if server X is routing requests to server Y, then disable dynamic and static content compression on the sites on both server X and Y.
Related
I have an IIS server hosting a few external domains and also an internal web app, also I have a woocommerce site sitting on an apache server. The IIS server sits on a fixed public IP address and the Apache server also on another fixed public IP. All infrastructure is in house. We are shortly giving up out /29 network for a single fixed IP /32 network. I was planning to use ARR and URL rewrite to have both the IIS and Apache server utilize 1 fixed public IP.
I installed ARR on the IIS box and configured the following web.config, note that bost the IIS box and Apache box have valid certificates.
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://192.168.8.100/(.*)" />
<action type="Rewrite" value="http{R:1}://test.example.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
<rules>
<clear />
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{CACHE_URL}" pattern="^(https?)://" />
</conditions>
<action type="Rewrite" url="{C:1}://192.168.8.100/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
192.168.8.100 being the internal server hosting woocommerce on Apache. So what works after this is that https://test.example.com works fine reverse proxied to appache from IIS, test.example.com also works fine. However http://test.example.com fails with ERR_TOO_MANY_REDIRECTS which I can see using fidler.
Things I have tried
Turning off 'Reverse rewrite host in response headers' in ARR, this stops the too many redirects but shows the host as the 192.168.8.100 address and obviously fails the cert, however woocommerce site comes up fine.
Adding a rewrite rule for HTTP to HTTPS to Apache at /etc/apache2/sites-available/wordpress.conf - This made no difference to the too many redirects error.
Adding a redirect rule for HTTP to HTTPS in the .HTACCESS file at /var/www/wordpress/.htaccess - This made no difference to the too many redirects error.
Remove Really Simple SSL plugin from Wordpress - This made no difference to the too many redirects error.
I am now at my wits end as to what to try now.
Answering my own question, and it was a schoolboy error, when I tried the IIS HTTP --> (HTTPS) rewrite, I forgot to move it up ahead of the reverse proxy rule, hence it was never, ever going to execute it. Move it up and all works fine. Doh!
I have an application that is behind a reverse proxy and when the user is trying to log in with a Facebook account, it fails because the redirect uri is an internal uri, instead of the public domain.
To come around this I want to rewrite redirected url.
This is the flow:
User logs in to Facebook
Microsoft.AspNetCore.Authentication.Facebook nuget package takes over the authentication process
A redirection (302) GET request happens to this url:
https://www.facebook.com/v2.6/dialog/oauth?client_id={clientid}&scope=public_profile,email&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A5000%2Fsignin-facebook&state={longstring}
And this is the part that I want to rewrite:
redirect_uri=https%3A%2F%2Flocalhost%3A5000%2Fsignin-facebook to
redirect_uri=https://mypublicdomain.com/signin-facebook
Is this possible with IIS Url rewrite module?
I tried to configure it but couldn't get it to work.
(on the server I'm using ASP.NETCORE 1.1.2)
<outboundRules>
<remove name="Rewrite Location Header" />
<rule name="Rewrite Location Header" preCondition="IsRedirection" enabled="true">
<match serverVariable="RESPONSE_Location" pattern="^https:\/\/(.*&redirect_uri=)([^&]*)(.*)" />
<action type="Rewrite" value="{R:1}https://google.com{R:3}" replace="false" />
</rule>
<preConditions>
<preCondition name="IsRedirection">
<add input="{RESPONSE_STATUS}" pattern="3\d\d" />
</preCondition>
</preConditions>
</outboundRules>
Yes this is possible. Make sure to use the {QUERY_STRING} input to match against and ensure you have Rewrite as the action type.
A similar solution you could use as a starting point can be found here
How to access IIS-configured response headers from a Web API 2 service?
In my IIS configuration there is a pre-configured response header Environment=DEV, which I need to check to figure out which environment settings to use.
When I check headers in my current response via HttpContext.Current.Response.Headers, I'm only seeing Server, and nothing else.
I don't think you should dependent on response headers as they are added to response by IIS at a very later stage in the pipeline and the control is already out of WEB API.
If you have to do this you can go with URL Rewrite + Server Variables. Install URL Rewrite and add a rule in your web.config under system.webServer as below
<rewrite>
<rules>
<rule name="GetEnvironmentInfo">
<match url=".*" />
<serverVariables>
<set name="Environment" value="Dev" />
</serverVariables>
<action type="Rewrite" url="{R:0}" />
</rule>
</rules>
</rewrite>
Also you can add this rule from IIS UI. Now depending upon webAPI configuration you can fetch server variables using below code
string output = string.Empty;
if (Request.Properties.ContainsKey("MS_HttpContext"))
{
output = ((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.ServerVariables["Environment"];
}
else if (Request.Properties.ContainsKey("MS_OwinContext"))
{
var httpContextWrapper = ((OwinContext)Request.Properties["MS_OwinContext"]).Environment["System.Web.HttpContextBase"] as HttpContextWrapper;
output = httpContextWrapper.Request.ServerVariables["Environment"];
}
The above XML can be generated from IIS GUI at server level
1.Install URL Rewrite.
2.Open IIS Manger (Windows Run -> Inetmgr)
3.Select Server in left menu
4.In the central pane double click URL Rewrite. In the Actions pane on the right hand side click Add Rule
5.Set values as below
and the save.
This will add same XML but now at the server level i.e. in C:\Windows\System32\inetsrv\Config\applicationHost.config file
<globalRules>
<rule name="GetEnInfo">
<match url=".*" />
<action type="Rewrite" url="{R:0}" />
<serverVariables>
<set name="Environment" value="dev" />
</serverVariables>
</rule>
</globalRules>
Regarding fetching response headers from IIS there could be a way but I wouldn't recommend it due to the reason mentioned in the beginning of the answer.
Hope this helps.
Boiling this down to the simplest possible rule:
<rule name="Reverse Proxy" stopProcessing="true">
<match url="^external/(.*)" />
<action type="Rewrite" url="http://some-site/{R:1}" />
</rule>
("Enable Proxy" is checked in the ARR Server Proxy settings at the server level).
The above rewrite rule works fine in a very simple test app with a web.config containing the section, it works fine in a web forms app, but if I put the same rule into an MVC3 app (on the same machine, so identical config for IIS higher up) it never has any effect; the request flows through.
if it's just a rewrite (and not a reverse proxy) it works OK, e.g.,
<rule name="rewrite to internal" stopProcessing="true">
<match url="^internal/(.*)" />
<action type="Rewrite" url="different-internal/{R:1}" />
</rule>
...is fine.
I can get the reverse proxy rule to work if I add
routes.IgnoreRoute("external/{*pathInfo}");
in the Global.asax.cs class, so that my request for external/* doesn't hit the default controller, but I don't understand why. I think the URL rewrite module kicks in way before the Routing (see http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/) so I'd expect there not to be a conflict between them.
Is the Routing module adding in "virtual" rewrite rules to the URL rewrite module, that are overriding my declared rewrite rules?
I had this exact same issue and it took me the entire day to find the solution.
Find: the ServoceModel tag in your Web.config file and add the serviceHostingEnvironment code as seen below:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
This will allow routes to be passed through to IIS to handle it.
One more tip, I recommend anyone having routing issues with their MVC projects to install Remote Debugger via NuGet. This will tell you what routes are being activated when.
I have a very simple OutBound UrlRewriter rule that rewrites url's it finds in the body of the http response stream:
<rewrite>
<outboundRules>
<rule name="Scripted"
preCondition="IsHtml"
patternSyntax="ECMAScript"
stopProcessing="false">
<match filterByTags="None" pattern="http://someurl.com" />
<action type="Rewrite" value="http://anotherurl.com" />
</rule>
<preConditions>
<preCondition name="IsHtml" patternSyntax="Wildcard">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
The problem is that as soon as I turn on the preCondition no rewriting takes place.
I need to be able to use a pre-condition because the page is an ASP.NET page and uses ASP.NET script resources e.g. <script src="ScriptResource.axd?d=...." type="text/javascript" />.
By default script resources are gzip compressed and I want to keep them that way. Without the content type precondition the URL rewriter RewriteModule throws a 500.52 error - "Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip")."
Using Fiddler I can see that Content-Type: text/html; charset=utf-8 is being sent in the response header but UrlRwriter seems unable to match this.
Why is this happening?
This is because the Server Variable HTTP_ACCEPT_ENCODING is not added to the allowed server variables list. Add it there (you can google how to in IIS).