Introduction to IIS URL Rewrite Module

The IIS URL Rewrite Module is one of the most powerful extensions available for Internet Information Services on Windows Server 2022. It allows administrators and developers to define rules that transform incoming URLs before IIS processes them, enabling clean URLs, canonical redirects, protocol enforcement, and complex routing logic — all without modifying application code. Unlike simple redirect rules, URL Rewrite can inspect request headers, server variables, query strings, and even the HTTP method to decide how a URL should be handled.

This guide walks through installing the module, understanding rule anatomy, writing regex patterns, building common use-case rules, and troubleshooting with Failed Request Tracing.

Installing the URL Rewrite Module

The URL Rewrite Module is not included in the default IIS installation. You must download and install it separately from the Microsoft IIS downloads page, or use Web Platform Installer / PowerShell with the Web Deploy MSI chain.

Download the x64 MSI directly from Microsoft:

Invoke-WebRequest -Uri "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi" -OutFile "C:Temprewrite_amd64.msi"
Start-Process msiexec.exe -ArgumentList "/i C:Temprewrite_amd64.msi /quiet /norestart" -Wait

After installation, restart IIS to load the new native module:

iisreset /restart

Verify the module is loaded by checking the IIS modules list:

Get-WebConfiguration system.webServer/globalModules | Where-Object { $_.name -like "*rewrite*" }

You should see RewriteModule listed. The module registers itself at the global level and is available to all sites and applications on the server.

Understanding the web.config Rule Structure

All URL Rewrite rules live inside the <system.webServer> section of a web.config file. Rules can be placed in the server-level applicationHost.config, a site-level web.config, or an application-level web.config. Site-level and app-level rules are generally preferred because they travel with the application and keep configuration self-contained.

The basic structure of a rewrite rule section looks like this:


  
    
      
        
          
          
            
          
          
        
      
    
  

The stopProcessing="true" attribute tells IIS to stop evaluating subsequent rules if this rule matches. Without it, rules continue to be evaluated in order, which can lead to unintended double-processing. Always set stopProcessing="true" on redirect rules to prevent redirect chains.

Inbound Rules and Regex Patterns

Inbound rules examine the URL path as it arrives from the client. The match url attribute takes a regular expression pattern that is tested against the URL path relative to the site root (without the leading slash). Capture groups in the regex are accessible as back-references: {R:0} is the full match, {R:1} is the first capture group, {R:2} the second, and so on.

A rule to rewrite /products/123 to /catalog.php?id=123 would look like:


  
  

The regex ^products/([0-9]+)$ anchors the match to URLs that begin with products/ and end with one or more digits. The digit portion is captured in group 1 and substituted into the rewrite target via {R:1}.

Rewrite vs. Redirect

URL Rewrite supports two fundamental action types: Rewrite and Redirect. They behave very differently and choosing the wrong one is a common mistake.

Rewrite is a server-side operation. The client never knows the URL was changed. IIS internally processes the request against the new URL while the browser continues to display the original URL. Use this for clean URL routing, hiding query strings, or mapping friendly URLs to dynamic scripts.

Redirect sends an HTTP 301 (Permanent) or 302 (Temporary) response to the client, instructing it to request a different URL. The browser URL bar updates. Use this for SEO canonicalization, HTTPS enforcement, and domain changes.



  
  




  
  

Using Conditions and Server Variables

Conditions allow rules to be applied only when additional criteria are met. You can test server variables such as {HTTP_HOST}, {HTTPS}, {REQUEST_METHOD}, {QUERY_STRING}, {HTTP_REFERER}, and many others. The logicalGrouping attribute of the conditions block can be set to MatchAll (AND logic) or MatchAny (OR logic).

Common server variables used in conditions:

{HTTP_HOST}        - Hostname from the Host header (e.g., www.example.com)
{HTTPS}            - "on" if the connection is HTTPS, "off" otherwise
{REQUEST_URI}      - Full request URI including query string
{QUERY_STRING}     - Query string portion of the URL
{REQUEST_METHOD}   - HTTP method (GET, POST, etc.)
{REMOTE_ADDR}      - Client IP address
{HTTP_USER_AGENT}  - User-Agent header string

A rule that only fires when the request is NOT already using HTTPS:


  
  
    
  
  

Canonical Redirect: www to non-www

One of the most common URL Rewrite use cases is enforcing a canonical domain. Search engines treat www.example.com and example.com as separate URLs, which can split PageRank. The following rule redirects all www. requests to the bare domain:


  
  
    
  
  

Notice the use of {C:1} here. Condition back-references use {C:N} instead of {R:N}. The first capture group in the condition pattern — the domain without www. — is referenced as {C:1}.

To do the reverse (redirect bare domain to www), flip the condition:


  
  
    
  
  

Custom 404 Redirect with URL Rewrite

You can use URL Rewrite to send users to a custom error page or redirect old URLs that no longer exist. The following rule matches a specific legacy path and sends a 301 to a new location:


  
  

For a wildcard catch of an old directory structure, use a more general pattern:


  
  

Rewrite Maps

Rewrite Maps are lookup tables that map input strings to output strings. They are ideal when you have a large number of one-to-one URL remappings that would be cumbersome to express as individual rules. The map is defined once and referenced from one or more rules.


  
    
      
      
      
    
  
  
    
      
      
        
      
      
    
  

When the rule is evaluated, IIS looks up {REQUEST_URI} in the LegacyRedirects map. If a match is found, the mapped value is returned and stored in {C:1}, which is then used as the redirect target.

Chained Rules

Rules can be chained so that a subsequent rule only fires if the previous rule matched. This is done by setting the type attribute of one rule’s action to Rewrite and then having a second rule examine the rewritten URL. Alternatively, you can use the trackAllCaptures attribute or condition-based chaining where one rule leaves a marker in a server variable that the next rule checks.

A simpler approach is to use consecutive rules without stopProcessing, allowing IIS to pass the URL through multiple transformations in sequence:



  
  
    
  
  




  
  

Troubleshooting URL Rewrite with Failed Request Tracing

When rules are not behaving as expected, Failed Request Tracing (FREB) is the most effective diagnostic tool. Enable it at the site level in IIS Manager, or via command line:

# Enable failed request tracing for the site
Enable-WebRequestTracing -Name "Default Web Site"

# Configure tracing for all status codes (including 200) to diagnose rewrites
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" `
  -filter "system.applicationHost/sites/site[@name='Default Web Site']/traceFailedRequestsLogging" `
  -name "enabled" -value "true"

Add a trace rule in web.config for 200 status codes to capture rewrite activity:


  
    
      
        
      
      
    
  

FREB logs are saved to %SystemDrive%inetpublogsFailedReqLogFiles as XML files. Open them in Internet Explorer or Edge (they include an XSL stylesheet) to see a detailed event trace showing exactly which rules fired, what patterns were tested, whether conditions matched, and what the final action was. This makes it straightforward to identify why a rule is matching unexpectedly or failing to fire.

Common troubleshooting tips: always test your regex patterns in isolation using a tool like regex101.com before putting them in web.config; check that stopProcessing is set correctly to prevent double-redirects; remember that URL patterns are matched against the path without the leading slash; and confirm the URL Rewrite module is actually installed if rules appear to have no effect.