What's the address of your website? www.domain.com or domain.com?

There are two camps on the subject of the www subdomain. One believe it should be enforced (www.yes-www.org) and the other (no-www.org) that it should be removed. They are both right.

What's important is that there is only a single canonical address to your website – with or without www.

The web.config makes it easy for us to either enforce or remove the www subdomain using URL rewrites. There are many examples online on how to do this, but they all share 2 fundamental flaws. The rules have a direct dependency to the domain name and they don't work with both HTTP and HTTPS.

So let's see if we can create generic URL rewrite rules that can be used on any website without modifications.

Your server needs to have the URL Rewrite module installed. Chances are that it does already. Azure Websites does and so does all of my other hosting providers.

Rewrite rules need to be placed inside the <rewrite> element in web.config:

      <!-- My rules -->

So here are 2 rules that works on all domains and on both HTTP and HTTPS.

Remove WWW

This rule redirects any incoming request to www.domain.com to domain.com while preserving the HTTP(S) protocol:

<rule name="Remove WWW" patternSyntax="Wildcard" stopProcessing="true">
  <match url="*" />
    <add input="{CACHE_URL}" pattern="*://www.*" />
  <action type="Redirect" url="{C:1}://{C:2}" redirectType="Permanent" />

Enforce WWW

This rule redirects any incoming request to domain.com to www.domain.com while preserving the HTTP(S) protocol:

<rule name="Enforce WWW" stopProcessing="true">
  <match url=".*" />
    <add input="{CACHE_URL}" pattern="^(.+)://(?!www)(.*)" />
  <action type="Redirect" url="{C:1}://www.{C:2}" redirectType="Permanent" />

So there you have it. It's easy once you now how.

For more info on the URL Rewrite Module, see the Configuration Reference.


Comment by Stefan Kip

I use these rules, which do more than just remove 'www.':

<!-- SEO rules (from: www.seomoz.org/.../what-every-seo-should-know-about-iis) -->
<!-- SEO | Section 1 | Whitelist -->
<rule name="Whitelist - Resources" stopProcessing="true">
<match url="^(?:css/|scripts/|images/|install/|config/|umbraco/|umbraco_client/|base/|webresource\.axd|scriptresource\.axd|__browserLink|[^/]*/arterySignalR/.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="None" />
<!-- SEO | Section 2 | Rewrites (chaining) -->
<rule name="SEO - Remove default.aspx" stopProcessing="false">
<match url="(.*?)/?default\.aspx$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
<action type="Rewrite" url="_{R:1}" />
<rule name="SEO - Remove trailing slash" stopProcessing="false">
<match url="(. )/$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<action type="Rewrite" url="_{R:1}" />
<rule name="SEO - Lower case" stopProcessing="false">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_METHOD}" pattern="GET" />
<add input="{R:1}" pattern="[A-Z]" ignoreCase="false" />
<action type="Rewrite" url="_{ToLower:{R:1}}" />
<!-- SEO | Section 3 | Redirecting -->

Comment by Nick

How is what you're doing to achieve this a better alternative to the default rule created when you use "Add Rule(s)" dialog in IIS and choose "Canonical domain name"?


Comment by Kal

This breaks if you are using an ip address url while debugging.

The method I found via Google is to have 2 rules that check the SERVER_PORT_SECURE header and depending on the value set http or https. Since the domain name is part of the test it is ignored when an ip address url is used.

Comment by Randy Martin

@Stefan - the redirect action for your https rewrite should actually say
<action type="Redirect" url="https://{C:1}/{R:2}" />
You have http instead of https in the gist you did.

Randy Martin