Deploy IIS with TLS, isolated pools, logging, and verified backups
Build a Windows Server 2025 IIS site with validated SNI TLS, a least-privilege pool identity, privacy-aware W3C logs, health evidence and a complete isolated restore test.
Serve an IIS application securely and recoverably without privileged workers, certificate bypass, plaintext exposure or configuration-only backup claims.
- Windows Server 2025
- Internet Information Services 10.0
- PowerShell 7.6 current
- Patched dedicated Windows Server 2025 host Reliable DNS/time, reviewed TCP/443 path, out-of-band access and no unresolved existing IIS/binding ownership.
Get-ComputerInfo | Select WindowsProductName,WindowsVersion,OsBuildNumber - Enterprise PKI certificate Exact SAN/EKU/trust/revocation/private key and renewal/rebind plan for the site FQDN.
Test-Certificate -Cert (Get-Item Cert:\LocalMachine\My\{{certificateThumbprint}}) -Policy SSL -DNSName {{siteHostName}} - Documented application release Supported runtime/modules, health endpoint, signed content, externalized writable state and protected secret/dependency design.
- Logging and operations capacity Protected W3C/application log paths, privacy/retention, forwarding, alerts and application/pool/TLS test fixtures.
- Complete recovery environment Protected configuration/content/data/PKI/secrets/dependency backups plus isolated Windows Server 2025 restore host.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A Windows Server 2025 IIS website with a dedicated `ApplicationPoolIdentity`, root-owned application/content files, separately permissioned writable data, a unique SNI HTTPS binding, a PKI-issued certificate validated for SAN/EKU/chain/revocation/private key, and no plaintext production binding.
- A production logging and diagnostics design using W3C UTC logs with method, URI stem, status, substatus, Win32 status and time taken; query strings are omitted by default to reduce secret/personal-data exposure. Capacity, retention, forwarding, Failed Request Tracing activation and privacy ownership are explicit.
- A deployment and health model covering application-pool identity, runtime/pipeline, rapid-fail behavior, recycling ownership, startup, process/site state, local/external TLS requests, certificate renewal, access-log evidence, application errors and a known-good rollback.
- A verified recovery set that distinguishes `appcmd add backup` of IIS server configuration from site content, application data, machine-level keys/certificates and external dependencies. The full set is restored on an isolated Windows Server 2025 IIS host and passes TLS, application, logging and rollback tests.
- The site listens only on the intended IP/443/FQDN SNI tuple, presents a valid certificate for that name, requires HTTPS, serves the expected health response and does not expose another site's certificate or content.
- The worker process runs as `IIS AppPool\<pool>`, can read application content and write only the declared data/log paths, cannot modify executable/configuration/content, and has no LocalSystem or shared-pool privilege.
- W3C logs and application events identify request method, path, status/substatus, Win32 status and latency in UTC without routinely storing query strings. Capacity, retention, ACL and forwarding checks pass.
- An isolated restore test reconstructs IIS configuration, content and required application state/certificate identity from protected artifacts. A successful `appcmd add backup` alone is never described as complete website backup evidence.
Architecture
How the parts fit together
HTTP.sys accepts the SNI HTTPS binding on TCP/443 and selects the certificate for the requested host name. IIS maps the binding to one site whose root application runs in a dedicated application pool under its virtual `ApplicationPoolIdentity`. NTFS grants that identity read/execute on immutable content and narrowly scoped modify permission only on a data directory outside the web root. IIS configuration resides primarily in ApplicationHost.config and related server configuration; AppCmd backup captures that layer but not complete content, application databases, private keys or external services. W3C logs are written to a protected capacity-isolated directory and forwarded. Application events complement request logs. The enterprise PKI owns certificate renewal/reissuance. A separate restore host receives the configuration backup, content/state artifacts and a test certificate/identity path, then proves bindings, pool, health, logs and application behavior without taking production traffic.
- Define host/site/FQDN, runtime, identity, immutable/writable paths, TLS/PKI, logging/privacy, dependencies, SLOs and recovery objectives.
- Capture existing IIS features, sites, bindings, pools, certificates, configuration backups/history, logs, ports, firewall and external dependencies.
- Install only required IIS role services and patch before exposure.
- Validate the certificate, create/protect content and data paths, create the dedicated pool and stopped site.
- Create the unique SNI HTTPS binding, bind the certificate, require SSL and confirm no conflicting/plaintext production binding.
- Configure W3C logging, application-pool health/recycling and deploy versioned content without secrets.
- Run local and external TLS/application/negative tests and correlate W3C/application/system evidence.
- Create configuration/content/state recovery artifacts, restore them on an isolated host and prove the full service before declaring backup success.
Assumptions
- The target is a dedicated, currently patched Windows Server 2025 host with IIS 10, reliable DNS/time and a host firewall/load-balancer design reviewed for TCP/443.
- An enterprise PKI issues a certificate whose SAN contains the public/service FQDN, with Server Authentication EKU, valid chain/revocation, protected private key and a tested renewal/rebind owner.
- The application has a documented runtime, health endpoint, configuration/secrets provider, external dependencies, immutable content and separate writable state. It never stores secrets in URL query strings.
- A unique dedicated application pool is acceptable; the workload does not require LocalSystem, broad IIS_IUSRS write access or a shared identity.
- Log retention/privacy, capacity, forwarding and incident access are approved. Query strings are omitted unless a separately justified, scrubbed application requires them.
- The organization has a separate Windows Server 2025 restore-test host or isolated clone and a supported way to recover application data/dependencies and certificate identity without exposing private-key passwords.
Key concepts
- ApplicationPoolIdentity
- A virtual account unique to an application pool, referenced in ACLs as `IIS AppPool\PoolName`.
- SNI
- TLS Server Name Indication lets HTTP.sys select the certificate/site by requested hostname on a shared IP and port.
- IIS binding
- A protocol plus IP, port and optional host name mapping; certificate binding is an additional HTTPS identity association.
- W3C logging
- Customizable request log format whose timestamps are UTC and whose fields can include status, substatus, Win32 status and time taken.
- AppCmd configuration backup
- Backup of IIS global configuration and related server state; it is not a complete backup of site content, application data, certificates or dependencies.
- Restore test
- Reconstruction on an isolated host followed by functional, TLS, identity, logging and data verification—not a backup file existence check.
Before you copy
Values used in this guide
{{siteName}}Unique IIS site name.
Example: AcmePortal{{appPoolName}}Dedicated IIS application pool name.
Example: AcmePortal-v1{{siteHostName}}Canonical FQDN in DNS and certificate SAN.
Example: portal.corp.example{{contentPath}}Root-owned immutable website/application content directory.
Example: D:\Web\AcmePortal\current{{dataPath}}Writable application data directory outside the web root.
Example: D:\WebData\AcmePortal{{logPath}}Protected capacity-isolated IIS log root.
Example: E:\IISLogs{{certificateThumbprint}}Validated LocalMachine\My HTTPS certificate thumbprint.
Example: 34A6BC2B56DC4CF8BFB741415A9D7C76B6D82031{{iisBackupName}}Versioned AppCmd IIS configuration backup name.
Example: AcmePortal-predeploy-20260728T1300Z{{restoreHost}}Isolated Windows Server 2025 IIS recovery-test host.
Example: WS25-IIS-RESTORE-01Security and production boundaries
- Use a dedicated ApplicationPoolIdentity and ACL the exact virtual account. Do not run the pool as LocalSystem or grant broad write to IIS_IUSRS, Users or the web root.
- Do not store certificate private-key passwords, application credentials or connection strings in command arguments, web.config plaintext, deployment logs or backups without the approved protected secret mechanism.
- Require certificate validation for every test. Never use `curl -k`, `Invoke-WebRequest -SkipCertificateCheck`, disabled revocation or an IP/alias that does not match SAN.
- Request logs can contain personal data and tokens. Omit URI query strings by default, prevent secrets in URLs, restrict log access and define retention/forwarding.
- AppCmd configuration restore is server-wide and can affect every site/pool. Perform restore testing only on an isolated host and use a production restore only under full server change control.
- A healthy HTTPS response does not prove backup recoverability, correct pool identity, negative ACLs, log completeness or external dependency recovery.
Stop before continuing if
- Stop if another site owns the binding, DNS/FQDN is wrong, certificate SAN/EKU/chain/revocation/private key fails or renewal/rebind ownership is missing.
- Do not deploy if the worker needs write access to code/config/content, LocalSystem, broad IIS_IUSRS rights or plaintext secrets.
- Stop when HTTP remains publicly reachable unintentionally, TLS validation requires bypass, or load balancer and origin identity/headers are not defined.
- Do not enable production traffic when W3C/app logging, capacity, privacy, forwarding, health endpoint or rollback is incomplete.
- Do not call AppCmd backup a website backup. Content, data, certificates/keys and external dependencies need separate protected recovery and an isolated restore test.
- Stop restoration if it targets production unintentionally, server-wide configuration would overwrite unrelated sites, or restored identity/data/version cannot be verified.
instruction
Define site, runtime, identity, data, TLS, logging, and recovery contract
Document the canonical FQDN, site/binding, runtime and modules, immutable content, writable data, secret provider, pool identity, health/SLO, external dependencies, log fields/retention, PKI lifecycle and every recovery layer with RPO/RTO.
Why this step matters
An IIS site includes runtime, worker identity, filesystem rights, secrets, data, TLS, logging and dependencies—not only a binding and folder. Separate immutable content from writable state, define the authoritative TLS/host path and exclude query strings from logs. Recovery names IIS configuration, content, state, certificate identity, secrets and dependencies separately with RPO/RTO.
What to understand
Record FQDN, DNS/load-balancer path, IP/port/SNI and HTTPS-only behavior.
Inventory runtime, handler/modules, health endpoint and external dependencies.
Separate root-owned content from narrowly writable data/temp/log paths.
Define dedicated pool identity, service rights and negative ACL tests.
Set W3C fields/retention/privacy and multi-layer backup/restore acceptance.
System changes
- Creates the reviewed service and recovery specification; no IIS changes.
Syntax explained
SNI binding- Uses requested TLS hostname to select the site certificate on a shared IP/443.
RPO/RTO- Maximum accepted data loss and recovery duration for the complete service.
Get-Content .\deployment\acme-portal-service-contract.json | ConvertFrom-Json | Format-ListFQDN : portal.corp.example Binding : https / *:443 / SNI Pool identity : IIS AppPoolAcmePortal-v1 Content : D:\Web\AcmePortal\current (read-only) Writable data : D:\WebData\AcmePortal Query logging : disabled Health : /health RPO / RTO : 15 minutes / 60 minutes Restore test : isolated Windows Server 2025 host
Checkpoint: Every runtime and recovery boundary has an owner
Test-Path .\deployment\acme-portal-service-contract.json; Get-FileHash .\deployment\acme-portal-service-contract.jsonContinue whenApproved topology, runtime, identity/ACL, TLS, logging/privacy, dependencies, RPO/RTO, fixtures and rollback.
Stop whenWritable/executable boundaries, secret provider, certificate lifecycle, dependencies, logs or restore layers are unknown.
If this step fails
Application writes beside deployed binaries.
Likely causeBuild/runtime layout mixes immutable and mutable state.
Trace all writes during startup and workload.
ResolutionReconfigure data/temp paths outside the content root before IIS deployment.
Team treats VM snapshot as the only backup.
Likely causeApplication-consistent data and restore portability are undefined.
Map IIS config, content, state, PKI/secrets and external dependencies.
ResolutionCreate supported layer-specific backups and an isolated restore test.
Security notes
- Do not place secrets or certificate key passwords in the contract.
Alternatives
- Use a managed hosting service when operating these layers exceeds the team's recovery/security capability.
Stop conditions
- Writable/executable boundaries, secret provider, certificate lifecycle, dependencies, logs or restore layers are unknown.
verification
Capture IIS features, sites, pools, bindings, certificates, and recovery state
Inventory installed role services, AppCmd/IIS configuration, site IDs/bindings/physical paths, pool identity/runtime/state, HTTP.sys listeners, firewall, certificates, log/history paths, backups and external dependencies before installation or change.
Why this step matters
IIS configuration is server-wide: a binding can collide and a restore can overwrite unrelated sites. Capture features, IDs, bindings, applications, pools, identities, locks, HTTP.sys certificates, firewall, logs/history and backups. A stopped Default Web Site is not unowned. Record dependencies and renewal agents, and label AppCmd backups accurately as configuration only.
What to understand
List installed IIS role services and pending reboot/updates.
Export server config and list sites/apps/bindings/pools/workers.
Inventory TCP/80/443 listeners, HTTP.sys SSL mappings and firewall rules.
List matching certificates without private-key output.
Record log/config-history/backup paths, ACL/capacity and external dependencies.
System changes
- None; creates protected pre-change IIS and dependency evidence.
Syntax explained
appcmd list site/apppool- Shows effective IIS objects and states from the server configuration.
appcmd list backup- Lists IIS configuration backups only, not application content/data.
Get-WindowsFeature Web-* | Where Installed; & $env:windir\system32\inetsrv\appcmd.exe list site; & $env:windir\system32\inetsrv\appcmd.exe list apppool; & $env:windir\system32\inetsrv\appcmd.exe list backupInstalled role services : Web-Server, Web-Mgmt-Tools, Web-Http-Logging Sites: SITE "Default Web Site" (id:1,bindings:http/*:80:,state:Stopped) Application pools: APPPOOL "DefaultAppPool" (MgdVersion:,MgdMode:Integrated,state:Started) Existing *:443 host bindings : 0 Manual backups : 2 Configuration history : enabled
Checkpoint: Existing server-wide ownership and conflicts are known
& $env:windir\system32\inetsrv\appcmd.exe list config -xml > .\evidence\iis-before.xml; Get-NetTCPConnection -State Listen -LocalPort 80,443 -ErrorAction SilentlyContinueContinue whenComplete features/config/binding/pool/cert/log/backup/dependency baseline and no unexplained target binding.
Stop whenAn existing site/service owns target binding/path, server changes are pending, backup scope is misunderstood, or unrelated site recovery is unavailable.
If this step fails
AppCmd is missing.
Likely causeIIS management tools are not installed or path is wrong.
Check Web-Mgmt-Tools feature and system inetsrv path.
ResolutionInstall only the approved management tools with the role change.
Another site uses the hostname/443.
Likely causeBinding design conflicts or duplicate service ownership exists.
Inspect site binding and HTTP.sys certificate mapping.
ResolutionCoordinate a unique binding/cutover; never overwrite it with Force.
Security notes
- IIS configuration exports can contain topology and protected configuration; restrict evidence.
Alternatives
- Use Microsoft.Web.Administration read-only inventory when AppCmd output integration is insufficient.
Stop conditions
- An existing site/service owns target binding/path, server changes are pending, backup scope is misunderstood, or unrelated site recovery is unavailable.
config
Install only required IIS role services and patch the host
Install Web Server, management tools, HTTP logging and only the application-required runtime/handler modules. Apply current Windows updates, reboot if required, and rescan installed features before creating the site.
Why this step matters
Each IIS role service adds code and configuration surface. Install only the contracted runtime/handlers; CGI, WebDAV, legacy authentication and FTP are not harmless defaults. Patch and complete any restart before exposure, then compare installed features with the approved list. A troubleshooting suggestion is not justification for an unrelated module.
What to understand
Map application runtime/handlers to exact Windows features.
Exclude unused legacy auth, CGI, WebDAV, FTP and directory browsing.
Install logging/request-monitoring required for operations.
Apply current security updates and complete restart before exposure.
Record installed feature delta and verify IIS/WAS service health.
System changes
- Installs IIS role services and may require patched-host restart.
Syntax explained
Web-Http-Logging- Adds W3C request logging required by the operations contract.
Web-Request-Monitor- Supports current-request inspection; it does not enable broad tracing automatically.
Install-WindowsFeature Web-Server,Web-Mgmt-Tools,Web-Http-Logging,Web-Request-Monitor -IncludeManagementTools; Get-WindowsFeature Web-* | Where Installed | Select Name,InstallStateSuccess Restart Needed Exit Code Feature Result
------- -------------- --------- --------------
True No Success {Web-Server, Web-Mgmt-Tools, Web-Http-Logging, Web-Request-Monitor}
Web-Server Installed
Web-Mgmt-Tools Installed
Web-Http-Logging Installed
Web-Request-Monitor InstalledCheckpoint: The IIS attack surface matches the application runtime
Get-WindowsFeature Web-* | Where Installed | Select Name; Get-Service W3SVC,WASContinue whenOnly approved features, current patches, no pending reboot and healthy WAS/W3SVC.
Stop whenRequired runtime is unsupported, unnecessary risky modules appear, update/reboot is pending, or core services are unhealthy.
If this step fails
Feature installation reports restart needed.
Likely causeComponent servicing requires reboot before stable testing.
Record installation result and pending reboot state.
ResolutionRestart in maintenance and repeat feature/service baseline.
Application later reports missing handler.
Likely causeRuntime-feature mapping was incomplete.
Use exact 500.19/handler/module error and application support matrix.
ResolutionInstall only the required supported module, then update recovery artifacts/tests.
Security notes
- Do not enable unused authentication schemes or handlers as troubleshooting shortcuts.
Alternatives
- Use Server Core where supported to reduce local UI/components while retaining managed IIS administration.
Stop conditions
- Required runtime is unsupported, unnecessary risky modules appear, update/reboot is pending, or core services are unhealthy.
verification
Validate the IIS server certificate and renewal ownership
Retrieve the exact LocalMachine certificate by thumbprint and validate SAN against the site FQDN, Server Authentication EKU, validity, trusted chain, revocation, private key presence/ACL and renewal/rebinding procedure.
Why this step matters
Select the certificate by recorded thumbprint and validate exact SAN FQDN, Server Authentication EKU, lifetime, chain, revocation and private key. SNI, DNS and the requested hostname must align. A renewed certificate has a new thumbprint, so plan rebinding and monitor the identity clients actually receive. Private keys remain inside enterprise PKI controls.
What to understand
Resolve the canonical hostname and authoritative TLS termination point.
Validate exact LocalMachine certificate SAN/EKU/time/chain/revocation.
Confirm protected private key association without exporting it.
Inventory any load balancer/origin certificate split.
Define expiry alert, renewal, rebind, client test and old-cert retirement.
System changes
- None; validates the already-issued certificate.
Syntax explained
Test-Certificate -Policy SSL- Checks certificate suitability/trust for SSL server use and requested DNS name.
SNI hostname- Name sent during TLS handshake and used to select the certificate binding.
Values stay on this page and are never sent or saved.
$cert=Get-Item Cert:\LocalMachine\My\{{certificateThumbprint}}; $cert | Select Subject,DnsNameList,NotBefore,NotAfter,Thumbprint,HasPrivateKey,EnhancedKeyUsageList; Test-Certificate -Cert $cert -Policy SSL -DNSName {{siteHostName}}Subject : CN=portal.corp.example
DnsNameList : {portal.corp.example}
NotAfter : 7/01/2027 00:00:00
Thumbprint : 34A6BC2B56DC4CF8BFB741415A9D7C76B6D82031
HasPrivateKey : True
EKU : Server Authentication
Test-Certificate : True
Renewal owner : Enterprise PKI automationCheckpoint: The certificate proves the intended site identity
Test-Certificate -Cert (Get-Item Cert:\LocalMachine\My\{{certificateThumbprint}}) -Policy SSL -DNSName {{siteHostName}}Continue whenTrue validation, exact SAN/EKU, trusted current revocation, protected key and owned renewal/rebind.
Stop whenAny identity/trust/revocation/private-key test fails, certificate is self-signed for production, or renewal is unowned.
If this step fails
Certificate validates locally but clients reject it.
Likely causeClient trust/revocation or requested name differs.
Inspect client-observed chain and exact URL/DNS path.
ResolutionCorrect trust/DNS/certificate through PKI; never use skip-validation flags.
Private key is missing.
Likely causeOnly public certificate was imported or enrollment failed.
Inspect enterprise enrollment/key provider status.
ResolutionEnroll correctly on the server or approved key provider; do not copy an unprotected key.
Security notes
- Do not export private keys or passwords into deployment commands/output.
Alternatives
- Terminate TLS at a managed load balancer only when origin authentication/encryption and client identity are explicitly designed.
Stop conditions
- Any identity/trust/revocation/private-key test fails, certificate is self-signed for production, or renewal is unowned.
config
Create immutable content and narrowly writable application data
Create separate content and data directories, deploy a versioned release to the content path under administrator ownership, remove inherited broad write access, and grant the future pool identity read/execute on content plus Modify only on the data path.
Why this step matters
A worker that can modify binaries, scripts, web.config or static content can persist compromise. Deploy immutable content, place uploads/cache/state outside the web root and ACL the exact `IIS AppPool\PoolName` identity. Preserve SYSTEM/administrator and required deployment/backup access, test content writes are denied, and keep secrets in an approved provider.
What to understand
Create versioned content and separate writable data/cache/upload locations.
Deploy content with administrator/SYSTEM ownership and integrity hash.
Grant the exact pool virtual identity RX on content.
Grant Modify only on declared data path, not parent/web root.
Test deployment, backup and security-agent access after inheritance changes.
System changes
- Creates site directories, deploys content and replaces NTFS ACL inheritance with explicit least privilege.
Syntax explained
(OI)(CI)(RX)- Inherits read/execute to content files and subdirectories without write.
(OI)(CI)(M)- Allows controlled create/change/delete under the dedicated data path.
/grant:r- Replaces existing explicit grant for the named trustee; review all resulting ACLs.
Values stay on this page and are never sent or saved.
New-Item -ItemType Directory -Path {{contentPath}},{{dataPath}} -Force | Out-Null; icacls {{contentPath}} /inheritance:r /grant:r 'Administrators:(OI)(CI)(F)' 'SYSTEM:(OI)(CI)(F)' 'IIS AppPool\{{appPoolName}}:(OI)(CI)(RX)'; icacls {{dataPath}} /inheritance:r /grant:r 'Administrators:(OI)(CI)(F)' 'SYSTEM:(OI)(CI)(F)' 'IIS AppPool\{{appPoolName}}:(OI)(CI)(M)'D:\Web\AcmePortal\current BUILTIN\Administrators:(OI)(CI)(F) NT AUTHORITY\SYSTEM:(OI)(CI)(F) IIS AppPool\AcmePortal-v1:(OI)(CI)(RX) D:\WebData\AcmePortal BUILTIN\Administrators:(OI)(CI)(F) NT AUTHORITY\SYSTEM:(OI)(CI)(F) IIS AppPool\AcmePortal-v1:(OI)(CI)(M) Successfully processed 2 files; Failed processing 0 files
Checkpoint: Worker can read code and write only runtime data
icacls {{contentPath}}; icacls {{dataPath}}; Get-FileHash (Join-Path {{contentPath}} 'app.dll')Continue whenRoot/admin-owned hashed content, pool RX only there, pool Modify only on exact data path and no broad inherited write.
Stop whenPool needs content/config write, ACL removes recovery/backup access, broad groups retain write, or data resides under executable web root.
If this step fails
Site returns access denied after deployment.
Likely causeTraverse/read ACL on path parents or content is incomplete.
Use effective access and ProcMon/application/IIS substatus without broad grants.
ResolutionGrant the exact pool identity minimum traverse/read on the exact path.
Application requires web.config write.
Likely causeRuntime design modifies deployment configuration.
Identify the exact mutable setting and supported external location.
ResolutionMove state to protected data/config service; do not grant web-root Modify.
Security notes
- Never use Everyone/Users/IIS_IUSRS Full Control as a repair.
Alternatives
- Use a deployment service account to publish immutable releases while the worker remains read-only.
Stop conditions
- Pool needs content/config write, ACL removes recovery/backup access, broad groups retain write, or data resides under executable web root.
config
Create a dedicated application pool and stopped HTTPS site
Create a unique application pool using ApplicationPoolIdentity and the application-required runtime, then create the site with the exact content path and SNI HTTPS binding metadata. Keep the site stopped until certificate, logging and configuration validation complete.
Why this step matters
A dedicated pool provides a distinct virtual identity, process lifecycle and failure boundary. Do not reuse DefaultAppPool or run as LocalSystem. Select managed runtime based on the application: an out-of-process or modern application often uses no managed CLR in the IIS pool, while classic ASP.NET Framework requires the supported CLR. The example shows an integrated, no-managed-runtime fixture and must be changed only by the application contract. Create a unique SNI hostname binding but keep the site stopped until the certificate is associated; an HTTPS binding record without a certificate is not a working TLS service. Verify no duplicate host/port binding and record the assigned site ID.
What to understand
Create one versioned pool per security/lifecycle boundary.
Set ApplicationPoolIdentity and exact runtime/pipeline requirements.
Create the site with exact path and SNI HTTPS host binding.
Stop it before network exposure and certificate association.
Inspect site ID, applications, virtual directories, pool and duplicate bindings.
System changes
- Creates an IIS application pool and stopped site with HTTPS binding metadata.
Syntax explained
ApplicationPoolIdentity- Runs the worker under the unique virtual account used in NTFS ACLs.
SslFlags 1- Enables SNI for the HTTPS binding so hostname participates in certificate selection.
Integrated pipeline- Uses the integrated IIS request pipeline; runtime support must match the application.
Values stay on this page and are never sent or saved.
Import-Module WebAdministration; New-WebAppPool -Name {{appPoolName}}; Set-ItemProperty IIS:\AppPools\{{appPoolName}} -Name processModel.identityType -Value ApplicationPoolIdentity; New-Website -Name {{siteName}} -PhysicalPath {{contentPath}} -ApplicationPool {{appPoolName}} -Port 443 -HostHeader {{siteHostName}} -Ssl -SslFlags 1; Stop-Website {{siteName}}Name : AcmePortal-v1 State : Stopped IdentityType : ApplicationPoolIdentity ManagedRuntime : PipelineMode : Integrated Site : AcmePortal State : Stopped PhysicalPath : D:\Web\AcmePortal\current Binding : https *:443:portal.corp.example SslFlags : 1 (SNI)
Checkpoint: The stopped site and pool match the declared runtime boundary
Get-Item IIS:\AppPools\{{appPoolName}} | Select Name,State,managedRuntimeVersion,managedPipelineMode; Get-Website -Name {{siteName}} | Select Name,Id,State,PhysicalPath,BindingsContinue whenUnique stopped site/pool, exact path/FQDN/443/SNI, ApplicationPoolIdentity and reviewed runtime.
Stop whenBinding duplicates another site, pool identity/runtime is wrong, content path differs, or site starts before certificate/logging validation.
If this step fails
New-Website reports duplicate binding.
Likely causeAnother site owns the same IP/port/host tuple.
List all site bindings and intended cutover ownership.
ResolutionChoose or migrate to a unique binding; never overwrite the other site.
Pool requires SpecificUser credentials.
Likely causeApplication accesses a remote resource or assumes a legacy identity.
Map exact local/network rights and supported identity options.
ResolutionPrefer ApplicationPoolIdentity or reviewed gMSA; never put a password in scripts.
Security notes
- Do not use LocalSystem or broad shared pools.
Alternatives
- Use a reviewed gMSA pool identity only for necessary remote resource access with narrow rights.
Stop conditions
- Binding duplicates another site, pool identity/runtime is wrong, content path differs, or site starts before certificate/logging validation.
config
Associate the SNI certificate and require HTTPS
Associate the validated LocalMachine certificate with the exact IIS SNI binding, require SSL at the site configuration level, confirm no unintended public HTTP binding exists, and inspect the effective binding/certificate before starting.
Why this step matters
The IIS site binding maps HTTPS requests to the site, while the SSL binding maps the IP/port/hostname to a certificate. Both must agree. SNI permits multiple certificates on one IP/443 but clients must send the intended hostname. Associate only the previously validated thumbprint and re-read effective binding; never choose a certificate by friendly name. `sslFlags=Ssl` rejects plaintext access at the IIS application layer, but the safest production design also omits an external HTTP binding unless an explicitly reviewed redirect site is used. If a load balancer terminates TLS, define whether origin TLS and host header validation remain required rather than silently accepting plaintext.
What to understand
Confirm the stopped site's HTTPS SNI binding is unique.
Associate the exact validated certificate thumbprint/store.
Require SSL in the site's access configuration.
Remove or avoid unintended HTTP production binding.
Inspect HTTP.sys/IIS effective certificate and plan renewal rebind.
System changes
- Binds the certificate to HTTPS/SNI and requires SSL for the site.
Syntax explained
Get-WebBinding ... -HostHeader hostname- Selects the one reviewed wildcard-IP, port 443 and SNI hostname binding before changing its certificate.
AddSslCertificate(thumbprint, 'My')- Associates the exact certificate thumbprint from LocalMachine\My with that HTTPS binding.
sslFlags Ssl- Requires SSL for requests reaching this IIS site/application.
Values stay on this page and are never sent or saved.
Import-Module WebAdministration; $binding=Get-WebBinding -Name {{siteName}} -Protocol https -Port 443 -HostHeader {{siteHostName}}; if (@($binding).Count -ne 1) { throw 'Expected exactly one reviewed HTTPS binding' }; $binding.AddSslCertificate('{{certificateThumbprint}}','My'); Set-WebConfigurationProperty -PSPath IIS:\ -Location {{siteName}} -Filter 'system.webServer/security/access' -Name sslFlags -Value SslIP Address : * Port : 443 Host Name : portal.corp.example SSL Flags : SNI Thumbprint : 34A6BC2B56DC4CF8BFB741415A9D7C76B6D82031 Store : MY Site access : sslFlags="Ssl" HTTP binding: none
Checkpoint: The site has one valid HTTPS identity and no plaintext exposure
Get-WebBinding -Name {{siteName}}; netsh http show sslcert hostnameport={{siteHostName}}:443Continue whenExact host/443/SNI, expected thumbprint, SSL required and no unintended HTTP/other-site conflict.
Stop whenThumbprint/name differs, binding collision exists, plaintext is exposed, or certificate validation/renewal is incomplete.
If this step fails
Client receives another site's certificate.
Likely causeSNI host, binding uniqueness or client hostname is wrong.
Inspect ClientHello hostname and every *:443 binding/certificate.
ResolutionCorrect exact host binding/certificate and DNS; never bypass name validation.
IIS returns 403.4 SSL required.
Likely causeRequest arrived over HTTP or upstream origin protocol is wrong.
Trace client/load-balancer scheme, listener and host header.
ResolutionUse HTTPS end to end or a separately reviewed redirect/termination design.
Security notes
- Do not use certificate-validation bypass or public plaintext origin traffic.
Alternatives
- Use a dedicated redirect-only HTTP site with no application content when explicit HTTP-to-HTTPS redirection is required.
Stop conditions
- Thumbprint/name differs, binding collision exists, plaintext is exposed, or certificate validation/renewal is incomplete.
config
Configure privacy-aware W3C request logging and capacity
Configure the site for enabled W3C file logging in a protected capacity-isolated path, UTC rollover and diagnostic fields including status, substatus, Win32 status and time taken. Omit URI query by default and verify ACL, retention and forwarding.
Why this step matters
W3C method, URI stem, status/substatus, Win32 status and UTC time taken make failures actionable. Exclude UriQuery because URLs often leak tokens or personal data. Use protected monitored capacity and privacy-aware forwarding/retention. A missing line requires checking site ID, routing, buffering, ACL and disk—not enabling every field.
What to understand
Use W3C with UTC timestamps and stable site-specific path.
Include status, substatus, Win32 status and time taken.
Omit query strings and review referer/user-agent privacy.
Restrict ACL, monitor free space/flush/rotation and define retention.
Forward logs and alert on gaps, 5xx, latency and write failures.
System changes
- Changes site logging path/format/timestamp settings and operational retention/forwarding expectations.
Syntax explained
W3C- Customizable IIS request log format with UTC record timestamps.
HttpSubStatus / Win32Status- Adds IIS/native failure detail needed to distinguish authorization, file and network errors.
TimeTaken- Records IIS server-side request duration in milliseconds, excluding network time.
Values stay on this page and are never sent or saved.
Set-ItemProperty IIS:\Sites\{{siteName}} -Name logFile.directory -Value {{logPath}}; Set-ItemProperty IIS:\Sites\{{siteName}} -Name logFile.logFormat -Value W3C; Set-ItemProperty IIS:\Sites\{{siteName}} -Name logFile.localTimeRollover -Value $falseenabled : True logFormat : W3C directory : E:\IISLogs localTimeRollover : False fields : Date,Time,ClientIP,UserName,ServerIP,Method,UriStem,HttpStatus,Win32Status,ServerPort,UserAgent,HttpSubStatus,Referer,TimeTaken UriQuery : omitted free space : 412 GB forwarding : healthy
Checkpoint: Requests are diagnosable without routine query-string collection
Get-ItemProperty IIS:\Sites\{{siteName}} -Name logFile.*; Get-Acl {{logPath}} | Format-List; Get-Volume -FilePath {{logPath}}Continue whenEnabled W3C/UTC diagnostic fields, no UriQuery, protected writable path, safe capacity/retention and healthy forwarding.
Stop whenLog directory is worker/user-writable beyond append needs, query logging lacks approval, capacity/retention/forwarding is unsafe, or another site shares ambiguous logs.
If this step fails
No log file appears after request.
Likely causeSite has not started/received request, site ID/path/ACL/buffering is wrong.
Check binding/site ID, request response, effective log config, ACL/free space and events.
ResolutionRepair exact routing/log path and treat missing interval as evidence gap.
Logs contain secrets in URI.
Likely causeApplication/client placed credentials or tokens in path/query.
Stop external distribution and identify every retained/forwarded copy.
ResolutionRemove secrets from URLs, rotate exposed credentials and apply privacy incident procedure.
Security notes
- Logs are sensitive evidence; the application pool should not be able to alter historical files.
Alternatives
- Add privacy-reviewed custom fields or application structured logs for correlation IDs instead of collecting query data.
Stop conditions
- Log directory is worker/user-writable beyond append needs, query logging lacks approval, capacity/retention/forwarding is unsafe, or another site shares ambiguous logs.
config
Configure application-pool health, startup, and recycling deliberately
Set the dedicated pool's identity/runtime/start mode and rapid-fail behavior according to the application SLO. Avoid arbitrary scheduled recycles; if a recycle is required, make it observable, overlap-safe and tested under load.
Why this step matters
Rapid-fail protection bounds crash loops, but its resulting 503 requires alerting and diagnosis. Scheduled recycling is not a universal memory fix; it can hide leaks and disrupt state. Keep ApplicationPoolIdentity and choose queue, idle, startup and recycle behavior from workload measurements. Start only after pool failure/recovery signals exist.
What to understand
Confirm exact pool identity, runtime and pipeline.
Keep rapid-fail protection with monitored thresholds.
Remove arbitrary recycle schedules unless the application owner requires and tests them.
Measure queue, startup, overlap, memory and dependency behavior.
Alert on stopped pool, rapid-fail, worker crashes/recycles and 503s.
System changes
- Changes/validates application-pool health and lifecycle settings.
Syntax explained
rapidFailProtection- Stops the pool after repeated worker failures in the configured interval.
periodicRestart.time 00:00:00- Disables elapsed-time recycling in this reviewed fixture; use workload-specific policy.
Values stay on this page and are never sent or saved.
Set-ItemProperty IIS:\AppPools\{{appPoolName}} -Name processModel.identityType -Value ApplicationPoolIdentity; Set-ItemProperty IIS:\AppPools\{{appPoolName}} -Name failure.rapidFailProtection -Value $true; Get-ItemProperty IIS:\AppPools\{{appPoolName}} | Select Name,state,processModel,failure,recyclingName : AcmePortal-v1 IdentityType : ApplicationPoolIdentity RapidFailProtection : True Failures : 5 Interval : 00:05:00 Periodic restart : 00:00:00 Specific recycle time: none State : Stopped
Checkpoint: Pool failures are bounded, observable, and not hidden by recycling
Get-WebAppPoolState {{appPoolName}}; & $env:windir\system32\inetsrv\appcmd.exe list apppool {{appPoolName}} /text:*Continue whenDedicated identity/runtime, rapid-fail alerting, no unexplained scheduled recycle and measured queue/startup behavior.
Stop whenPool runs privileged/shared, recycle hides instability, rapid-fail alerts/recovery are missing, or tuning is copied without load evidence.
If this step fails
Pool stops repeatedly.
Likely causeApplication crashes/startup/configuration/dependency failure triggers rapid-fail protection.
Inspect WAS/Application events, crash dumps and application logs before restart loops.
ResolutionFix the application/dependency and validate on staging; do not disable rapid-fail blindly.
Recycle causes request errors.
Likely causeApplication is not overlap-safe, startup is slow or in-memory state is lost.
Correlate recycle events, worker overlap, health and request logs.
ResolutionRemove unnecessary recycle or implement graceful external state/warm-up before scheduling.
Security notes
- Do not change identity to LocalSystem to diagnose file or dependency errors.
Alternatives
- Use application-level health/restart orchestration when IIS pool controls cannot express the workload lifecycle safely.
Stop conditions
- Pool runs privileged/shared, recycle hides instability, rapid-fail alerts/recovery are missing, or tuning is copied without load evidence.
verification
Create a labeled predeployment IIS configuration backup and recovery manifest
Create an AppCmd backup with a unique UTC name, list and hash its files, and create a manifest that explicitly lists separate content, data, certificate/PKI, secrets and dependency backups plus their restore owners. Do not claim completeness yet.
Why this step matters
AppCmd captures IIS server configuration, not the complete website. Content, writable data, certificate/reissuance, secrets and external services need separate protected recovery. Label and hash the configuration-only backup, note that restore is server-wide, and link every layer to its consistency method, owner and RPO/RTO. Only an isolated restore test makes the set verified.
What to understand
Create a unique timestamped AppCmd configuration backup.
List files, hash and copy backup to protected off-host storage.
Record all sites/pools covered because restore is server-wide.
Map content, state, PKI/secrets and dependency backups separately.
Mark the recovery set unverified until isolated restore acceptance.
System changes
- Creates an IIS server-configuration backup and recovery manifest.
Syntax explained
appcmd add backup- Captures IIS global configuration, not application content/data/certificates.
iisBackupName- Unique revision identifier used for listing and controlled restore.
Values stay on this page and are never sent or saved.
& $env:windir\system32\inetsrv\appcmd.exe add backup {{iisBackupName}}; & $env:windir\system32\inetsrv\appcmd.exe list backup {{iisBackupName}}; Get-ChildItem (Join-Path $env:windir 'system32\inetsrv\backup\{{iisBackupName}}') -Recurse | Get-FileHashBACKUP object "{{iisBackupName}}" added
BACKUP "{{iisBackupName}}"
ApplicationHost.config SHA256 7A9B...
administration.config SHA256 12C4...
redirection.config SHA256 42DF...
Scope: IIS server configuration only
Content artifact: pending verified copy
Application data: pending application-consistent backup
Certificate identity: enterprise PKI reissue/escrow procedure
Restore-test status: NOT YET VERIFIEDCheckpoint: Every required recovery layer is explicit and honestly labeled
& $env:windir\system32\inetsrv\appcmd.exe list backup {{iisBackupName}}; Get-Content .\recovery\AcmePortal-manifest.json | ConvertFrom-Json | Format-ListContinue whenProtected hashed config backup plus complete layer manifest, owners/RPO/RTO and `restore-test status: pending`.
Stop whenBackup name collides, files cannot be protected, manifest omits data/certificate/secrets/dependencies, or anyone labels it complete before restore.
If this step fails
AppCmd backup completes but directory is empty/inaccessible.
Likely causePath, permissions, storage or command context is wrong.
List exact backup object/path and inspect ACL/events.
ResolutionRepair protected configuration backup and create a new unique revision.
Certificate recovery has no approved path.
Likely causePrivate key is nonexportable without PKI reissuance/escrow plan.
Review enterprise PKI template, enrollment and disaster recovery.
ResolutionDefine tested reissuance or protected key recovery without exposing passwords.
Security notes
- Backup configuration may contain sensitive paths/settings; restrict and integrity-protect it.
- Never include plaintext private-key or application secret passwords in the manifest.
Alternatives
- Use enterprise configuration management as an additional rebuild source, still testing complete application recovery.
Stop conditions
- Backup name collides, files cannot be protected, manifest omits data/certificate/secrets/dependencies, or anyone labels it complete before restore.
verification
Start the site and verify TLS, application, ACL, and logging paths
Start the pool/site, make local and external requests by canonical FQDN with normal certificate validation, verify health/content/headers/status/latency and W3C entry, then prove the pool can write data but cannot modify content or configuration.
Why this step matters
Start only after the binding, certificate, ACL, logs and recovery artifacts exist. Request by canonical FQDN so SNI and certificate validation are exercised; a localhost/IP test cannot prove public identity. Use curl without `-k` or PowerShell without SkipCertificateCheck. Verify expected application version and response, then correlate the W3C line's method/path/status/substatus/Win32 status/time. Test from an external approved path and a wrong hostname. Run the app's bounded data-write fixture and a negative content-write fixture under the pool identity; the former must pass and the latter fail. Inspect worker/pool identity and application/system events.
What to understand
Start the dedicated pool/site and confirm worker identity.
Request health by FQDN locally and externally with full TLS validation.
Verify expected version, headers, status and latency.
Find the matching W3C line and application correlation event.
Prove data write succeeds and content/config write fails.
System changes
- Starts the site/pool, serves test requests and creates bounded application data/log fixtures.
Syntax explained
curl --fail --show-error- Fails on HTTP errors and shows diagnostic errors while retaining normal TLS validation.
canonical FQDN- Exercises DNS, SNI, certificate SAN and site host binding together.
Values stay on this page and are never sent or saved.
Start-WebAppPool {{appPoolName}}; Start-Website {{siteName}}; curl.exe --fail --show-error --verbose https://{{siteHostName}}/health* Server certificate:
* subject: CN=portal.corp.example
* SSL certificate verify ok.
> GET /health HTTP/1.1
> Host: portal.corp.example
< HTTP/1.1 200 OK
< Content-Type: application/json
{"status":"ok","version":"2026.07.28.1"}
W3C: 2026-07-28 14:02:18 10.20.30.15 GET /health - 443 - 10.20.30.42 curl/8.14.1 - 200 0 0 37Checkpoint: The real HTTPS path, identity boundary, and evidence all work
.\tests\Test-AcmePortal.ps1 -Uri https://{{siteHostName}} -ExpectedVersion 2026.07.28.1 -RequireValidCertificate -RequireLogs -RequireAclNegativesContinue whenValid certificate/200 health/version, correct pool identity, data-only write, denied content write and correlated W3C/application evidence.
Stop whenTLS needs bypass, wrong site/certificate answers, health/version fails, worker is privileged, content write succeeds, or logs are missing.
If this step fails
503 response.
Likely causePool stopped, rapid-fail triggered or startup/dependency failed.
Inspect pool state, WAS/Application events and app startup logs.
ResolutionStop traffic, fix the exact startup/identity/dependency problem and retest.
200 response has wrong content.
Likely causeSNI/host binding, load balancer or deployment path selects another site/release.
Inspect response certificate/host, site binding and physical path/version.
ResolutionCorrect routing/binding/deployment before any traffic.
Security notes
- Never use TLS bypass to turn a failed identity test green.
Alternatives
- Use a synthetic monitoring agent from each network path after the same manual acceptance passes.
Stop conditions
- TLS needs bypass, wrong site/certificate answers, health/version fails, worker is privileged, content write succeeds, or logs are missing.
verification
Exercise failures and prove status, substatus, and pool diagnostics
Generate safe 404, denied-path and bounded application-error fixtures, then correlate W3C status/substatus/Win32/time with application/WAS events and health. Enable Failed Request Tracing only temporarily for a defined condition and protect its sensitive output.
Why this step matters
Operational readiness requires evidence for failures, not only a 200 response. A safe missing URL should produce 404 with substatus/Win32 fields; a controlled application fixture can produce a scrubbed 500 with correlation ID; a forbidden write should fail. Correlate the exact UTC time across W3C, application and WAS events and confirm the pool remains stable. Failed Request Tracing can capture detailed headers/module activity and potentially sensitive data, so enable it only for a narrow status/path/time window, protect output and disable it after collection. Do not generate authentication attacks or crash loops on production to test logging.
What to understand
Generate bounded 404, application error and ACL-denial fixtures.
Map each to W3C status/substatus/Win32/time taken and application correlation.
Verify pool/worker remains healthy and no rapid-fail event occurs.
Use narrow temporary Failed Request Tracing only if normal evidence is insufficient.
Verify forwarding/alerts and remove sensitive trace fixtures according to retention.
System changes
- Generates bounded failed requests and diagnostic evidence; optional tracing is temporary and scoped.
Syntax explained
HttpSubStatus- Refines the IIS status category for authorization/configuration/routing diagnosis.
Win32Status- Provides the underlying Windows result code for native failures.
Failed Request Tracing- Detailed per-request module trace used only under a narrow protected diagnostic plan.
Values stay on this page and are never sent or saved.
curl.exe --fail --show-error https://{{siteHostName}}/missing-fixture; Get-Content (Get-ChildItem {{logPath}} -Recurse -Filter 'u_ex*.log' | Sort LastWriteTime -Descending | Select -First 1).FullName -Tail 20curl: (22) The requested URL returned error: 404 2026-07-28 14:10:04 10.20.30.15 GET /missing-fixture - 443 - 10.20.30.42 curl/8.14.1 - 404 0 2 11 Denied content write fixture : ACCESS DENIED (expected) Application 500 fixture : 500.0 / correlation id 5d36... WAS crash/recycle events : none Log forwarding lag : 3.1 seconds
Checkpoint: Common failures are diagnosable without broad tracing or data collection
.\tests\Test-IISFailureEvidence.ps1 -SiteName {{siteName}} -LogRoot {{logPath}}Continue whenExpected 404/500/ACL failures, correlated fields/events/alerts, stable pool and no persistent broad tracing.
Stop whenLogs expose secrets, failure cannot be correlated, pool destabilizes, tracing is broad/unprotected, or alerts/forwarding fail.
If this step fails
W3C has status but no matching app event.
Likely causeApplication logging/correlation is missing or clocks differ.
Check UTC time, correlation middleware and application log forwarding.
ResolutionAdd scrubbed correlation and repeat the bounded fixture.
Failed Request Tracing captures authorization headers.
Likely causeTrace scope/data handling was not privacy-safe.
Stop trace, restrict access and identify forwarded/copied artifacts.
ResolutionInvoke sensitive-data procedure and redesign narrow capture/redaction.
Security notes
- Diagnostic traces may be more sensitive than W3C logs; minimize, protect and retain deliberately.
Alternatives
- Prefer application structured diagnostics and W3C fields before enabling Failed Request Tracing.
Stop conditions
- Logs expose secrets, failure cannot be correlated, pool destabilizes, tracing is broad/unprotected, or alerts/forwarding fail.
config
Create application-consistent content, data, and dependency recovery artifacts
Back up the immutable release by hash, create an application-consistent backup of writable data, record the PKI certificate reissue/key-recovery path and external dependency versions. Keep secrets in the approved vault/backup system, never in commands or the manifest.
Why this step matters
The configuration backup cannot recover content or application data. Immutable releases are best recovered from signed build artifacts, with file hashes proving the version. Writable data needs an application-consistent mechanism; copying open files may produce a corrupt state even when every file exists. External databases, queues and storage require their own backup IDs and restore order. Certificate recovery may use enterprise reissuance instead of exporting a private key, while secrets remain in the approved vault/escrow—not command lines or manifests. Record dependency versions and restore sequence. This step creates artifacts but still does not declare success until an isolated host restores and serves them.
What to understand
Retain signed/versioned content artifact and complete file hashes.
Quiesce or use supported application-consistent data backup.
Record external database/service backup IDs and restore order.
Use enterprise PKI reissue or protected key recovery without plaintext passwords.
Reference secret-vault recovery policy without exporting secret values.
System changes
- Creates protected content, data and dependency recovery artifacts; may briefly quiesce bounded application writes.
Syntax explained
application-consistent- Backup represents a recoverable transaction/state boundary rather than an arbitrary open-file copy.
content hash manifest- Proves exact immutable release files restored later.
Values stay on this page and are never sent or saved.
Get-ChildItem {{contentPath}} -Recurse -File | Get-FileHash -Algorithm SHA256 | Export-Clixml .\recovery\content-hashes.xml; & .\backup\Invoke-AcmePortalDataBackup.ps1 -DataPath {{dataPath}} -DestinationId 'protected-backup-set'Content release : 2026.07.28.1 Content files hashed : 184 Data backup ID : acme-data-20260728T1415Z Consistency checkpoint: PASS PKI recovery method : enterprise certificate reissue Secrets recovery : vault policy ACME-WEB-PROD Dependency manifest : complete Restore status : pending isolated test
Checkpoint: Every non-IIS layer has a recoverable protected artifact
Get-Content .\recovery\AcmePortal-manifest.json | ConvertFrom-Json | Select Content,Data,Pki,Secrets,DependenciesContinue whenVersioned hashed content, consistent data backup, PKI/secrets/dependency paths, owners/RPO/RTO and restore still marked pending.
Stop whenData copy is crash-inconsistent, secret/private-key appears in output, dependency backup ID is missing, or artifacts are not protected/off-host.
If this step fails
Backup agent cannot quiesce data.
Likely causeApplication lacks supported consistency hook or writers remain active.
Inspect application/backup provider consistency status.
ResolutionUse supported snapshot/database backup or planned maintenance; do not label raw copy recoverable.
Content hashes change after backup.
Likely causeRelease mutated in place or collection raced deployment.
Compare deployment artifact, filesystem writers and timestamps.
ResolutionStop deployment, restore immutable release discipline and create a stable new backup.
Security notes
- No secrets, private-key passwords or connection strings appear in scripts/output/manifests.
Alternatives
- Rebuild immutable content from a signed artifact repository while backing up only state, still proving the restore workflow.
Stop conditions
- Data copy is crash-inconsistent, secret/private-key appears in output, dependency backup ID is missing, or artifacts are not protected/off-host.
verification
Restore the complete website on an isolated Windows Server 2025 host
On the isolated restore host, verify the intended IIS configuration backup, restore it only there, recover exact content/data/dependencies and certificate identity, update nonproduction DNS/host mapping safely, then run TLS, health, state, pool identity, ACL and logging tests.
Why this step matters
`appcmd restore backup` replaces server-wide IIS configuration, so run it only on a confirmed isolated host. Restore exact configuration, signed content, consistent data, secrets through the approved provider, dependencies and certificate identity. Use isolated name resolution, repeat TLS/application/ACL/log checks, compare state/hash/version and measure RPO/RTO. Only this reconstruction makes the recovery set verified.
What to understand
Prove the target is the isolated restore host with no production bindings/traffic.
Copy and verify the exact AppCmd backup, then restore server configuration there.
Restore content hashes, data checkpoint, secrets/PKI and external dependencies in order.
Use isolated name resolution and valid test certificate identity without bypass.
Run health/version/state, pool identity, negative ACL, W3C and forwarding tests; measure RTO/RPO.
System changes
- Replaces IIS server configuration and restores complete application layers on the isolated recovery host only.
Syntax explained
appcmd restore backup- Server-wide IIS configuration restore; destructive to current restore-host IIS state.
isolated restore host- Prevents the test from overwriting or receiving production service traffic.
Values stay on this page and are never sent or saved.
$session=New-PSSession -ComputerName {{restoreHost}}; try { $source=Join-Path $env:windir 'system32\inetsrv\backup\{{iisBackupName}}'; if (-not (Test-Path $source)) { throw 'Reviewed IIS backup is missing on the source host' }; Invoke-Command -Session $session -ScriptBlock { New-Item -ItemType Directory -Path (Join-Path $env:windir 'system32\inetsrv\backup') -Force | Out-Null }; Copy-Item -Path $source -Destination (Join-Path $env:windir 'system32\inetsrv\backup') -ToSession $session -Recurse -Force; Invoke-Command -Session $session -ScriptBlock { & $env:windir\system32\inetsrv\appcmd.exe list backup '{{iisBackupName}}'; & $env:windir\system32\inetsrv\appcmd.exe restore backup '{{iisBackupName}}' } } finally { if ($session) { Remove-PSSession $session } }Restore host : WS25-IIS-RESTORE-01 Network isolation : verified IIS config backup : restored Content hash match : 184 / 184 Data consistency check : PASS Certificate identity : valid restore-test certificate/reissue Pool identity/ACL : PASS HTTPS health/version : PASS / 2026.07.28.1 W3C log/forwarding : PASS Measured RTO : 43 minutes Verified backup : YES
Checkpoint: The recovery set reconstructs the actual secure service
.\tests\Test-AcmePortalRestore.ps1 -ComputerName {{restoreHost}} -ExpectedVersion 2026.07.28.1 -RequireTls -RequireData -RequireLogs -RequireAclNegativesContinue whenExact config/content/data/identity/dependencies, valid TLS, healthy app, correct pool/ACL/logs and RPO/RTO within objective.
Stop whenTarget could be production, backup ID/version is ambiguous, content/data/certificate/dependency differs, TLS needs bypass, or any acceptance test fails.
If this step fails
Restore overwrites unrelated test sites.
Likely causeAppCmd configuration backup is server-wide as documented.
Compare pre-restore restore-host inventory and backup contents.
ResolutionRebuild the dedicated restore host and isolate recovery tests from shared IIS servers.
Application starts with empty/stale data.
Likely causeData backup/restore order or consistency point is wrong.
Compare backup ID, transaction/checkpoint and dependency restore timestamps.
ResolutionCorrect application-consistent backup/restore and rerun the full drill.
Security notes
- Never run the shown restore command against production as a test.
- Use a valid isolated certificate/name path; no SkipCertificateCheck or `curl -k`.
Alternatives
- Restore an isolated VM clone when a dedicated recovery host is not persistent, ensuring network and identity isolation.
Stop conditions
- Target could be production, backup ID/version is ambiguous, content/data/certificate/dependency differs, TLS needs bypass, or any acceptance test fails.
decision
Operate the site, renew identity, and rehearse known-good rollback
Monitor certificate expiry and client-observed identity, binding/pool/worker state, W3C gaps/5xx/latency, application events, disk and restore-test age. Rehearse a version rollback using immutable content plus configuration/data compatibility—not an untested server-wide restore.
Why this step matters
Production assurance decays as certificates, OS/runtime modules, application releases, dependencies and recovery artifacts change. Monitor the certificate clients actually receive and alert before renewal, then validate/rebind a new thumbprint on a canary before retiring the old certificate. Track binding/site/pool/worker state, crash/recycle/rapid-fail, W3C continuity, status/substatus/Win32, latency, disk and forwarding. A routine application rollback should switch to a known-good immutable release and compatible data/config plan, not restore all IIS configuration over unrelated sites. Server-wide AppCmd restore is reserved for actual configuration recovery under full change control. Repeat isolated restore drills after material changes and on a fixed cadence.
What to understand
Monitor DNS/SNI/certificate expiry, chain/revocation and client-observed thumbprint.
Alert on binding drift, pool stop/crash/recycle, 503/5xx and log/forwarding gaps.
Keep immutable releases and document data/schema compatibility for rollback.
Rebind renewed certificate only after full validation and external tests.
Repeat restore drill and negative ACL/log tests after material change.
System changes
- None during normal review; rollback rehearsal may switch a canary to a prior immutable release.
Syntax explained
application rollback- Returns site content/config/data compatibility to a known-good release without overwriting unrelated IIS server config.
server config restore- Recovers damaged IIS global configuration and requires full server change control.
Values stay on this page and are never sent or saved.
& $env:windir\system32\inetsrv\appcmd.exe list site {{siteName}}; & $env:windir\system32\inetsrv\appcmd.exe list apppool {{appPoolName}}; curl.exe --fail --show-error https://{{siteHostName}}/healthSite : Started Pool : Started Worker identity : IIS AppPoolAcmePortal-v1 Certificate days left : 338 Observed cert match : True 5xx rate : 0.02% Log gap : 0 Restore test age : 0 days Rollback rehearsal : PASS Next review : 2026-10-28
Checkpoint: Identity, service, evidence, and recovery remain current
.\tests\Test-AcmePortalOperations.ps1 -SiteName {{siteName}} -Uri https://{{siteHostName}} -RestoreEvidence .\recovery\latest.jsonContinue whenHealthy TLS/site/pool/app/logs, no drift/gaps, current verified recovery and a successful bounded rollback rehearsal.
Stop whenCertificate nears expiry/untrusted, binding/pool/logs drift, 5xx/latency breaches, backup lacks recent restore test, or rollback/data compatibility is unknown.
If this step fails
Renewed certificate is installed but old one is served.
Likely causeSNI binding still references the old thumbprint or another termination point serves TLS.
Compare IIS/HTTP.sys/load-balancer binding with client-observed cert.
ResolutionKeep old certificate valid, rebind the validated new one and retest before retirement.
Rollback code works but data schema is incompatible.
Likely causeRelease rollback ignored database/state migration direction.
Inspect release migration/compatibility and recovery checkpoint.
ResolutionUse the tested forward-fix or coordinated data restore plan; do not improvise on production.
Security notes
- Never bypass certificate validation during renewal or monitoring.
- Preserve logs and failed artifacts during rollback investigation.
Alternatives
- Use blue/green hosts and traffic switching for stronger release rollback, while retaining complete restore testing.
Stop conditions
- Certificate nears expiry/untrusted, binding/pool/logs drift, 5xx/latency breaches, backup lacks recent restore test, or rollback/data compatibility is unknown.
Finish line
Verification checklist
Test-Certificate -Cert (Get-Item Cert:\LocalMachine\My\{{certificateThumbprint}}) -Policy SSL -DNSName {{siteHostName}}; curl.exe --fail --show-error https://{{siteHostName}}/healthValid certificate and exact SNI site return expected health/version without bypass.Get-Item IIS:\AppPools\{{appPoolName}} | Select Name,processModel; icacls {{contentPath}}; icacls {{dataPath}}Dedicated ApplicationPoolIdentity reads content, writes only data and cannot modify code/config.Get-ItemProperty IIS:\Sites\{{siteName}} -Name logFile.*; .\tests\Test-IISFailureEvidence.ps1 -SiteName {{siteName}} -LogRoot {{logPath}}W3C UTC fields, no query string, complete 200/404/500 evidence and healthy forwarding/capacity..\tests\Test-AcmePortal.ps1 -Uri https://{{siteHostName}} -RequireValidCertificate -RequireLogs -RequireAclNegativesRequired workload passes, wrong name/plaintext/content-write paths fail..\tests\Test-AcmePortalRestore.ps1 -ComputerName {{restoreHost}} -ExpectedVersion 2026.07.28.1 -RequireTls -RequireData -RequireLogs -RequireAclNegativesIsolated config/content/data/identity/dependency recovery meets RPO/RTO and all acceptance tests.Recovery guidance
Common problems and safe checks
HTTPS returns a certificate-name warning.
Likely causeThe requested host is absent from SAN or another certificate/binding is selected.
Inspect requested SNI host, site binding and client-observed certificate.
ResolutionCorrect DNS/binding or reissue the certificate; never bypass validation.
IIS returns 503 Service Unavailable.
Likely causeApplication pool is stopped, rapid-fail protection triggered, startup failed or queue is unavailable.
Inspect pool state, WAS/Application events, worker process and application startup logs.
ResolutionFix the application/identity/configuration cause and verify the pool remains stable.
IIS returns 500.19.
Likely causeConfiguration is invalid, locked, unreadable or references a missing module.
Read exact HRESULT/config path and compare installed features/config backup.
ResolutionRestore supported configuration/module and validate offline; do not grant broad file permissions.
Static content is 401/403.
Likely causeSite authentication/authorization or NTFS ACL denies the pool/user.
Inspect IIS substatus, Win32 status, auth configuration and effective ACL.
ResolutionGrant the exact intended read identity or correct auth; never grant Everyone Full Control.
No W3C entry appears.
Likely causeWrong site/log directory, buffering, ACL/capacity or request never reached this IIS site.
Match site ID, binding, log config, directory ACL/free space and HTTP.sys/site selection.
ResolutionRepair exact logging/path or routing and treat the interval as an evidence gap.
AppCmd restore succeeds but application fails.
Likely causeContent, data, certificate, secret or external dependency was not part of the IIS configuration backup.
Inventory each recovery layer and compare application version/identity/dependencies.
ResolutionRestore the missing protected layer and repeat the complete isolated recovery test.
Recovery
Rollback
Stop or drain the affected site, preserve IIS/W3C/application/certificate evidence, switch the application to the previous immutable release and its tested compatible configuration/data state, restore the prior certificate binding if the TLS change failed, and verify health/identity/ACL/logging. Use `appcmd restore backup` only for actual server-wide IIS configuration recovery with all sites drained and a fully identified backup—not as the routine application rollback.
- Stop new traffic through the load balancer or stop only the affected site while preserving unrelated IIS sites.
- Preserve W3C/application/WAS events, current bindings/pool/config, content hashes and certificate evidence.
- Identify whether failure is release, data/schema, certificate, binding, pool identity/ACL, runtime module or server configuration.
- Restore/switch to the previous immutable content release and its tested compatible application configuration.
- Use the approved data rollback/forward-fix plan; never copy arbitrary live files over state.
- If TLS changed, rebind the previously valid nonexpired certificate without bypassing client validation.
- Restore the previous exact pool/site/log settings through versioned configuration.
- Reserve AppCmd server-wide restore for confirmed IIS configuration loss and execute it only under full-host recovery control.
- Run canonical-FQDN TLS, health/version, pool identity, ACL negative, W3C and workload tests before traffic returns.
- Retain failed artifacts and update the isolated restore test before another release.
Evidence