4
votes

I have Service Fabric cluster on Azure. I would like to use this cluster to host multiple ASP.NET Core based sites. All sites have to be accessible on Internet via HTTPS (on port 443). Also each site operates on different domain thus having unique SSL certificates. Some sites even have wild card certificates.

I've learned that using WebListener is the recommended way to host ASP.NET Core based sites on Service Fabric. As far as I know WebListener should support binding multiple sites to the same port by using the request HTTP headers to recognize the requested site. This is cool, but I have not found information on how to bind the SSL certificates to the sites (hostname). Is it even possible?

If it's not possible to bind certificates to the specific site when using WebListener, I don't know of any practical way of achieving this.

Does somebody have an idea how to solve this issue in a manner that is practical for adding new sites to the cluster with minimal work and expense (performance or infrastructure cost)?

I guess one way would be to use unique port for each site and then doing work on Azure Load Balancer and/or Application Gateway. This could get a bit complicated to manage and even costly (public IPs and application gateway aren't exactly free).

2

2 Answers

1
votes

So having just spun up a new ASP.Net Core WebSite I can see that the program.cs file contains a specific ICommunicationListner implementation for .Net Core. I would modify the following method on that listener to allow you to specify an app root, similar to what the default Owin communication listener does for WebAPI. This would allow you to bind multiple sites to the single port.


Task ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
            {
                var endpoint = FabricRuntime.GetActivationContext().GetEndpoint(_endpointName);

                string serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";

                _webHost = new WebHostBuilder().UseWebListener()
                                               .UseContentRoot(Directory.GetCurrentDirectory())
                                               .UseStartup()
                                               .UseUrls(serverUrl)
                                               .Build();

                _webHost.Start();

                return Task.FromResult(serverUrl);
            }

The change may look like this:

string serverUrl = $"{endpoint.Protocol}://+{endpoint.Port}/{this.appRoot}";

Then within the service manifest file tweak the endpoint configuration to run on https and 443

 <Endpoints>
      <Endpoint Protocol="https" Name="ServiceEndpoint" Type="Input" Port="443" />
</Endpoints>

And then in the Service Fabric application manifest add in the certificate (which should already be deployed to the VMS) using the thumbprint to identify which certificate to use, like so.

Then still within the application manifest add in a policy to bind that certificate to the endpoint for your service

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Web1Pkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides />
    <Policies>
      <EndpointBindingPolicy EndpointRef="ServiceEndpoint" CertificateRef="Cert1" />
    </Policies>
  </ServiceManifestImport>

EDIT: Fixed typo in service url (approot was in wrong location) and replaced default kestrel extension with weblistener.

EDIT 2: Updated the service url to use wild card due to how binding works with the Web Listener

0
votes

As you already said, one way to do it (we do it with 3 domains), is to have X public IP addresses. Each of those is forwarded to an internal port (different for each) that has a website listing on that port (or one app listening on multiple ports). Then you can assign SSL and such to each of those.

PublicIP1:443 -> Port 447 -> Webapp listening on port 447 PublicIP2:443 -> Port 448 -> Webapp listening on port 448 PublicIP3:443 -> Port 449 -> Webapp listening on port 449

All in all, using ServiceFabric just as a hosting solution for websites is probably not something I would do. If I had to host multiple (read many) websites, I'd do that on Azure App Service. If I then had need for processing/persistence of data on scale, I'd look at maybe using SF for that. But that doesn't mean that the websites has to run on SF.