SNI and wildcard SSL certificates on the same server with IIS

Solution 1:

Baris is right! The SSL certificate configured on an IP:PORT binding (example: 100.74.156.187:443) always takes precedence in http.sys! So the solution is as follows:

Do not configure an IP:443 binding for your wildcard-fallback-certificate but configure a *:443 binding (* means "All Unassigned") for it.

If you have configured your wildcard certificate on the Azure Cloud Service SSL endpoint (as i have) you have to change the SSL binding created by the Azure Cloud Service Runtime (IISconfigurator.exe) from IP:PORT to *:PORT. I am calling the following method in OnStart of my web role:

public static void UnbindDefaultSslBindingFromIp()
{
    Trace.TraceInformation(">> IISTenantManager: Unbind default SSL binding from IP");
    using (var serverManager = new Microsoft.Web.Administration.ServerManager())
    {
        try
        {
            var websiteName = string.Format("{0}_Web", Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CurrentRoleInstance.Id);
            var site = serverManager.Sites[websiteName];
            var defaultSslBinding = site.Bindings.Single(b => b.IsIPPortHostBinding && b.Protocol == "https");
            defaultSslBinding.BindingInformation = string.Format("*:{0}:", defaultSslBinding.EndPoint.Port);
            serverManager.CommitChanges();
        }
        catch (Exception ex)
        {
            Trace.TraceError(ex.ToString());
        }
    }
}

The following screenshot shows a working configuration of our cloud service. Please don't be confused about the non-standard ports. The screenshot is from the emulated cloud service.

working IIS configuration

One further thing to mention: Do not change all bindings to * because the HTTP (port 80) binding only works with IP:PORT binding in the deployed cloud service. Something else is bind to IP:80 so *:80 does not work because * stands for "all unassigned" and the IP is already assigned somewhere else in http.sys.

Solution 2:

Make sure that your catch-all binding is not of type IP:Port. When an IP:Port binding exists for an HTTPS binding while SNI is not required, that binding will always take precedence. For your catch-all case, use a *:Port binding (* being the all unassigned).