The Configuration Model: web.config, applicationHost.config & Configuration Inheritance
IIS In Depth
Chapter 3 · The Configuration Model: web.config, applicationHost.config & Configuration Inheritance
Web Servers Fundamentals Chapter 3 introduced the shape of IIS's own configuration model — applicationHost.config machine-wide, web.config per-directory — and noted it sits structurally closer to Apache's own .htaccess philosophy than to Nginx's single centralized file. What it didn't cover is how a setting actually gets resolved once more than one web.config exists in the same directory chain, or what stops a subdirectory from overriding something the machine administrator deliberately locked down. That's this chapter.
The Configuration Hierarchy
Every configurable setting in IIS lives somewhere in a layered hierarchy of XML files, read in a fixed order from the most general to the most specific:
A request to /api/admin/users doesn't just read the deepest web.config in isolation — IIS reads every file in the chain above it, starting at applicationHost.config and walking down through each web.config in turn, merging settings as it goes. This is precisely the same directory-context idea Apache In Depth Chapter 3 covers for .htaccess — the deepest applicable file wins for any setting it actually specifies, and any setting it doesn't specify simply falls through to whatever the level above it already resolved to.
How Merging Actually Works: Add, Remove, Clear
For simple scalar settings — a boolean, a numeric limit — a more specific web.config value straightforwardly replaces the less specific one. Collection-based settings (a list of default documents, a list of MIME types, a list of modules) behave differently, because IIS's configuration schema exposes three explicit collection actions rather than silently overwriting the whole list:
<add> appends an item to whatever the collection already inherited from the level above. <remove> takes out one specific inherited item by name, leaving the rest. <clear> discards everything inherited so far and starts the collection fresh at that point in the hierarchy — used here before adding this directory's own two default documents, so this subdirectory's list isn't quietly appended onto whatever the site root or machine level already had configured.
web.config in a subdirectory intending to replace the default-document list, without a <clear /> first. Without it, the new <add> entries land on top of everything already inherited from the site root and machine level, producing a longer, unintended combined list rather than the shorter, intentional one — this is a genuine, easy-to-miss gotcha specific to how IIS's collection inheritance works, with no equivalent concept in a scalar setting.
Locking Sections: overrideModeDefault and allowOverride
Inheritance alone doesn't stop a subdirectory from overriding something a machine administrator never wanted overridden at all — that's a separate, deliberate lock, configured at the machine level:
Each configuration section — system.webServer/authentication, system.webServer/defaultDocument, and so on — carries its own overrideModeDefault, set in applicationHost.config's own <sections> declarations. Allow means any web.config further down the hierarchy is free to override that section. Deny means it isn't — a web.config that attempts to set a locked section produces an actual HTTP 500.19 configuration error rather than silently being ignored. Several security-sensitive sections ship Deny by default precisely so that an application deployed by someone without machine-level access can't quietly re-enable something an administrator locked down — system.webServer/authentication among them, which is exactly why Chapter 8's Windows Authentication material has to be configured at a level with the necessary permission, not casually from an arbitrary application's own web.config.
| overrideModeDefault | Effect | Typical use |
|---|---|---|
| Allow | Any web.config down the chain may override this section | Most content/display sections — defaultDocument, staticContent, etc. |
| Deny | Only applicationHost.config (or a location tag there) may set it; a web.config attempt fails with 500.19 | Security-sensitive sections — authentication, authorization, and similar |
Overriding a Locked Section From the Machine Level: <location>
A locked (Deny) section isn't necessarily fixed identically for every site forever — an administrator with access to applicationHost.config itself can still grant one specific site or path a different value, using a <location> tag:
This is how a locked, Deny-mode section still ends up different for one specific site or subdirectory without unlocking it for every application on the server — the override lives entirely inside applicationHost.config, scoped by path, rather than inside that site's own web.config. The distinction that matters: a <location> block is still machine-level configuration, written by whoever has access to applicationHost.config itself — it is not a loophole an application deployer can reach from their own web.config.
Resolution Order, Put Together
- IIS Manager or a config tool checks
applicationHost.config's section declarations foroverrideModeDefault(and any<location>override) — this determines whether a lower-levelweb.configis even permitted to touch that section - Reading proceeds top-down:
applicationHost.config, then eachweb.configfrom the site root down to the requested directory - Scalar settings from a deeper file simply replace shallower ones
- Collections accumulate via
<add>/<remove>unless a<clear />resets them at that level - The final, fully-merged configuration for that specific request path is what IIS actually applies
system.webServer section, subject to the exact same Allow/Deny/<location> mechanics covered here.
web.config that attempts to set a section locked with overrideModeDefault="Deny" produces exactly the same 500.19 status. The actual IIS error page names the specific config source and section responsible, which is the fastest way to tell the two apart rather than guessing.
Hands-On Exercises
A site's root web.config sets a defaultDocument list of index.html and default.aspx. A subdirectory's own web.config adds home.html with <add value="home.html" />, but includes no <clear />. List, in order, the final default-document list IIS will actually try for a request into that subdirectory, and explain why.
📄 View solutionA developer with no access to applicationHost.config tries to enable Windows Authentication from their application's own web.config and gets an HTTP 500.19 error. Explain what's actually happening, and describe the one legitimate way an administrator could still grant that specific application a different authentication setting than the rest of the server.
📄 View solutionExplain, in your own words, why IIS's configuration model needs three distinct collection actions (add, remove, clear) instead of just letting a more specific web.config's collection value silently replace a less specific one, the way a scalar setting does.
📄 View solutionChapter 3 Quick Reference
- Hierarchy — applicationHost.config (machine) → web.config at the site root → web.config at each subdirectory down to the request path
- Scalars replace; collections accumulate via <add>/<remove> unless reset with <clear />
- overrideModeDefault — Allow lets a web.config override a section; Deny restricts it to applicationHost.config, producing a 500.19 if violated
- <location path="..."> — how a machine administrator grants one specific site/path a different value for an otherwise-locked section, without unlocking it server-wide
- A 500.19 can mean either malformed XML or a locked section — the IIS error page names which