Uncategorized

IIS rewrite rules

This post describes some of the tips and tricks that one may find useful when solving URL-based problems for their web server or web site. Each tip/trick has a description of a problem and then an example of how it can be solved with IIS 7 URL Rewrite Module.

1. Add or Remove Trailing Slash

Many web applications use “virtual URLs” – that is the URLs that do not directly map to the file and directory layout on web server’s file system. An example of such application may be an ASP.NET MVC application with URL format similar to this:https://stackoverflow.com/questions/60857/modrewrite-equivalent-for-iis-7-0 ) or a PHP application with URL format that looks like this:https://ruslany.net/2008/11/url-rewrite-module-release-to-web/) If you try to request these URLs with or without trailing slash you will still get the same page. That is OK for human visitors, but may be a problem for search engine crawlers as well as for web analytics services. Different URLs for the same page may cause crawlers to treat the same page as different pages, thus affecting the page ranking. They will also cause Web Analytics statistics for this page to be split up. This problem is very easy to fix with a rewrite rule. Having or not having a trailing slash in the URL is a matter of taste, but once you’ve made a choice you can enforce the canonical URL format by using one of these rewrite rules:

To always remove trailing slash from the URL:

<rule name="Remove trailing slash" stopProcessing="true">
<match url="(.*)/$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
</rule>

To always add trailing slash to the URL:


<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>

2. Enforce Lower Case URLs

A problem similar to the trailing slash problem may happen when somebody links to your web page by using different casing, e.g.https://ruslany.net/2008/07/IISNET-Uses-Url-Rewrite-Module/ vs. https://ruslany.net/2008/07/iisnet-uses-url-rewrite-module/. In this case again the search crawlers will treat the same page as two different pages and two different statistics sets will show up in Web Analytics reports.

What you want to do is to ensure that if somebody comes to your web site by using a non-canonical link, then you redirect them to the canonical URL that uses only lowercase characters:


<rule name="Convert to lower case" stopProcessing="true">
<match url="[A-Z]" ignoreCase="false" />
<action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>

3. Canonical Hostnames

Very often you may have one IIS web site that uses several different host names. The most common example is when a site can be accessed via https://www.yoursitename.com and via https://yoursitename.com. Or, perhaps, you have recently changed you domain name from oldsitename.com to newsitename.com and you want your visitors to use new domain name when bookmarking links to your site. A very simple redirect rule will take care of that:


<rule name="Canonical Host Name" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^ruslany\.net$" />
</conditions>
<action type="Redirect" url="https://ruslany.net/{R:1}" redirectType="Permanent" />
</rule>

To see an example of how that works try browsing to https://www.ruslany.net/2008/10/aspnet-postbacks-and-url-rewriting/. You will see in the browser’s address bar that “www” is removed from the domain name.

4. Redirect to HTTPS

When a site that requires SSL is accessed via non-secure HTTP connection, IIS responds with HTTP 403 (Unauthorized) status code. This may be fine if you always expect that your site visitors will be typing “https://…” in the browser’s address bar. But if you want your site to be easily discoverable and more user friendly, you probably would not want to return 403 response to visitors who came over unsecure HTTP connection. Instead you would want to redirect them to the secure equivalent of the URL they have requested. A typical example is this URL: http://www.paypal.com. If you follow it you will see that browser gets redirected to https://www.paypal.com.

With URL Rewrite Module you can perform this kind of redirection by using the following rule:


<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther" />
</rule>

Note that for this rule to work within the same web site you will need to disable “Require SSL” checkbox for the web site. If you do not want to do that, then you can create two web sites in IIS – one with http binding and another with https binding – and then add this rule to the web.config file of the site with http binding.

5. Return HTTP 503 Status Code in Response

HTTP status code 503 means that the server is currently unable to handle the request due to maintenance. This status code implies that the outage is temporary, so when search engine crawler gets HTTP 503 response from your site, it will know not to index this response, but instead to come back later.

When you stop the IIS application pool for your web site, IIS will return HTTP 503 for all requests to that site. But what if you are doing maintenance to a certain location of the web site and you do not want to shut down the entire site because of that? With URL Rewrite Module you can return 503 response only when HTTP requests are made to a specific URL path:


<rule name="Return 503" stopProcessing="true">
<match url="^products/sale/.*" />
<action type="CustomResponse" statusCode="503"
subStatusCode="0"
statusReason="Site is unavailable"
statusDescription="Site is down for maintenance" />
</rule>

6. Prevent Image Hotlinking

Image Hotlinking is the use of an image from one site into a web page belonging to a second site. Unauthorized image hotlinking from your site increases bandwidth use, even though the site is not being viewed as intended. There are other concerns with image hotlinking, for example copyrights or usage of images in an inappropriate context.

With URL Rewrite Module, it is very easy to prevent image hotlinking. For example the following rewrite rule prevents hotlinking to all images on a web site https://ruslany.net:


<rule name="Prevent image hotlinking">
<match url=".*\.(gif|jpg|png)$"/>
<conditions>
<add input="{HTTP_REFERER}" pattern="^$" negate="true" />
<add input="{HTTP_REFERER}" pattern="^https://ruslany\.net/.*$" negate="true" />
</conditions>
<action type="Rewrite" url="/images/say_no_to_hotlinking.jpg" />
</rule>

This rule will rewrite a request for any image file to /images/say_no_to_hotlinking.jpg only if the HTTP Referer header on the request is not empty and is not equal to the site’s domain.

7. Reverse Proxy To Another Site/Server

By using URL Rewrite Module together with Application Request Routing module you can have IIS 7 act as a reverse proxy. For example, you have an intranet web server and you want to expose its content over internet. To enable that you will need to perform the following configuration steps on the server that will act as a proxy:

Step1: Check the “Enable proxy” checkbox located in Application Request Routing feature view is IIS Manager.

Step2: Add the following rule to the web site that will be used to proxy HTTP requests:


<rule name="Proxy">
<match url="(.*)" />
<action type="Rewrite" url="https://internalserver/{R:1}" />
</rule>

Note the https:// prefix in the rewrite rule action. That is what indicates that this request must be proxy’ed, instead of being rewritten. When rule has “Rewrite” action with the URL that contains the protocol prefix, then URL Rewrite Module will not perform its standard URL rewriting logic. Instead it will pass the request to Application Request Routing module, which will proxy that request to the URL specified in the rule.

8. Preserve Protocol Prefix in Reverse Proxy

The rule in previous tip always uses non-secure connection to the internal content server. Even if the request came to the proxy server over HTTPS, the proxy server will pass that request to the content server over HTTP. In many cases this may be exactly what you want to do. But sometimes it may be necessary to preserve the secure connection all the way to the content server. In other words, if client connects to the server over HTTPS, then the proxy should use “https://” prefix when making requests to content server. Similarly, if client connected over HTTP, then proxy should use “https://” connection to content server.

This logic can be easily expressed by this rewrite rule:


<rule name="Proxy">
<match url="(.*)" />
<conditions>
<add input="{CACHE_URL}" pattern="^(https?)://" />
</conditions>
<action type="Rewrite" url="{C:1}://internalserver/{R:1}" />
</rule>

9. Rewrite/Redirect Based on Query String Parameters

When rewriting/redirection decisions are being made by using values extracted from the query string, very often one cannot rely on having the query string parameters always listed in exact same order. So the rewrite rule must be written in such a way so that it can extract the query string parameters independently of their relative order in the query string.

The following rule shows an example of how two different query string parameters are extracted from the query string and then used in the rewritten URL:


<rule name="Query String Rewrite">
<match url="page\.asp$" />
<conditions>
<add input="{QUERY_STRING}" pattern="p1=(\d+)" />
<add input="##{C:1}##_{QUERY_STRING}" pattern="##([^#]+)##_.*p2=(\d+)" />
</conditions>
<action type="rewrite" url="newpage.aspx?param1={C:1}&amp;param2={C:2}" appendQueryString="false"/>
</rule>

With this rule, when request is made to page.asp?p2=321&p1=123, it will be rewritten to newpage.aspx?param1=123&param2=321. Parameters p1 and p2 can be in any order in the original query string.

10. Avoid Rewriting of Requests for ASP.NET Web Resources

ASP.NET-based web applications very often make requests to WebResources.axd file to retrieve assembly resources and serve them to the Web browser. There is no such file exists on the server because ASP.NET generates the content dynamically when WebResources.axd is requested. So if you have a URL rewrite rule that does rewriting or redirection only if requested URL corresponds to a file or a folder on a web server’s file system, that rule may accidentally rewrite requests made to WebResources.axd and thus break your application.

This problem can be easily prevented if you add one extra condition to the rewrite rule:


<rule name="RewriteUserFriendlyURL1" stopProcessing="true">
<match url="^([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<!-- The following condition prevents rule from rewriting requests to .axd files -->
<add input="{URL}" negate="true" pattern="\.axd$" />
</conditions>
<action type="Rewrite" url="article.aspx?p={R:1}" />
</rule>

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.