skip to content

You add a second website to an IIS server bound to port 443 and it will not start; the System event log says the WWW Publishing Service could not register the URL prefix. What does an IIS binding consist of, and how would you diagnose and resolve the conflict?

level: seniorimportance: should knowfreq 46%

answer

  1. protocol, IP, port, host name
  2. the kernel owns the port, not IIS
  3. blank host name is the catch-all
  4. the certificate is chosen before Host is read
  5. check urlacl before blaming the other site

basics

~20 s

An IIS binding is the tuple protocol, IP address, port and host name (plus a certificate for HTTPS). Two sites whose tuples collide cannot both register their prefix with HTTP.sys, so the second fails to start. Give them distinct host names — with SNI enabled for HTTPS — or distinct IPs or ports.

solid answer

~50 s

A binding is four things: protocol, IP address (or `*` for all), TCP port, and host name; HTTPS bindings add a certificate and an SNI flag. IIS hands each binding to HTTP.sys as a URL prefix reservation, and the kernel refuses a prefix that another registration already owns, which surfaces as the site failing to start with error `0x80070020`. Before assuming it is the other site, check whether a non-IIS process holds the port at all — `netsh http show servicestate` lists every registered prefix and its owning queue, `netsh http show urlacl` lists standing reservations, and `netstat -ano` finds a plain listener. The resolution is to make the tuples distinct: different host names on the same IP and port, different IPs, or different ports. For HTTPS on a shared IP and port you must tick Require Server Name Indication, because otherwise IIS has to choose one certificate for the whole endpoint before it has read any host name.

code

powershell · 4 lines
powershell
netsh http show servicestate view=requestq
netsh http show urlacl
netsh http show sslcert
netstat -ano | findstr ":443"

go deeper

for a junior

Be able to name the parts of an IIS binding — protocol, IP address, port and host name — and say that two sites need different values in at least one of them.

for a middle

Explain that IIS registers prefixes with HTTP.sys in the kernel, why a blank host name acts as a catch-all, and what Require Server Name Indication changes for HTTPS.

for a senior

Show a diagnosis order rather than a guess: prove who owns the prefix with netsh before touching bindings, and recognise urlacl reservations and orphaned sslcert bindings as causes.

for a principal

Own the certificate topology for a fleet — SNI versus per-site IPs versus SAN or wildcard certificates versus a Central Certificate Store, weighing renewal blast radius and old-client support.

## What a binding is An IIS site does not "listen" on anything itself. It declares one or more bindings, and IIS translates each into a URL prefix registration with HTTP.sys, the kernel driver that actually owns the port. A binding has four parts, written in configuration as a colon-separated `bindingInformation` string of `IP:port:hostname`: ```xml <site name="Contoso" id="2"> <bindings> <binding protocol="https" bindingInformation="*:443:www.contoso.com" sslFlags="1" /> <binding protocol="http" bindingInformation="*:80:www.contoso.com" /> </bindings> </site> ``` `*` in the IP position means all addresses. An empty host name means "any host name" — the catch-all — and that is the source of a second, quieter failure mode discussed below. `sslFlags="1"` is the SNI flag. ## Why the second site will not start HTTP.sys enforces exclusivity per prefix. When W3SVC tries to register `https://*:443:` for a new site and something already owns that exact prefix, registration fails and the site stays stopped. The event log text is the generic Win32 message `0x80070020 — The process cannot access the file because it is being used by another process`, which sends people hunting for a locked file that does not exist. Three different situations produce it, and they need different fixes: 1. **Another IIS site holds the identical tuple.** Most common when both bindings were left with a blank host name. 2. **A non-IIS process owns the port.** A self-hosted service that called `HttpListener`, a Windows service, or another web server. It may hold a *urlacl* reservation even when it is not currently running. 3. **The port is held by an ordinary socket listener** that has nothing to do with HTTP.sys at all. ## Diagnosing in the right order ``` netsh http show servicestate view=requestq netsh http show urlacl netstat -ano | findstr :443 ``` The first dumps every request queue HTTP.sys knows about with the registered URLs and the owning process IDs — this is the definitive answer to "who has my prefix". The second lists standing URL ACL reservations, which persist across reboots and are how a non-IIS application claims a prefix in advance. The third catches a plain socket listener; map the PID with `tasklist /fi "pid eq <id>"`. Only after that is it worth looking at IIS Manager's binding list. ## Making the tuples distinct For HTTP the fix is usually just a host name. `*:80:www.contoso.com` and `*:80:www.fabrikam.com` coexist happily, because HTTP.sys reads the `Host` header and routes to the matching queue, preferring the most specific match: an exact host name beats a wildcard host name beats the blank catch-all. A site left with a blank host name will silently answer for every name that has no better match, which is why a newly added site sometimes "works" but serves the wrong content — no error anywhere, just the catch-all winning. For HTTPS there is a chicken-and-egg problem: the server has to present a certificate during the TLS handshake, before any HTTP request — and therefore any `Host` header — exists. That is why, historically, one IP and port could carry only one HTTPS certificate. Since IIS 8.0 you can tick **Require Server Name Indication**, which makes IIS select the certificate from the SNI value the client sends in the handshake, allowing many HTTPS sites on `*:443` with different host names. The alternatives when SNI is not viable — very old clients that send no SNI — are a dedicated IP per site, a non-standard port, one certificate covering all the names (a SAN or wildcard certificate bound once at the endpoint), or the Central Certificate Store, which selects a certificate file by requested host name from a shared folder rather than from the machine store. ## The trap that makes this feel non-deterministic Certificate bindings for HTTPS live in HTTP.sys, not only in IIS configuration, and they are keyed by IP:port (or by host:port for SNI bindings). Removing a site in IIS Manager does not always clear the underlying `sslcert` binding, so the prefix can stay claimed by a site that no longer exists. `netsh http show sslcert` shows what is actually bound, and it is the place to look when IIS Manager insists nothing is using the port. Equally, changing the certificate on one non-SNI binding changes it for every site sharing that IP and port, because there is only one certificate at that endpoint — a surprise that shows up as an unrelated site suddenly serving the wrong name.

  • A new site starts fine but requests for its host name are answered by an older site. What is wrong?
    The older site has a binding with a blank host name on the same IP and port, which matches any `Host` header. HTTP.sys prefers the most specific match, so it only wins when nothing better exists — but if the new site's binding uses a different port, IP, or a mistyped host name, the catch-all takes the traffic. Fix the new binding, or give the catch-all site an explicit host name.
  • Why can two HTTPS sites share one IP and port only if SNI is enabled?
    The certificate is presented during the TLS handshake, before any HTTP request exists, so without SNI the server has one certificate per IP and port and no way to pick per site. SNI carries the requested host name in the handshake itself, letting IIS select the matching certificate. Clients too old to send SNI still get whatever certificate is bound as the endpoint default.
  • How would you host several HTTPS host names on one endpoint without configuring SNI at all?
    Bind a single certificate that covers every name — a wildcard for one label of a domain, or a SAN certificate listing the names explicitly. One certificate on the endpoint serves them all, and host-header routing still separates the sites at the HTTP layer. The cost is that renewing or reissuing touches every site at once.

saying these in an interview costs you the question

  • Thinks IIS binds the socket rather than HTTP.sys
  • Says the host header can select the TLS certificate
  • Treats a blank host name as matching nothing
  • Assumes only IIS can hold a port reservation
  • Believes deleting a site always clears its sslcert binding

context