Setting up a reverse proxy in Azure App Service to point requests from subdirectory to subdomain - iis

I have a WordPress website located at https://blog.example.com and another site hosted separately in Azure App Service (Windows) at https://www.example.com. Cloudflare sits in front of both of these sites.
I have set up a reverse proxy that points requests from https://www.example.com/blog to https://blog.example.com. This appears to be mostly working in that the blog posts appear, but there are a few peculiarities that make me think something is not set up quite right:
When submitting certain forms in the WordPress admin dashboard (e.g. general settings), it signs the user out of the session and redirects to the sign in page (a URL parameter references blog.example.com)
Using pagination in the Wordpress admin dashboard redirects to the page but on https://blog.example.com
There are a handful of pages in the Wordpress admin dashboard where there are console errors indicating that something coludn't be loaded from https://blog.example.com
When I add a 301 redirect from https://blog.example.com -> https://www.example.com/blog, it goes into an infinite redirect loop.
From my reading, I'm wondering whether all of these problems arise because when the request is processed by server hosting WordPress, the Host header is https://blog.example.com rather than https://www.example.com. There are several places (e.g. here) where WordPress uses the Host header to construct certain URLs, rather than the WordPress Website URL or Home URL (both set to https://www.example.com/blog).
Application Request Routing (ARR) on IIS has a preserveHostHeader option that presumably be used to have the original host header be retained. I've tried enabling this but the proxy stops working entirely:
Visiting https://www.example.com/blog (the root of the blog) shows me the https://www.example.com homepage
Visiting https://www.example.com/blog/a-blog-post shows me a 404 (generated by the site at https://www.example.com)
Here is my existing set up:
applicationHost.xdt (to enable ARR on Azure App Service as it's disabled by default)
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false"/>
<rewrite xdt:Transform="InsertIfMissing">
<allowedServerVariables xdt:Transform="InsertIfMissing">
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_X_UNPROXIED_URL" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>
web.config (to rewrite requests from subdirectory -> subdomain)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\Example.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
<rewrite>
<rules>
<clear />
<rule name="Blog Proxy" stopProcessing="false">
<match url="^blog(?:$|/)(.*)" />
<action type="Rewrite" url="https://blog.example.com/{R:1}" appendQueryString="true" logRewrittenUrl="false" />
<serverVariables>
<set name="HTTP_X_UNPROXIED_URL" value="https://blog.example.com/{R:1}" />
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
This appears to be a pretty standard setup for reverse proxies, but alas. Is this because I'm running behind Cloudflare? Does preserveHostHeader not work with Azure App Services? How can I set this reverse proxy up so that it handles my use case?

Related

Could you please advise how to resolve the issue with URL rewrite rules for azure web app?

I have an MVC dot net application (multi-tenant platform) deployed on Azure Web App.
I have configured two tenants: tenant1 and tenant2, with their URLs:
primer-test.azurewebsites.net/tenant1 and
primer-test.azurewebsites.net/tenant2
Both of them are accessible from IE, Safari etc. I purchased two domains on GoDaddy:
domain1.com
domain2.com
and I would like to configure the rewrite rules for them so whenever someone types in his browser either www.domain1.com or domain1.com, the content of primer-test.azurewebsites.net/tenant1 should be presented. Similarly, for the domain2.
I have attached these two custom domains to my web app, with no problem. I wrote the rewrite rules, but they seem to don't work as expected.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<rewrite>
<rules>
<rule name="domain1.com" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www.)?domain1.com" />
<add input="{PATH_INFO}" pattern="^/tenant1/" negate="true" />
</conditions>
<action type="Rewrite" url="\tenant1\{R:0}" />
</rule>
<rule name="domain2.com" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www.)?domain2.com" />
<add input="{PATH_INFO}" pattern="^/tenant2/" negate="true" />
</conditions>
<action type="Rewrite" url="\tenant2\{R:0}" />
</rule>
</rules>
</rewrite>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\kobsq.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />
</system.webServer>
</location>
</configuration>
Any idea what might be wrong?
Thanks very much!
In this case, from the URL you provided, I can see that primer-test.azurewebsites.net is the webapp you created and used. tenant1 and tenant2 should be virtual applications in webapp.
Concept:
Virtual application
Related Posts:
1. How to deploy a Flask+React application to Azure Web Service
2. Hosting Two Website Under one Web App - Azure Services
Correct use process and test steps:
Step 1.
Preparation work, create a main application of the .net framework (use web.config in the project for the purpose of configuring rewrite.
Configure in portal.
Create folder under site path and deploy virtual app by zip.
Test it without rewrite settings.
Step 2. Modify web.config file in RewriteTest project.
Step 3. Create custom domain to test.
Step 4. Test result. Fulfill your needs.

DNN UrlRewrite ("DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules") does not run custom rewrite rule on web.config

On our DNN site hosted in an Azure app service, we have the following custom rule set on our web.config:
<rewrite>
<rules>
<rule name="Proxy" stopProcessing="true">
<match url="^base3/?(.*)" />
<action type="Rewrite" url="https://(a website hosted in aws s3)/tx/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_X_Blog" value="1" />
</serverVariables>
</rule>
</rules>
We have also setup the following in our applicationHost.xdt
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
<rewrite>
<allowedServerVariables>
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_UNPROXIED_URL" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_ACCEPT_ENCODING" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_Mischief" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_Blog" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>
However, when trying to navigate to it (https://(our azure webapp.com)/base3/index.html) we constantly get the error The resource you are looking for has been removed, had its name changed, or is temporarily unavailable. which is confusing because this was the rewrite rule we have used on our other sites.
We even tried the same approach on a fresh app service and the rewrite rule above works just fine..
Trying to figure out what's wrong through heuristic analysis, on our web.config the rewrite rule now works if:
under <system.webServer>
<modules runAllManagedModulesForAllRequests="true">
then commenting <add name="UrlRewrite" type="DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules" preCondition="managedHandler" />
However, the main site breaks now..
How do we implement a rewrite rule that works properly with DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules??
UPDATE
<configSections>
<section name="RewriterConfig" type="URLRewriter.Config.RewriterConfigSerializerSectionHandler,URLRewriter" />
</configSections>
......
<RewriterConfig>
<Rules>
<RewriterRule>
<LookFor>^default/([0-9]+)/([_0-9a-z-]+)</LookFor>
<SendTo>11.aspx?id={R:1}</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
PRIVIOUS
About the function of url rewrite, the reason is the Web Server integrated by App Service cannot have full control. You can refer my answer in another post .
You can use the Application Gateway to implement the url rewriting function.

(413) Request Entity Too Large in IIS 10 URL Rewrite

I have an IIS 10 server configured as a basic URL Rewrite reverse proxy to preauthenticate requests directed at another web server, the calls are all presenting client certificates over SSL. I'm having issues with (413) Request Entity Too Large errors with large POSTs.
I've tried setting this in applicationHost.config
<serverRuntime uploadReadAheadSize="2147483647" />
However this had no effect. Are there any other settings that control URL Rewrite's rejection of large POSTs?
The web.config for the reverse proxy is very simple:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{CACHE_URL}" pattern="^(https?)://" />
</conditions>
<action type="Rewrite" url="{C:1}://my.internal.server:444/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
To sum up from the comment.
Try changing <httpRuntime maxRequestLength="4194304" /> first.
If it doesn't work try <requestLimits maxAllowedContentLength="2147483647" /> next.
If it stills doesn't work leave me a comment.
Normal setting for max upload file size:
Setting the request limits in the root web.config of the site (default is 30 MB). This can be set in Internet Information Services Manager Program also (MACHINE->Site->IIS->Request Filtering->Edit Feature Settings)
<!– 100 MB . Format uses Bytes –>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength=”102400000″ />
</requestFiltering>
</security>

Is it possible to disable HTTP on an azure app service, not just redirect it to HTTPS

In azure app services you are able to redirect HTTP traffic to HTTPS either via the web.config file or through the custom domains blade in azure portal. Is it possible to disable HTTP completely without doing a redirect?
Here is a way to achieve this:
Go to Kudu console for the Web App
Go into the D:\home\site folder
Create a file called applicationhost.xdt in that folder, with the following content (you can drag/drop it from your local machine):
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location path="%XDT_SITENAME%" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
<system.webServer xdt:Transform="InsertIfMissing">
<rewrite xdt:Transform="InsertIfMissing">
<rules xdt:Transform="InsertIfMissing">
<rule name="Disable HTTP" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="401" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
This will make http requests fail with 401 (you can customize the response in the <action> tag).

IIS HTTP Basic auth for specific URL

I want to restrict access using HTTP Basic Auth for a specific path so that someone who visits /www/private will be prompted with the authentication but not /www/public , /www/public/dashboard, ....
note: "private", "public", "dashboard", etc are not folders, but url rewrite
My current webconfig:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$" ignoreCase="false" negate="true" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
<location path="mysite/www/private">
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="false" />
<basicAuthentication enabled="true" />
<windowsAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
</location>
<location path="mysite/www">
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="true" />
<basicAuthentication enabled="false" />
<windowsAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
</location>
I also enabled basic auth and anonymous authorization in IIS Manager
However this does not work - it never prompts for authorization
IIS URLRewrite module rewrites the request before the authentication kicks in so with your current rewrite rule,this is not possible.
Exceprts from here
The URL Rewrite module is a native code module that plugs into the
request-processing pipeline at the Pre-begin Request or Begin Request
stages, and then evaluates the requested URL path by using a set of
rewrite rules. Each rewrite rule analyzes the URL path and, if all the
rule conditions are met, changes the original path to a new path.
After all the rules have been evaluated, the URL Rewrite module
produces a final URL path that is used for the request through the
remainder of the IIS pipeline processing. This means that the handler
selection in the IIS pipeline is made based on the rewritten URL that
is produced by the URL Rewrite module.
Your rewrite rule is in such a way that it rewrites any path which is not to a static file to index.php. Rest of the IIS pipeline sees the path as index.php. You have to implement your authentication inside index.php.Or you can easily write a simple IIS module,this SO question talks about it. You have to add little bit more logic to check the URL(if contains www/private) and send 401 etc.

Resources