IIS rewrite rule with HTTP status code 301 - redirect

I need to write a IIS rewrite rule which matches the following condition
example.com
www.example.com
http://www.example.com
https://www.example.com
http://example.com
https://example.com
this all should redirect to https://www.example.com/somepage/
The condition is that from SEO point of view only one 301 redirection should be identified. Any pointer is appreciated
Following redirection were tried works but leads to two hops instead of one
<rule name="no path" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" pattern="^\/?$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^(www.)?example.com$" ignoreCacom="true" />
</conditions>
<action type="Redirect" url="https://www.example.com/somepage" redirectType="Permanent" />
</rule>
<rule name="with path and http" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" negate="true" ignoreCacom="true" />
<add input="{REQUEST_URI}" pattern="^\/.+$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^(www.)?example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with path and https" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" negate="true" ignoreCacom="true" />
<add input="{REQUEST_URI}" pattern="^\/.+$" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^ON$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with somepage, no www" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^example.com$" ignoreCacom="true" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="with somepage and https, no www" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{PATH_INFO}" pattern="\/somepage" ignoreCacom="true" />
<add input="{HTTP_HOST}" pattern="^www.example.com$" ignoreCacom="true" />
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://www.example.com{REQUEST_URI}" redirectType="Permanent" />
</rule>
enter code here

Are these rules achieve your requirement?
With this rule order. http(s)://(www.)example.com/a.aspx with path will be redirected to https://www.example.com/a.aspx
https://www.example.com/a.aspx will not be redirected to avoid infinite redirection loop.
http(s)://(www.)example.com/ will be redirected to https://www.example.com/somepage.
Since it is impossible to merge everything into a rule. We need at least 3 rule to achieve this.
<rule name="https://www.example.com">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_URI}" pattern="^/.+$" />
<add input="{HTTP_HOST}" pattern="www.example.com" />
<add input="{HTTPS}" pattern="^on$" />
</conditions>
<action type="None" />
</rule>
<rule name="no path" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{URL}" pattern="^(/)?$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example.com$" />
</conditions>
<action type="Redirect" url="https://www.example.com/somepage/" />
</rule>
<rule name="with path" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_URI}" pattern="^/.+$" />
<add input="{HTTP_HOST}" pattern="^(www\.)?example.com$" />
<add input="{REQUEST_URI}" pattern="^/somepage" negate="true" />
</conditions>
<action type="Redirect" url="https://wwww.example.com{REQUEST_URI}" />
</rule>

Related

IIS RewriteMaps to new URL including WWW and HTTPS

I have the following Rule in my RewriteRules
<rule name="New URL redirects">
<match url=".*"/>
<conditions>
<add input="{OldUrls:{REQUEST_URI}}" pattern="(.+)"/>
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false"/>
</rule>
in my RewriteMaps i have the following
<rewriteMap name="OldUrls">
<add key = "/SomeOldUrl" value = "/New/ShinyUrl" />
</rewriteMap>
I want to make sure that the new url is using www and https as part of the redirect, how do i add all of this into one rule?
You could try below rule:
<rule name="Force WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^[^www]" />
<add input="{HTTPS}" pattern="off" />
<add input="{HTTPS}" pattern="www.sample1.com" negate="true" />
<add input="{OldUrls:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="https://www.sample1.com/{C:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rewriteMap name="OldUrls">
<add key="/s2" value="/s3" />
</rewriteMap>
</rewriteMaps>

IIS Rewrite / Redirect Rules Query

The rule below does the following:
- http://www.example.com -> https://example.com
etc
- https://example.com/contacts.html -> . https://example.com/contacts
So (all requests to HTTPS, and all www -> (non)www) + hides .HTML extensions.
I would like to add the ability to remove the following issue:
https://example.com/Home.html -> https://example.com/Home
But for the specific case of /Home I would prefer it displays /
Any help would be greatly appreciated..
Rule below:
<rewrite>
<rules>
<rule name="Force non-WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^(www\.)(.*)$" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://example.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Redirect .html extension" stopProcessing="false">
<match url="^(.*)\.html$" ignoreCase="true" />
<conditions logicalGrouping="MatchAny">
<add input="{URL}" pattern="(.*)\.html$" ignoreCase="false" />
</conditions>
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<rule name="hide .html extension" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:0}.html" />
</rule>
</rules>
</rewrite>
I made some change in your rule to prevent rewrite for /Home and /. Then created two rules to handle request to /Home.html.
It works fine on my side and should achieve your requirement.
<rewrite>
<rules>
<rule name="Force non-WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^(www\.)(.*)$" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://example.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Redirect .html extension" enabled="true" stopProcessing="true">
<match url="^(.*)\.html$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="(.*)\.html$" ignoreCase="false" />
<add input="{URL}" pattern="^/Home.html$" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<rule name="hide .html extension" enabled="true" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}.html" matchType="IsFile" />
<add input="{URL}" pattern="^/$" negate="true" />
<add input="{URL}" pattern="^/Home$" negate="true" />
</conditions>
<action type="Rewrite" url="{R:0}.html" />
</rule>
<rule name="redirect /Home" enabled="true" stopProcessing="true">
<match url="^Home.html$" />
<action type="Redirect" url="/" />
</rule>
<rule name="rewrite Home" stopProcessing="true">
<match url="^$" />
<action type="Rewrite" url="/Home.html" />
</rule>
</rules>
</rewrite>

IIS Rewrite for single query string to SEO version

I am trying for hours to get the following IIS rewrite to work:
Incoming URL:
https://example.com/services/control/status?Id=SO1234567
Expected output:
https://example.com/orders/detail/SO1234567
IIS Rewrite Rule:
<rule name="Custom rewrite rule" patternSyntax="ExactMatch" stopProcessing="true">
<match url="^services/control/status\?Id=(SO|so){1}([0-9]*)" />
<action type="Rewrite" url="/orders/detail/{R:0}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
Additional information:
I am running a single web site in IIS.
1 web applications for an API under this web site.
Angular files within the web site.
Angular rules:
<rule name="Angular Routes" stopProcessing="false">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<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>
Complete Rewrite section:
<rewrite>
<rules>
<clear />
<rule name="Angular Routes" stopProcessing="false">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(marketplace)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
<rule name="Custom rewrite rule" patternSyntax="ExactMatch" stopProcessing="true">
<match url="^services/control/status\?Id=(SO|so){1}([0-9]*)" />
<action type="Rewrite" url="/orders/detail/{R:0}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
</rule>
</rules>
</rewrite>
As far as I know, the url pattern will not match the query string. If you want to get the query string value, you should use rewrite condition.
Details, you could refer to below rule:
<rule name="QueryStringRue" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{QUERY_STRING}" pattern="^Id=([0-9a-zA-Z]*)" />
</conditions>
<action type="Redirect" url="https://example.com/orders/detail/{C:0}" />
</rule>

Two redirections instead of one for Lower Case

When I add the following rule to the redirection file:
<rule name="To Lowercase" enabled="true" stopProcessing="true">
<match url=".*[A-Z].*" ignoreCase="false" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/Images/" negate="true" />
<add input="{REQUEST_METHOD}" pattern="GET" ignoreCase="true" />
</conditions>
<action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
<rule name="Redirect to WWW">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^foo.com$" />
</conditions>
<action type="Redirect" url="http://www.foo.com/{R:0}" redirectType="Permanent" />
</rule>
And attempt to open webiste "Foo.com" watching network behaviour I can see that it's first redirected (301) from "https://Foo.com" to "http://foo.com" and then from "http://foo.com" back to "https://foo.com" with status 302.
Is there a way to modify this rule to make just one redirection?
Based on your answers in comments, you can just simply specify the domain name in your rules to avoid multiple redirects. For example:
<rule name="To Lowercase" enabled="true" stopProcessing="true">
<match url=".*[A-Z].*" ignoreCase="false" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/Images/" negate="true" />
<add input="{REQUEST_METHOD}" pattern="GET" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.foo.com/{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
<rule name="Redirect to WWW">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^foo.com$" />
</conditions>
<action type="Redirect" url="https://www.foo.com/{R:0}" redirectType="Permanent" />
</rule>

Redirect to https://www in web.config

I'd like both example.com and www.example.com to be redirected to https://www.example.com
At the moment, I have these two rules in my web.config:
<rule name="HTTP/S to HTTPS Redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{SERVER_PORT_SECURE}" pattern="^0$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
</rule>
<rule name="Root Redirect to www" stopProcessing="true">
<match url=".*" negate="false" />
<action type="Redirect" url="{C:1}://www.{HTTP_HOST}/{R:0}" />
<conditions trackAllCaptures="true">
<add input="{CACHE_URL}" pattern="^(.*)://" />
<add input="{HTTP_HOST}" pattern="^(?!www\.).*" />
</conditions>
</rule>
Is it possible to combine them, so the user only experiences one redirect?
Update:
This seems to do the trick:
<rules>
<clear />
<rule name="Redirect non-www OR non-https to https://www">
<match url=".*" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^example.com$" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:0}" redirectType="Permanent"/>
</rule>
</rules>
Any downsides?