How to Temporarily Redirect All HTTP/HTTPS Traffic to a Maintenance Page in IIS: A Scalable Solution


2 views

When managing an IIS server hosting hundreds of web applications, temporarily redirecting all traffic during maintenance presents unique scaling challenges. Traditional methods like per-application rewrite rules or App_Offline.htm files become impractical due to deployment overhead.

Here's a server-level approach that works without modifying individual applications:

<configuration>
  <system.webServer>
    <tracing>
      <traceFailedRequests>
        <add path="*">
          <traceAreas>
            <add provider="ASP" verbosity="Verbose" />
            <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
          </traceAreas>
          <failureDefinitions statusCodes="200-999" />
        </add>
      </traceFailedRequests>
    </tracing>
    <rewrite>
      <rules>
        <rule name="Global Maintenance Redirect" patternSyntax="Wildcard" stopProcessing="true">
          <match url="*" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
            <add input="{HTTP_HOST}" pattern="maintenance.example.com" negate="true" />
          </conditions>
          <action type="Redirect" url="https://maintenance.example.com" appendQueryString="false" redirectType="Temporary" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

1. Create a dedicated maintenance website in IIS
2. Deploy the rewrite rule at server level (applicationHost.config)
3. Use PowerShell to toggle maintenance mode:

# Enable Maintenance Mode
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "system.webServer/rewrite/rules/rule[@name='Global Maintenance Redirect']/match" -Name "url" -Value "*"
  
# Disable Maintenance Mode  
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "system.webServer/rewrite/rules/rule[@name='Global Maintenance Redirect']/match" -Name "url" -Value "disable_maintenance_redirect"

For complex environments, consider these enhancements:

<rule name="Maintenance Bypass for Health Checks" patternSyntax="Wildcard" stopProcessing="true">
  <match url="healthcheck.aspx" />
  <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
    <add input="{REMOTE_ADDR}" pattern="192\.168\.1\.100" />
  </conditions>
  <action type="None" />
</rule>

When implementing global redirects:

  • Use 307 (Temporary Redirect) status code
  • Minimize the maintenance page size (under 10KB)
  • Set appropriate cache headers: Cache-Control: no-store, no-cache

When managing multiple web applications on IIS with shared backend resources, temporary maintenance windows present a unique operational challenge. The core problem emerges when you need to:

  • Redirect ALL traffic across multiple sites simultaneously
  • Implement the solution quickly (faster than the maintenance duration)
  • Maintain clean revert capability
  • Avoid manual per-site configuration

Option 1: Centralized URL Rewrite at Server Level

Contrary to common documentation, the global applicationHost.config approach works better than framework-level web.config modifications:

<configuration>
    <system.webServer>
        <rewrite>
            <globalRules>
                <rule name="Global Maintenance Redirect" enabled="true" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_HOST}" pattern="localhost" negate="true" />
                    </conditions>
                    <action type="Redirect" url="https://status.yourdomain.com/maintenance" 
                            appendQueryString="false" redirectType="Temporary" />
                </rule>
            </globalRules>
        </rewrite>
    </system.webServer>
</configuration>

Key advantages:

  • Applies to all sites without individual deployment
  • Can be toggled via appcmd set config commands
  • Excludes internal health checks (localhost condition)

Option 2: Failover Binding Technique

For environments using single IP with host headers:

:: PowerShell implementation
Import-Module WebAdministration

# Create maintenance site
New-WebSite -Name "MaintenanceProxy" -Port 80 -IPAddress "*" -PhysicalPath "C:\inetpub\maintenance"
Set-ItemProperty "IIS:\Sites\MaintenanceProxy" -Name Bindings -Value @{protocol="http";bindingInformation="*:80:"}

# Prioritize the site
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/site[@name='MaintenanceProxy']" -name "applicationDefaults.preloadEnabled" -value "true"

# Alternate method using binding precedence
(Get-WebBinding -Name "MaintenanceProxy").ElementInformation.Properties["bindingInformation"].Value = "*:80:"

For zero-downtime transitions:

@echo off
:: Batch script for maintenance mode toggle
SET MAINTENANCE_MODE=%1

if "%MAINTENANCE_MODE%"=="ON" (
    appcmd set config -section:system.webServer/rewrite/globalRules /+"[name='Global Maintenance Redirect',enabled='True']" /commit:apphost
    iisreset /noforce
) else (
    appcmd set config -section:system.webServer/rewrite/globalRules /-"[name='Global Maintenance Redirect',enabled='True']" /commit:apphost
    iisreset /noforce
)

Remember to:

  • Test with non-production traffic first
  • Implement proper cache-control headers on maintenance page
  • Consider HTTP 503 status for API endpoints
  • Log all redirect events for post-maintenance analysis