IIS URL Redirect Configuration Guide
Guide to configuring URL redirects in IIS: URL Rewrite module, web.config rules, match patterns, conditions, HTTPS enforcement, and troubleshooting with Failed Request Tracing.
IIS (Internet Information Services) handles redirects through the URL Rewrite module and web.config rules. The approach is XML-based and GUI-friendly, but the syntax has enough quirks to trip up anyone used to Apache or Nginx. For the full overview of all redirect types, see our HTTP Redirect Guide.
This guide covers the URL Rewrite module, web.config rule structure, common redirect patterns, and how to debug when things go wrong.
The URL Rewrite Module
IIS does not include redirect/rewrite functionality out of the box. You need the URL Rewrite module, which is a free Microsoft extension.
Install it:
- Download from the official Microsoft IIS site or install via Web Platform Installer
- On Windows Server, it may already be available through Server Manager > Add Roles and Features
Once installed, you can manage rules through IIS Manager (GUI) or directly in web.config (XML). Both produce the same result. The web.config approach is better for version control and deployment.
web.config Rule Structure
All redirect rules live inside the <system.webServer><rewrite><rules> section of web.config:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="My Redirect" stopProcessing="true">
<match url="^old-page$" />
<action type="Redirect" url="https://example.com/new-page"
redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
The key attributes:
- name: A label for the rule. Must be unique within the rules section.
- stopProcessing: When
true, no further rules are evaluated after this one matches. Similar to the[L]flag in Apache. - match url: A regex pattern matched against the URL path (without the leading slash).
- action type:
Redirectsends a redirect response. Other types includeRewrite(internal, no redirect) andAbortRequest. - redirectType:
Permanent(301),Found(302),SeeOther(303), orTemporary(307).
Single Page Redirects
The simplest case: redirect one URL to another.
<rule name="Redirect old-page to new-page" stopProcessing="true">
<match url="^old-page$" />
<action type="Redirect" url="/new-page" redirectType="Permanent" />
</rule>
For a temporary redirect, change redirectType to Found:
<rule name="Temporary redirect" stopProcessing="true">
<match url="^sale$" />
<action type="Redirect" url="/current-promotion" redirectType="Found" />
</rule>
Pattern Matching with Regex
IIS URL Rewrite uses ECMAScript-style regex. Capture groups work with back-references {R:1}, {R:2}, etc.
Redirect a directory
<rule name="Redirect old-blog" stopProcessing="true">
<match url="^old-blog/(.*)$" />
<action type="Redirect" url="/blog/{R:1}" redirectType="Permanent" />
</rule>
{R:1} is the first capture group from the match pattern. /old-blog/my-post becomes /blog/my-post.
Strip file extensions
<rule name="Remove .html extension" stopProcessing="true">
<match url="^(.+)\.html$" />
<action type="Redirect" url="/{R:1}" redirectType="Permanent" />
</rule>
Redirect with multiple captures
<rule name="Restructure product URLs" stopProcessing="true">
<match url="^products/([^/]+)/([^/]+)$" />
<action type="Redirect" url="/shop/{R:1}/{R:2}" redirectType="Permanent" />
</rule>
Conditions
Conditions let you add logic beyond URL pattern matching. They check server variables like HTTPS status, hostname, headers, and query strings.
Basic condition syntax
<rule name="Rule with condition" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
redirectType="Permanent" />
</rule>
The <conditions> block sits between <match> and <action>. All conditions must be true (AND logic by default) for the rule to fire.
OR conditions
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^old-domain\.com$" />
<add input="{HTTP_HOST}" pattern="^legacy\.example\.com$" />
</conditions>
MatchAny means any condition being true triggers the rule. The default MatchAll requires all conditions to be true.
Condition back-references
Conditions have their own capture groups, referenced with {C:1}, {C:2}, etc.:
<rule name="Redirect based on query" stopProcessing="true">
<match url="^product\.aspx$" />
<conditions>
<add input="{QUERY_STRING}" pattern="^id=([0-9]+)$" />
</conditions>
<action type="Redirect" url="/products/{C:1}" appendQueryString="false"
redirectType="Permanent" />
</rule>
This redirects /product.aspx?id=42 to /products/42.
Forcing HTTPS
The most common IIS redirect. For the full HTTPS migration guide, see HTTP to HTTPS Redirect Guide.
<rule name="Force HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
redirectType="Permanent" />
</rule>
If your IIS server sits behind a load balancer that terminates SSL, check the X-Forwarded-Proto header instead:
<rule name="Force HTTPS behind load balancer" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_X_FORWARDED_PROTO}" pattern="^http$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
redirectType="Permanent" />
</rule>
WWW vs Non-WWW
Redirect www to non-www
<rule name="Remove www" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.example\.com$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://example.com/{R:1}"
redirectType="Permanent" />
</rule>
Redirect non-www to www
<rule name="Add www" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^example\.com$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:1}"
redirectType="Permanent" />
</rule>
Combine HTTPS + www in one rule
Avoid redirect chains by handling HTTPS and www canonicalization together:
<rule name="Canonical URL" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{HTTP_HOST}" pattern="^example\.com$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:1}"
redirectType="Permanent" />
</rule>
Query String Handling
By default, IIS URL Rewrite appends the original query string to the redirect target. Control this with the appendQueryString attribute.
Preserve query string (default)
<action type="Redirect" url="/new-page" redirectType="Permanent" />
<!-- /old-page?ref=google becomes /new-page?ref=google -->
Strip query string
<action type="Redirect" url="/new-page" appendQueryString="false"
redirectType="Permanent" />
<!-- /old-page?ref=google becomes /new-page -->
Redirect based on query parameters
<rule name="Query-based redirect" stopProcessing="true">
<match url="^search$" />
<conditions>
<add input="{QUERY_STRING}" pattern="^q=(.+)$" />
</conditions>
<action type="Redirect" url="/find?query={C:1}" appendQueryString="false"
redirectType="Permanent" />
</rule>
Outbound Rules
Outbound rules modify the response body before it reaches the client. They are not redirects, but they are useful when migrating domains. For example, rewriting links in HTML from http:// to https://:
<outboundRules>
<rule name="Update internal links to HTTPS">
<match filterByTags="A, Img, Script, Link" pattern="http://example\.com" />
<action type="Rewrite" value="https://example.com" />
</rule>
</outboundRules>
Use outbound rules sparingly. They process every response body, which adds overhead.
Rule Ordering
IIS evaluates rules in the order they appear in web.config. The first matching rule with stopProcessing="true" wins. Put specific rules before general ones:
<rules>
<!-- Specific redirects first -->
<rule name="Specific page" stopProcessing="true">
<match url="^specific-old-page$" />
<action type="Redirect" url="/specific-new-page" redirectType="Permanent" />
</rule>
<!-- General rules after -->
<rule name="Force HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
redirectType="Permanent" />
</rule>
</rules>
If the HTTPS rule came first, it would intercept the request before the specific page redirect could fire, potentially creating an extra hop.
Troubleshooting with Failed Request Tracing
When redirects are not working as expected, IIS's Failed Request Tracing (FRT) shows exactly what the URL Rewrite module is doing.
Enable Failed Request Tracing
- Open IIS Manager
- Select your site
- Click Failed Request Tracing in the Actions panel
- Enable it and set the log directory
Create a tracing rule
- Go to Failed Request Tracing Rules
- Add a new rule for status codes
301-302(or200-399for broader coverage) - Select the URL Rewrite provider
Read the trace logs
FRT generates XML files in the log directory. Open them in a browser (IIS includes an XSL stylesheet) to see a step-by-step breakdown of rule evaluation:
- Which rules were evaluated
- Which conditions matched or failed
- What the final URL was
- Whether
stopProcessinghalted further evaluation
Disable FRT in production
Failed Request Tracing writes a log file per request. Under traffic, this fills disk space fast. Enable it to diagnose a problem, then turn it off.
Common IIS Redirect Mistakes
Missing the URL Rewrite module
If your web.config includes <rewrite> rules but the URL Rewrite module is not installed, IIS returns a 500 error. The error message in the event log will reference the rewrite section as unrecognized.
Forgetting stopProcessing
Without stopProcessing="true", IIS continues evaluating rules after a match. This can cause double redirects or unexpected behavior.
Escaping issues in XML
Remember that web.config is XML. Special characters need escaping: & becomes &, < becomes <. Regex patterns with these characters will break if not escaped properly.
Testing in the wrong context
Rules in the root web.config apply to the entire site. Rules in a subdirectory's web.config only apply to that subdirectory. Make sure your rule is in the right file.
Testing Your Redirects
# Check redirect status and location header
curl -I https://example.com/old-page
# Follow the full chain
curl -ILs https://example.com/old-page | grep -E "HTTP/|Location:"
# Test with query string
curl -I "https://example.com/old-page?ref=test"
After making changes to web.config, IIS picks them up automatically. No restart or reload is needed. But browser caching of 301 redirects can make it look like changes are not taking effect. Test with curl or an incognito window.
Trace your redirect chains
Paste any URL and see every hop, status code, and header instantly.
References
- Microsoft, "URL Rewrite Module," https://www.iis.net/downloads/microsoft/url-rewrite
- Microsoft, "Creating Rewrite Rules for the URL Rewrite Module," https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/creating-rewrite-rules-for-the-url-rewrite-module
- Microsoft, "Failed Request Tracing," https://learn.microsoft.com/en-us/iis/configuration/system.webserver/tracing/
Related Articles
Never miss a broken redirect
Trace redirect chains and detect issues before they affect your users and SEO. Free instant tracing.
Try Redirect Tracer