Azure Web App HTTP/HTTPS rewrite rules - azure

I have an angular app that I host in a Microsoft Azure Web Site. I've set it up with auto-redirect of all requests to HTTPS by installing an extension for me: https://github.com/gregjhogan/redirect-http-to-https-site-extension
What the extension app does is that it adds an applicationhost.xdt file which looks like this:
<?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" lockElements="clear">
<rule name="redirect HTTP to HTTPS" enabled="true" stopProcessing="true" lockItem="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
Now that works fine, and everything is redirected to HTTPS. Now I've come across a new requirement, and I want to edit the rewrite rule to the following: Redirect all requests to HTTPS (as it is now), except any url that contains the following: "/#/user/[Some random user id]".
I've read different posts, and tried some different stuff, but IIS setup and stuff like this isn't quite my domain, and I'm strugling finding it out. The try I feel like is close is when I added this {REQUEST_URI} condition:
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{REQUEST_URI}" negate="true" pattern=".*/#/user/.+" ignoreCase="true" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
I've tried restarting the Azure Web App, as well as redeploying it, but it doesn't seem kick in, everything still redirects to HTTPS as the original rule applies.

I was testing your regex online, and it seems that you need to escape the forward slash:
\/#\/user\/.+
Tested string:
http://localhost/#/user/123
Tested regex:
\/#\/user\/.+
website:
http://www.regextester.com/

Try adding this to your Application_beginrequest event
if (!HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.Url.Host.Contains("/#/user/[Some random user id]"))
{
Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+ HttpContext.Current.Request.RawUrl);
}

Related

additional paths with azure web app returns error

I made a react app using create-react-app. I am trying to deploy it on azure web app. I created a build and deployed using FTP.
When there is the internal redirect from the react the app I am able to see the webpage. But when I try to directly go to the url, I get this error.
For example:
if base url is www.example.com, and the app internally redirects to /new, the page goes to www.example.com/new. But if I directly try to load www.example.com/new, I get the above shown response. This doesn't happen in local testing
Demo:
I have created a demo here
For it to work for me, I added a web.config-file in the public-folder (this is where favicon.ico, index.html & manifest.json is located), and added the following code:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React 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="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I hope this might help :)
Place the below web.config file under the /site/wwwroot directory
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React 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="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
When there is the internal redirect from the react the app I am able to see the webpage. But when I try to directly go to the url, I get this error.
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
If you use Network tool to capture network traffic when you click the button New to render (redirect to) the new page, you will find it just changes the URL locally instead of really requesting for http://data-trigger-mass-test.azurewebsites.net/new to the server. When you directly browse and request for http://data-trigger-mass-test.azurewebsites.net/new to the server, the server could not find the resource, so it returns (404) error. In order to make the URL http://data-trigger-mass-test.azurewebsites.net/new work on both server and client-side, you may need to set up routes for it on both server and client side.
Your server should always send the root html file for all client request, so that it can pass routing to react.
If the server is NodeJs, add something like below into your server.js.
app.get('*', (req, res) => {
res.sendFile('public/index.html', { root: __dirname });
});
This worked:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React 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="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I created a web.config file in the public-folder where the index.html is located and added the above code.

Does redirecting a secure domain require an ssl certificate on both domains?

I'm hosting a site on Microsoft Azure and I need to add a redirect from the old domain (domain1.com) to a new domain (www.domain2.com). The problem I'm having however is that the redirect works fine on insecure url's :
http://domain1.com -> https://www.domain2.com
http://www.domain1.com -> https://www.domain2.com
However it doesn't work properly on secure url's:
https://domain1.com -> https://www.domain2.com
https://www.domain1.com -> https://www.domain2.com
What happens is that I get a certificate warning i.e. the given certificate isn't valid for this domain. If i accept the warning, the redirect occurs to the new domain just fine.
This shows me everything is working fine, it's just that ssl is negotiated before the redirect occurs in the browser and because there is no ssl certificate on the first domain I get the warning. Is this correct?
Is there something I'm missing here? Is there a better way to do this? Do I need an ssl certificate on both domains?
Here is my web.config file so you can see my configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<!-- Don't show directory listings for URLs which map to a directory. -->
<directoryBrowse enabled="false" />
<rewrite>
<rules>
<rule name="Protect files and directories from prying eyes" stopProcessing="true">
<match url="\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$" />
<action type="CustomResponse" statusCode="403" subStatusCode="0" statusReason="Forbidden" statusDescription="Access is forbidden." />
</rule>
<rule name="Force simple error message for requests for non-existent favicon.ico" stopProcessing="true">
<match url="favicon\.ico" />
<action type="CustomResponse" statusCode="404" subStatusCode="1" statusReason="File Not Found" statusDescription="The requested file favicon.ico was not found" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
</rule>
<!-- Rewrite URLs of the form 'x' to the form 'index.php?q=x'. -->
<rule name="Short URLs" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
<add input="{URL}" pattern="^/favicon.ico$" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php?q={R:1}" appendQueryString="true" />
</rule>
<rule name="Redirect old-domain to new-domain" stopProcessing="true" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www.)?domain1.com$" />
</conditions>
<action type="Redirect" url="https://www.domain2.com/{R:0}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="WWW Rewrite" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\." />
<add input="{HTTP_HOST}" negate="true" pattern="localhost" />
</conditions>
<action type="Redirect" url="https://www.domain2.com/{R:0}" appendQueryString="true" redirectType="Permanent" />
</rule>
<!-- Force HTTPS Starts -->
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.domain2.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<!-- Force HTTPS Ends -->
</rules>
</rewrite>
<httpErrors>
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" prefixLanguageFilePath="" path="/index.php" responseMode="ExecuteURL" />
</httpErrors>
<defaultDocument>
<!-- Set the default document -->
<files>
<remove value="index.php" />
<add value="index.php" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
You will be able to redirect non-secure URL to the HTTP/HTTPs. But you won’t be able to redirect HTTPS URL (https://domain1.com) to any HTTP/HTTPs (https://www.domain2.com) unless you have installed valid SSL certificate.
http://domain1.com -> https://www.domain2.com [YES, with or without SSL]
http://www.domain1.com -> https://www.domain2.com [YES, with or without SSL]
And,
https://domain1.com -> https://www.domain2.com [Required Valid SSL certificate for domain1.com]
https://www.domain1.com -> https://www.domain2.com [Required Valid SSL for domain1.com]
That’s why you are getting error as ‘the given certificate isn't valid for this domain’ because you have not valid certificate. Please note you have to install SSL certificate on both OLD and NEW domain if you want old URLs to redirect on new HTTPS URLs.
While the above answer is correct, there is something powerful with Google Domains. It allows you to, under advanced settings, to redirect with HTTPS, without needing an SSL certificate. I haven't seen it with other registrars besides Google Domains, and I should note that they don't support ever TLD. Assuming you've registered or transferred the domain in question over to Google Domains, here's how to implement it:
Navigate to Google Domains and click into the domain you want to redirect
Open the menu Menu, if applicable.
Click Website .
Under "Forward to an existing webpage, click; Add a forwarding address.
Enter a URL or IP address in the "Website URL" field.
Open 'Advanced Settings', and optionally select Permanent redirect (301) or Temporary
Then, under FORWARDING OVER SSL, select SSL on
click Forward to save your settings and that's it!

Azure web app redirect http to https

I use Azure cloud with web app and my server side written on nodejs.
When web app receive a http request I want to redirect the request to https
I found the solution.
I put that to my web.config file inside the rules tag
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="false" redirectType="Permanent" />
</rule>
The problem is when I type in the browser "https://myURL.com" it redirect to main screen every thing ok,
but when I change https to http "http://myURL.com" it redirect to https://myURL.com/" and add to the url "bin/www" according that the url looks like that "http://myURL.com/bin/www", the response is: page doesn't find.
The question is how to redirect a clear url without added data to the url?
Part of my web.config file:
<rewrite>
<rules>
<!-- Do not interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^bin/www\/debug[\/]?" />
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}" />
</rule>
<!-- All other URLs are mapped to the node.js site entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
</conditions>
<action type="Rewrite" url="bin/www" />
</rule>
<!-- Redirect all traffic to SSL -->
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="false" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin" />
</hiddenSegments>
</requestFiltering>
</security>
Thanks for answers, Michael.
Go to Azure portal and open the overview page of the (Web) App Service you wanna set to HTTPS only. In the sidebar, under the Settings section, there is an option for TLS/SSL Settings.
On clicking it, you will get an option on the screen to set your app's protocol to HTTPS only. There isn't any need to manually add separate ruleset for this.
This works on every tier of App Service Plan including the 'F'-Series (free subscription).
Note that, if you are adding any custom domain you also need to add corresponding SSL bindings, you can easily get them using LetsEncrypt or alike. If any of the custom hostnames for your app are missing SSL bindings, then:
When HTTPS Only is enabled clients accessing your app on those custom hostnames will see security warnings.
PS: I just saw that this question was asked about 3 years ago and that time maybe there was no direct option to do this. But even so, I'm posting my answer because on Google (as on February 2020) this question still ranks first among others regd. automatic HTTPS redirection in Azure.
As of November 2017, this is now a simple switch in the Azure Portal: "HTTPS Only", under Custom domains.
https://blogs.msdn.microsoft.com/benjaminperkins/2017/11/30/how-to-make-an-azure-app-service-https-only/
It's also very easy in ARM:
“httpsOnly”: true
There is also a free and open source extension for this.
Go to your Web App settings sidebar, search for the "Extensions" tab and click on "Add".
Scroll down and find the extension Redirect HTTP to HTTPS by gregjhogan.
Accept the terms.
Restart the Web App for the actions to take effect immediately.
Done !
For further details on the implementation of this extension, check the source code on GitHub. The most important source file is the applicationhost.xdt.
Quote from GitHub (02-08-2017) (credits go to gregjhogan):
applicationhost.xdt
<?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" lockElements="clear">
<rule name="redirect HTTP to HTTPS" enabled="true" stopProcessing="true" lockItem="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
R:1 is a back-reference to the rule pattern. You append that to the url here:
url="https://{HTTP_HOST}/{R:1}"
changing that into
url="https://{HTTP_HOST}"
should result in a redirect to the https root.

Angular2 - page refresh 404ing when hosted in Azure

I am working on an Angular2 app. It uses "#angular/common": "2.0.0-rc.4" and "#angular/router": "3.0.0-beta.2".
My problem is that when I use the browser refresh on some of the pages I see an error saying...
"The resource you are looking for has been removed, had its name changed, or is temporarily unavailable."
This also happens if I hit the url directly.
An example url is...
https://tilecasev2.azurewebsites.net/profile/therichmond
However if you view pages via the homepage they work ok but only until refreshed (https://tilecasev2.azurewebsites.net).
I have the below in my index.html head...
<base href="/">
Why does this happen and how can I fix it?
HashLocationStrategy avoids the issue by including a # in all of your angular routes but doesn't really fix it.
To make angular routes without hashes work in azure the same way they do in your local development environment, you just need to configure IIS to rewrite all requests as root. This lets angular handle the routing.
To do this, add a Web.config file to your site's root folder with the following contents:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
If you deploying in same app service plan both angular and API project then this the solution.
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Angular" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_URI}" pattern="^/api" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer></configuration>
for more details refer this link https://less0.github.io/azure-angular-II/
As Gunter pointed out HashLocationStrategy needed to be setup.
I followed the steps in the Angular2 docs and it all works now...
https://angular.io/docs/ts/latest/api/common/index/HashLocationStrategy-class.html

Web.config webServer rewrite rules for local and remote

I have an application that I want to run locally via http and remotely (on Azure) via https so I added this to my web.config file.
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to https">
<match url="(.*)"/>
<conditions>
<add input="{HTTPS}"
pattern="Off"/>
<add input="{REQUEST_METHOD}"
pattern="^get$|^head$" />
</conditions>
<action type="Redirect"
url="https://{HTTP_HOST}/{R:1}"/>
</rule>
</rules>
</rewrite>
</system.webServer>
After deploying this to Azure it worked perfectly on the remote server but when I run it locally the re-route occurs and I get SSL connection errors because I don't have or want a local ssl cert.
I have tried using the rule below (with an extra input testing localhost) to overcome the local issue but it appears as if the damage is done and nothing else I have tried will get my local site to work again.
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to https">
<match url="(.*)"/>
<conditions>
<!-- This has been added -->
<add input="{HTTP_HOST}"
pattern="localhost"
negate="true"/>
<add input="{HTTPS}"
pattern="Off"/>
<add input="{REQUEST_METHOD}"
pattern="^get$|^head$" />
</conditions>
<action type="Redirect"
url="https://{HTTP_HOST}/{R:1}"/>
</rule>
</rules>
</rewrite>
</system.webServer>
Would anyone mind putting me out of my misery and explaining where I'm going wrong?
I've got it working now!
I'm sure some of my previous attempts should have worked as well but didn't realise I need to clear the cache within Chrome - I guess Chrome caches such redirects?
Anyway, I added this rule and deleted the cache and all is working as I'd expect!
<rule name="Redirect to http"
stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll"
trackAllCaptures="false">
<add input="{HTTP_HOST}"
pattern="localhost" />
</conditions>
<action type="None" />
</rule>
Hope some of this might help others in the future...

Resources