12

I'd like to host a website that should listen to subdomains (e.g. sub.domain.com) together with multiple websites that live just under a second-level domain (e.g. domain2.com, domain3.com) with IIS and with SSL.

For the website with the subdomains I have a wildcard certificate (*.domain.com) and I also have certificates specifically for the other sites (domain2.com and domain3.com).

Can such a setup be hosted on the same IIS (if that matters, in an Azure Cloud Service web role)?

The issue is exactly what titobf explained here: theoretically for this we'd need bindings using SNI, with the host specified for domain2/3.com and then a catch-all website with * host for *.domain.com. But in practice no matter how the bindings are set up if the catch-all website is on it will also receive all requests to domain2/3.com (although supposedly it's matched only as a last resort).

Any help would be appreciated.

Still unsolved

Unfortunately I wasn't able to solve this: it seems to be solvable only in extremely complicated ways, like creating a software that sits between IIS and the internet (so basically a firewall) and modifies incoming requests (before the SSL handshake takes place!) to allow the scenario. I'm fairly confident this is not possible with IIS, no matter what, not even from a native module.

I have to clarify: we use Azure Cloud Services, so we have a further constraint that we can't use multiple IP addresses (see: http://feedback.azure.com/forums/169386-cloud-services-web-and-worker-role/suggestions/1259311-multiple-ssl-and-domains-to-one-app). If you can point multiple IPs to your server then you don't have this issue since you can create bindings for IPs too, and those will work together wildcard bindings. More specifically, you need an IP for the wildcard site (but since you have a separate IP now you wouldn't have to configure a wildcard host name binding) and another IP for all other non-wildcard ones.

Actually our workaround was the usage of a non-standard SSL port, 8443. So the SNI binding is actually bound to this port, thus it works along with the other bindings. Not nice, but an acceptable workaround for us until you can use multiple IPs for web roles.

The non-working bindings now

The first https binding is SNI with a simple certificate, the second is not SNI, with a wildcard certificate.

The http site works, as well as the SNI https site, but the one with the wildcard binding gives an "HTTP Error 503. The service is unavailable." (without any further information, no Failed Request Tracing or Event Log entry). Bindings

Finally getting it basically working

Enabling the ETW trace log like Tobias described showed that the root error was the following:

Request (request ID 0xF500000080000008) rejected due to reason: UrlGroupLookupFailed.

As far as I understand this means that http.sys is not able to route the request to any available endpoint.

Checking the registered endpoints with netsh http show urlacl showed that there was indeed something registered for port 443:

Reserved URL            : https://IP:443/
    User: NT AUTHORITY\NETWORK SERVICE
        Listen: Yes
        Delegate: No
        SDDL: D:(A;;GX;;;NS)

Removing this with netsh http delete urlacl url=https://IP:443/ finally enabled my SSL binding.

Piedone
  • 384
  • 1
  • 6
  • 18
  • You should absolutely be able to do this on IIS using SNI, without resorting to multiple IPs or non-standard ports. – Joe Sniderman Sep 14 '14 at 20:12
  • You mean that IIS should support this? I agree :-). – Piedone Sep 15 '14 at 11:00
  • I totally agree with you, Piedone. I am really disappointed that IIS (or to be more precisely http.sys) does NOT support the combination of a wildcard certificate as a default SSL certificate and multiple concrete certificates with SNI AS EXPECTED. The problem is well known since 2012 as you can see here: http://forums.iis.net/t/1192170.aspx. I just wrote an email to Microsoft and hope to get feedback soon. – Tobias J. Oct 27 '14 at 20:06
  • Thanks Tobias. Please come back here once Microsoft replied. – Piedone Oct 28 '14 at 12:14
  • 2
    Probably http.sys is refusing the request so no Failed Request is logged in IIS. Create a http.sys ETW trace log: 1) start trace log. run: `logman start httptrace -p Microsoft-Windows-HttpService 0xFFFF -o httptrace.etl -ets` 2) do the 503 request 3) stop trace log. run: `logman stop httptrace -ets` 4) write trace log to file. run: `tracerpt.exe httptrace.etl -of XML -o httptrace.xml` 5) check the reason for 503 in the xml file and post it here. – Tobias J. Nov 11 '14 at 06:30
  • Thank you. See my updates to my question, it seems to be working. I'll make more tests (and slowly build back everything else that I stripped down from the config to just have the essentials) and see if this fixes the issue for real and whether removing this reserved URL causes any errors. – Piedone Nov 11 '14 at 22:47
  • I'll get back soon with end results. – Piedone Nov 11 '14 at 22:53
  • Very interesting that your web role instance has a registered binding for IP:443. My instances do not have such registrations. Did you do your tests on a clean reimaged instance or is the existing IP:443 binding a burden of former tests you did manually (via mstsc)on the machine? Recently I had the situation on one of my machines that deleting bindings in IIS does not delete the registration in http.sys. However it is important to know which application does the IP:443 registration (and I also really want to know which application is responsible for the IP:80 binding I mentioned in my answer). – Tobias J. Nov 12 '14 at 07:08
  • For heaven's sake! I withdraw my statement that my machines do not have such a terrible IP:443 reservation. They absolutely have. Maybe during my playing I had deleted the reservation but after reimaging my instances the reservations exist. I am not sure if we can delete these reservations without creating other problems?! – Tobias J. Nov 13 '14 at 09:46
  • I asked this on the Azure forums, let's hope somebody will share some insights: https://social.msdn.microsoft.com/Forums/azure/en-US/4198421e-b8ed-4d21-8dbf-073efd69ff32/can-the-automatically-reserved-url-httpsip443-removed-from-azure-cloud-services?forum=windowsazuredevelopment I hope removing this default URL won't break anything because then I'm back to square one again. – Piedone Nov 13 '14 at 17:15
  • I did some more involved testing with everything else on the web role built back, and such a catch-all binding added. It seems to be working well. Early next week I'll deploy the changes to production, keeping my finger on the rollback button. I'll come back with results. – Piedone Nov 22 '14 at 00:23
  • It works! Thank you for your help. I'd split the answer mark between you and bariscaglar. – Piedone Nov 22 '14 at 19:09

3 Answers3

6

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.

Tobias J.
  • 176
  • 1
  • 3
  • Thanks for your detailed answer. I updated my question: as I remember now I probably didn't go with this setup because I got the same error as now. – Piedone Nov 10 '14 at 23:05
4

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).

  • Thanks, but as you can see in my description I initially tried to set up the SNI binding without port, but since that didn't work I ended up with a custom port binding. – Piedone Oct 30 '14 at 11:25
  • By port, I take it that you mean the IP. You cannot have a binding without a port. Inetmgr will not allow it. For the SNI bindings you can use the specific IP or "All Unassigned" and the outcome will be the same. It is the Catch All binding, for which you have a wildcard certificate, that needs to be on "All Unassigned" and not on a specific IP. – bariscaglar Oct 30 '14 at 18:50
  • I meant port but I wanted to say "non-standard port". The IP was not specified, just as you say and it still doesn't work, also see the link of Tobias. There are two ways to work around this limitation of IIS: use a custom port or an IP different than the other bindings: on Azure cloud services the latter is not available so we've gone with a custom port. – Piedone Oct 30 '14 at 19:02
  • bariscaglar is the Microsoft developer (working on IIS) I had a very nice and helpful conversation with! Thx Baris! Together we analyzed the behavior and we came to the conclusion, that the described behavior is the desired behavior of http.sys. But there is a nice workaround. See my answer for details. – Tobias J. Nov 06 '14 at 07:10
  • Just a note for anyone reading, I have recently discovered that if you use the Azure Portal to configure a service for Remote Desktop (or otherwise change the cert configuration) it can cause an IP:Port binding to be created automatically and break all your SNI. I don't have a solution to that particular issue. It happens after RoleEnvironment.Changed so I can't catch it in WebRole.cs. – Mike May 10 '16 at 14:36
1

IIS does support SNI, even in azure cloud service web roles although you can't get to the config through the portal and if you do it on the box after deployment it'll be wiped with your next deployment. The solution is to automate the config. Have a look here for details:

http://www.vic.ms/microsoft/windows-azure/multiples-ssl-certificates-on-windows-azure-cloud-services/

CamW
  • 151
  • 5
  • Thanks, but as I explained there is no problem with SNI itself (I'm using it) but rather how wildcard host name matching works in IIS. – Piedone Oct 02 '14 at 09:43
  • This article no longer exists, but here it is on the Web Archive:https://web.archive.org/web/20151020041907/http://www.vic.ms/microsoft/windows-azure/multiples-ssl-certificates-on-windows-azure-cloud-services/ – Mike May 10 '16 at 14:34