Windows
IIS Web Server¶
Internet Information Services (IIS) is the web server built into Windows Server. It
hosts static sites, ASP.NET / ASP.NET Core apps, and reverse-proxied back ends,
managed through a GUI, PowerShell, or appcmd.
Tested on
Windows Server 2022 with IIS 10.0. The workflow is identical on Windows Server 2019 and 2016 (also IIS 10.0).
Installing IIS¶
IIS is the Web Server (IIS) role. Install it with PowerShell:
# Core web server plus IIS Manager and the PowerShell module
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
# Common extras you will likely want
Install-WindowsFeature Web-Asp-Net45, Web-Windows-Auth, Web-Http-Redirect
Or via Server Manager -> Add Roles and Features -> Web Server (IIS), selecting role services on the wizard's Role Services page.
Verify with Get-WindowsFeature Web-Server and browse to http://localhost - you
should see the IIS default page.
IIS Manager¶
IIS Manager (inetmgr / Server Manager -> Tools -> Internet Information
Services (IIS) Manager) is the central console. The left Connections pane shows
the server, an Application Pools node, and a Sites node. The middle pane
shows feature icons for the selected item; the right Actions pane has the
contextual commands (Add Website, Bindings, Restart, ...).
The PowerShell equivalent is the WebAdministration module (Import-Module
WebAdministration), which exposes an IIS:\ drive plus cmdlets like
New-Website, New-WebAppPool, and New-WebBinding.
Sites, bindings, and application pools¶
Three concepts do the heavy lifting:
- Site - a hosted web application with a physical path (the folder of files) and one or more bindings.
- Binding - the combination of protocol + IP address + port + host name that tells IIS which incoming requests belong to this site. The host name lets many sites share one IP and port 80/443 (name-based hosting).
- Application pool - the worker process(es) (
w3wp.exe) a site runs in, with its own identity and settings.
Binding examples (all can coexist on one server):
http *:80:www.example.com -> Site "Example"
https *:443:www.example.com -> Site "Example" (needs a certificate)
http 10.0.0.5:8080: -> Site "Internal" (IP + port, no host name)
Why application pools matter¶
Each application pool runs in a separate process with its own identity. This gives you:
- Isolation - one site crashing or leaking memory does not take down sites in other pools.
- Security - a pool can run as the low-privilege
ApplicationPoolIdentity(a virtual accountIIS APPPOOL\<PoolName>), so you grant filesystem access to exactly that site and no more. - Independent lifecycle - you can recycle or stop one pool without touching others, and set per-pool .NET CLR version and recycling rules.
Give each site (or each trust boundary) its own app pool.
Adding a site¶
GUI¶
- In IIS Manager, right-click Sites -> Add Website....
- Site name:
Example. A matching app pool is created automatically. - Physical path:
C:\inetpub\sites\example(the folder with your files). - Binding: Type
http, IPAll Unassigned, Port80, Host namewww.example.com. - OK. Put an
index.html(or app files) in the path and browse to it.
PowerShell¶
Import-Module WebAdministration
New-Item 'C:\inetpub\sites\example' -ItemType Directory
New-WebAppPool -Name 'ExamplePool'
New-Website -Name 'Example' -PhysicalPath 'C:\inetpub\sites\example' `
-ApplicationPool 'ExamplePool' -HostHeader 'www.example.com' -Port 80
# Add an HTTPS binding (certificate attached separately, see below)
New-WebBinding -Name 'Example' -Protocol https -Port 443 -HostHeader 'www.example.com'
Grant the pool identity read access to the content:
icacls C:\inetpub\sites\example /grant 'IIS APPPOOL\ExamplePool:(OI)(CI)RX'
(see File sharing and permissions for ACLs).
SSL/TLS bindings and certificates¶
HTTPS needs a certificate bound to the site's https binding. The conceptual
flow - key pair, CSR, trusted CA, certificate, then bind - is the same as on Linux;
see HTTPS with Let's Encrypt for the
underlying ideas.
- Get a certificate into the server's Local Machine -> Personal store (import a PFX, request from an internal CA, or use a tool like win-acme for public ACME/Let's Encrypt certs).
- In IIS Manager, select the site -> Bindings... -> Add -> Type
https, port443, host name, then pick the certificate from the SSL certificate list. Enable Require Server Name Indication (SNI) to host multiple HTTPS sites on one IP.
# Bind an installed cert (by thumbprint) to the site's https binding
$cert = Get-ChildItem Cert:\LocalMachine\My |
Where-Object Subject -like '*www.example.com*'
New-Item -Path "IIS:\SslBindings\!443!www.example.com" -Value $cert -SSLFlags 1
-SSLFlags 1 enables SNI. Use Edit Bindings to add an https binding first if
you have not already.
Authentication and authorization¶
In the site's Authentication feature you enable/disable methods:
- Anonymous - on by default; serves content with no logon (public sites).
- Basic - prompts for username/password; only over HTTPS (credentials are base64, not encrypted).
- Windows Authentication - transparent SSO for domain users (intranets); needs
the
Web-Windows-Authrole service.
The Authorization Rules feature then allows/denies specific users or roles. A common intranet setup: disable Anonymous, enable Windows Auth, and add an Allow rule for a domain group.
# Example: turn off anonymous, turn on Windows auth for a site
Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/anonymousAuthentication' `
-Name enabled -Value $false -PSPath 'IIS:\Sites\Example'
Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/windowsAuthentication' `
-Name enabled -Value $true -PSPath 'IIS:\Sites\Example'
Logs¶
By default IIS writes W3C access logs per site under:
The <SiteID> matches the site's ID in IIS Manager. Configure fields, rollover, and
location in the site's Logging feature. Failed Request Tracing (a separate
role service) captures detailed traces for specific status codes when you are
debugging.
iisreset and recycling¶
iisreset # stop+start the whole IIS service stack (all sites - disruptive)
iisreset /status # show service states
# Per-site / per-pool control (preferred - scoped, less disruptive)
Restart-WebAppPool 'ExamplePool' # recycle just one pool
Stop-Website 'Example'
Start-Website 'Example'
Recycling restarts a pool's worker process gracefully (finishing in-flight
requests on the old process while a new one starts). App pools recycle
automatically on a schedule and on config changes; tune this in the pool's
Advanced Settings -> Recycling. Reach for iisreset only when you really need
to restart everything - it briefly takes all sites offline.
IIS vs nginx¶
If you also run nginx on Linux, the roles map roughly like this:
| IIS | nginx | |
|---|---|---|
| Platform | Windows Server (role) | Linux/Unix (package) |
| Config | GUI + web.config / applicationHost.config |
text files (nginx.conf) |
| Process model | App pools -> w3wp.exe worker(s) |
master + worker processes |
| Per-site isolation | Application pools (own identity) | typically one daemon, server {} blocks |
| Virtual hosts | Site bindings (host/IP/port) | server blocks + server_name |
| Restart/reload | iisreset, recycle app pool |
nginx -s reload (graceful) |
| Native strength | ASP.NET / .NET, Windows Auth | static files, reverse proxy at scale |
Both are production web servers; the binding/virtual-host and graceful-reload ideas carry over directly between them.
Verify your work¶
- Run
Get-WindowsFeature Web-Serverand confirm it shows Installed. - Browse to
http://localhostand confirm the IIS default page loads. - After adding your site, browse to its host name (add a hosts-file entry if no
DNS) and confirm your content loads; check
Get-Websitelists it. - Add the HTTPS binding + certificate, browse
https://www.example.com, and confirm the padlock / a valid certificate. - Run
Restart-WebAppPool 'ExamplePool', reload the site, and confirm it still serves. Check a request appears inC:\inetpub\logs\LogFiles\W3SVC<ID>\.
Summary¶
- Install IIS with
Install-WindowsFeature Web-Server -IncludeManagementTools; manage it in IIS Manager (inetmgr) or the WebAdministration module. - A site has a physical path and bindings (protocol + IP + port + host name); application pools isolate sites into separate worker processes with their own identity.
- Add HTTPS by binding a certificate to an
httpsbinding (use SNI for many sites on one IP); the cert concepts match the Linux HTTPS page. - Control access with Authentication (Anonymous/Basic/Windows) plus
Authorization Rules; logs live under
C:\inetpub\logs\LogFiles\W3SVC<SiteID>\. - Prefer app-pool recycling / per-site start-stop over the disruptive
iisreset. Versus nginx, bindings ~ server blocks and recycling ~ graceful reload. See also PowerShell basics.