IIS Server Optimization: Should You Remove DefaultWebSite and Default App Pools in Production?


3 views

When you first install Internet Information Services (IIS) on a Windows Server, it automatically creates:

  • A "Default Web Site" bound to port 80
  • An "DefaultAppPool" application pool
  • A "Classic .NET AppPool" (on some versions)

Security experts recommend removing default configurations because:

  1. Default sites might expose server information through directory browsing
  2. Unused application pools consume system resources
  3. Default configurations may have less restrictive permissions

While Microsoft doesn't explicitly mandate removal, their security documentation suggests:

"Remove or disable any default websites, applications, and virtual directories that you aren't using."

To safely remove these defaults, use this PowerShell script:


# Remove Default Web Site
Remove-Website -Name "Default Web Site"

# Remove default app pools
Remove-WebAppPool -Name "DefaultAppPool"
Remove-WebAppPool -Name "Classic .NET AppPool"

# Verify removal
Get-Website | Select-Object Name
Get-WebAppPool | Select-Object Name

If you need to keep the defaults but want to secure them:


# Disable the default website
Stop-WebSite -Name "Default Web Site"
Set-ItemProperty "IIS:\Sites\Default Web Site" -Name serverAutoStart -Value false

# Secure default app pools
Set-WebConfigurationProperty -Filter "/system.applicationHost/applicationPools/add[@name='DefaultAppPool']" -Name processModel.identityType -Value "LocalSystem"

Be cautious when:

  • Other services might expect DefaultAppPool to exist
  • Some legacy installers recreate the default site
  • Monitoring tools might check for default configurations
Action Production Recommended Test Environment
Remove Default Web Site Yes Optional
Remove DefaultAppPool Yes (after migration) No
Remove Classic .NET AppPool Yes Yes

When setting up IIS servers in production environments, administrators often wonder whether to keep the default installation artifacts. The Default Web Site (typically bound to port 80) and default application pools (like DefaultAppPool) are created automatically during IIS installation.

While Microsoft doesn't explicitly prohibit keeping these defaults, their security documentation strongly recommends removing unused components. This aligns with the principle of least privilege and reduces attack surface. The Windows Server Hardening Guide suggests:

# Remove default website using PowerShell
Remove-Website -Name "Default Web Site"

# Remove default application pools
Remove-WebAppPool -Name "DefaultAppPool"
Remove-WebAppPool -Name "Classic .NET AppPool"

Keeping default sites and pools creates several risks:

  • Default configurations may have weaker security settings
  • Unused components increase patching requirements
  • Potential confusion during troubleshooting
  • Default bindings might conflict with custom applications

For existing production servers, follow this transition approach:

# First, create your custom application pool
New-WebAppPool -Name "CustomProdPool" 
Set-ItemProperty "IIS:\AppPools\CustomProdPool" -Name "managedRuntimeVersion" -Value "v4.0"

# Migrate applications from default pool
Get-WebApplication | Where-Object { $_.applicationPool -eq "DefaultAppPool" } | 
ForEach-Object { Set-WebConfigurationProperty -Filter "/system.applicationHost/sites/site[@name='$($_.SiteName)']/application[@path='$($_.path)']" -Name "applicationPool" -Value "CustomProdPool" }

Use this PowerShell script to identify and remove unused components:

# Audit default components
$defaultComponents = @{
    Websites = Get-Website | Where-Object { $_.Name -like "*Default*" }
    AppPools = Get-WebAppPool | Where-Object { $_.Name -like "*Default*" -or $_.Name -like "*Classic*" }
}

# Safe removal procedure
if ($defaultComponents.Websites.Count -gt 0) {
    Write-Host "Found default websites:"
    $defaultComponents.Websites | ForEach-Object {
        if ($_.State -eq "Stopped") {
            Remove-Website -Name $_.Name
            Write-Host "Removed website: $($_.Name)"
        }
    }
}

$defaultComponents.AppPools | Where-Object { (Get-WebApplication -ApplicationPool $_).Count -eq 0 } |
ForEach-Object {
    Remove-WebAppPool -Name $_.Name
    Write-Host "Removed unused app pool: $($_.Name)"
}

There are rare scenarios where keeping defaults might be justified:

  • When using IIS as reverse proxy with ARR
  • Certain legacy applications requiring Classic pipeline
  • Temporary testing environments

In these cases, at least modify the default configurations:

# Harden default app pool if keeping it
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.applicationHost/applicationPools/add[@name='DefaultAppPool']/recycling/periodicRestart" -name "time" -value "00:00:00"
Set-ItemProperty "IIS:\AppPools\DefaultAppPool" -Name "processModel" -Value @{identityType="ApplicationPoolIdentity"}