# IIS sites, applications and virtual directories: the four-layer model

> Understand site vs application vs virtual directory vs application pool, create a lab site on 8080, and choose the isolation boundary deliberately.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29
- Test machine: IIS Manager UI reference: VM 361 Windows 11 26H2; Site Lab on :8080; Server 2025 cmdlets E1

IIS Manager Sites on VM 361: Default Web Site (:80) and Lab (:8080). Windows 11 UI reference; Server 2025 role steps are E1. Click to open full size.

## The short answer

Four different things:

| Object | What it is | Own binding? | Own app pool? |
|---|---|---|---|
| **Site** | A web endpoint: binding + root + app pool | Yes | Yes |
| **Application** | A path segment inside a site (e.g. `/shop`) | No (inherits site binding) | Yes |
| **Virtual directory** | A folder mapped to a URL path | No | No |
| **Application pool** | The worker-process boundary | No | — |

Use a **site** for a different hostname/port. Use an **application** for a separate app under the same host. Use a **virtual directory** only for static content that does not need its own process.

## The lab site

IIS Manager on VM 361 shows:

- `Default Web Site`, id 1, `http/*:80:`
- `Lab`, id 2, `http/*:8080:`, root `C:\inetpub\lab`, app pool `labpool`

The Lab site selected: binding 8080, path C:\inetpub\lab, app pool assigned. Captured on Windows 11 26H2.

Create it with PowerShell (WebAdministration module):

```powershell
Import-Module WebAdministration
New-Item -ItemType Directory -Force C:\inetpub\lab | Out-Null
New-WebAppPool -Name 'labpool'
New-WebSite -Name 'Lab' -PhysicalPath 'C:\inetpub\lab' -Port 8080 -ApplicationPool 'labpool'
```

Or with `appcmd`:

```bat
appcmd add apppool /name:labpool /managedRuntimeVersion:""
appcmd add site /name:Lab /physicalPath:C:\inetpub\lab /bindings:"http/*:8080:"
appcmd set app "Lab/" /applicationPool:labpool
```

`managedRuntimeVersion:""` means **No Managed Code** — correct for a static site or a reverse-proxied Node/Python app. Do not leave it on v4.0 unless the app needs .NET Framework.

## Add an application

```powershell
New-WebApplication -Site 'Lab' -Name 'shop' -PhysicalPath 'C:\apps\shop' -ApplicationPool 'shoppool'
```

This creates `http://host:8080/shop` with its own app pool. The parent site's web.config still applies unless the child overrides it. That inheritance is useful, and a common source of “it works at the root but not under /shop” bugs.

## Add a virtual directory

```powershell
New-WebVirtualDirectory -Site 'Lab' -Name 'docs' -PhysicalPath 'D:\StaticDocs'
```

`/docs` maps to a folder but uses the parent application's app pool. It is not an isolation boundary.

## Verify

```powershell
Get-Website | Select-Object Name, State, PhysicalPath, ApplicationPool
Get-WebApplication -Site 'Lab'
Get-WebVirtualDirectory -Site 'Lab'
Invoke-WebRequest http://localhost:8080/ -UseBasicParsing | Select-Object StatusCode
```

Then check from another machine on the allowed network; a localhost-only test does not prove the firewall/binding is correct.

> **Caution: Do not use one site per folder by habit**
>
> A new site needs a binding. If you only want `/app` under the same hostname, use an application, not a second site on another port. Ports are not a routing strategy.

## Common traps

- **Binding conflict:** two sites on the same IP:port with no host header/SNI. IIS starts one and fails the other.
- **Wrong app pool:** static site on `DefaultAppPool` with .NET loaded; unnecessary surface.
- **Virtual directory permissions:** the app pool identity needs NTFS read on the target folder, not just IIS “connect as”.
- **Nested config:** a parent `web.config` can block a child app; read the 500.19 error instead of deleting config.
- **Default site left running:** it may answer requests for an unbound hostname.

## Lab boundary

The UI is Windows 11 26H2. The cmdlets and object model are the same family as Server 2025, but Server-specific role installation remains E1 until a Server 2025 VM reproduces it.

## Sources

- [Microsoft Learn — IIS getting started](https://learn.microsoft.com/en-us/iis/get-started/introduction-to-iis/iis-web-server-overview)
- [Microsoft Learn — IIS configuration](https://learn.microsoft.com/en-us/iis/configuration/)
- [Microsoft Learn — New-WebSite](https://learn.microsoft.com/en-us/powershell/module/webadministration/new-website)

---

Source: https://windows.homes/en/server/web/iis-sites/
