On a multi-site Windows host, a single bad HTTPS binding can take down every site that shares the IP. Server Name Indication (SNI) is what keeps certificate selection per-hostname instead of per-IP, and it is the default pattern you should use on IIS 10.0 under Windows Server 2025.

If you still have legacy IP-based or non-SNI bindings left over from older migrations, certificate renewals become outage windows. Clean SNI bindings, a predictable cert store layout, and a repeatable add/replace process fix that for ASP.NET and static sites alike.

#What SNI changes on the wire

During the TLS handshake the client sends the target hostname. IIS matches that name to a site binding that has Require Server Name Indication enabled and a specific certificate hash. Without SNI, IIS can only pick one certificate for the entire IP:port pair, which forces either a shared cert (SAN/wildcard only) or dedicated IPs.

Windows Server 2025 continues to use IIS 10.0. Binding behavior is familiar, but newer Schannel defaults and stricter cipher negotiation make stale non-SNI or weak-protocol configs fail faster against modern browsers and HttpClient stacks in .NET 10.

#Inventory bindings before you touch production

Always list what is already bound. Conflicts show up as the wrong cert served, handshake failures on one hostname only, or a site that works on HTTP but not HTTPS after a renew.

powershell
Import-Module WebAdministration

Get-WebBinding -Protocol https |
  Select-Object ItemXPath, bindingInformation, sslFlags, certificateHash |
  Format-List

# sslFlags: 0 = no SNI, 1 = SNI enabled
Get-ChildItem IIS:\SslBindings | Format-Table

bindingInformation looks like IP:port:hostname. An empty hostname with sslFlags 0 is a non-SNI catch-all. Prefer explicit hostnames and sslFlags 1 for every public site. Leave a deliberate catch-all only if you own that IP and understand who receives the fallback cert.

#Add or replace an SNI binding safely

Import the new PFX into the Local Machine Personal store (or your chosen store), note the thumbprint, then attach it to the site with SNI on. Removing the old binding after the new one works avoids a gap with no HTTPS listener.

powershell
$siteName   = "contoso-app"
$hostName   = "app.contoso.example"
$thumbprint = "D2A7F3C1B9E8456A0F1D2C3B4A5968778899AABB"
$storeName  = "My"

# Ensure site exists; add HTTPS binding with SNI (sslFlags=1)
New-WebBinding -Name $siteName -Protocol https -Port 443 `
  -IPAddress "*" -HostHeader $hostName -SslFlags 1

# Map cert to IP:port:hostname (SNI)
$bindPath = "0.0.0.0!443!$hostName"
New-Item -Path "IIS:\SslBindings\$bindPath" `
  -Thumbprint $thumbprint -SSLFlags 1 -Store $storeName

# Optional: remove previous binding only after a live TLS check

Verify with a hostname-aware client from outside the box (browser, curl --resolve, or Invoke-WebRequest with the correct Host). Checking only by IP often shows the catch-all cert and hides an SNI mistake.

#Store hygiene and rotation habits

  • Keep site certs in Local Computer\Personal; avoid User stores for app-pool identities that are not loaded interactively.
  • Grant the app pool identity Read on the private key only when the app itself must use that cert (client cert outbound, custom TLS). IIS HTTPS bindings do not require the pool to read the key for ordinary server auth.
  • Name certs and friendly names by hostname and expiry so renew scripts do not grab the wrong thumbprint.
  • After binding, confirm Schannel is not still offering only legacy protocols on that endpoint; disable TLS 1.0/1.1 machine-wide when clients allow it.

For many hostnames on one box, Centralized Certificate Store (CCS) can map hostname.pfx files from a share and reduce per-binding thumbprint edits. CCS still relies on SNI; it does not replace correct host headers on the site objects. Use it when certificate volume makes manual thumbprint swaps error-prone, not as a shortcut past binding inventory.

#Pitfalls that show up on shared Windows hosts

Duplicate host headers across sites cause unpredictable cert selection. Bindings on a specific IP that no longer exists on the NIC fail silently until traffic shifts. Web Deploy or publish profiles that recreate the site without copying SSL bindings drop HTTPS until someone re-runs the cert step. Document the thumbprint source of truth (ACME output path, internal PKI export job) next to the site name so on-call is not guessing which PFX is live.

ASP.NET Core apps behind IIS terminate TLS at IIS in the common in-process or out-of-process setups. The app sees forwarded scheme/headers only if you configured them; certificate problems are almost always at the IIS binding or Schannel layer, not in Kestrel, when IIS is the edge.

Practical takeaway: before the next renew, export Get-WebBinding and SslBindings for each production server, convert every public site to hostname + SNI, and script New-WebBinding plus the SslBindings item with the new thumbprint. Test by hostname, then remove the old mapping. That sequence keeps multi-site IIS hosts stable through certificate rotation on Windows Server 2025 without surprising neighboring apps.