Hosting Multiple SSL Sites in Azure VMs

Until recently, it was not possible in Azure to host multiple SSL websites in a single IaaS VM (or load-balanced set of VMs), all listening on port 443 using different certificates (e.g. for separate domain names). People had to either use ARR farms in front of the web servers (making deployments more expensive and hard to manage) or use SNI (Server Name Indication) certificates, eliminating usage by all those brave people still running XP. This limitation was caused by the fact that a cloud service in Azure did only get one Virtual IP Address (VIP) from the fabric to get bound to port 443 for a single certificate.

Now, as Microsoft has announced availability of multiple VIPs per cloud service around Build 2015, it’s finally possible to configure several SSL endpoints, each of them pointing to a different website on the same VM (or set of VMs behind the Azure load balancer). This post will go through a simple example of setting up two SSL websites on a single VM.

Creating Web Server and Certificates

First, let’s create an ordinary Windows Server 2012 R2 VM. Note that this VM can be located either within a virtual network or standalone in a cloud service, both cases allow configuration of multiple VIPs. In this example our server gets hostname webserver and cloud service name multissl.cloudapp.net.

server

RDP into the VM and install the Web Server (IIS) role via Server Manager.

webserver

For our testing purposes, we will create two self-signed certificates for the SSL sites we are planning to host on the web server. In order to do that you can use makecert, which is contained in the Windows SDK and is also part of any Visual Studio installation.

Let’s start by creating a self-signed root authority certificate in an elevated command prompt:


makecert -n "CN=SSLRoot" -r -sv SSLRoot.pvk SSLRoot.cer

You will have to enter a password to protect the private key. Copy the file SSLRoot.cer to the web server VM and install it into the Trusted Root Certificate Store in the Local Computer Certificates MMC:

ImportRoot

Now, we will create the certificate for our first SSL website, let’s call it sslsite1.com:


makecert -pe -iv SSLRoot.pvk -n "CN=sslsite1.com" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -ic SSLRoot.cer SSLSite1.cer

You will have to enter the password specified above. This statement will create the certificate in the local machine store. In order to be able to import the certificate in IIS on the web server VM, we first need to export it from our local machine certificate store (assuming you ran makecert on your development machine, not on the web server).

Open the Certificate Management Console, find the sslsite1.com certificate and export it to a file sslsite1.pfx (make sure to include the private key in the exported file). Again, you will protect the file by entering a password.

Configure the First SSL Site on the Web Server

On the web server VM, open IIS Manager, navigate to the ‘Server Certificates’ section and import sslsite1.pfx as shown below:

ImportCert

Once you double-click on the certificate shown in the management console, you should see a valid certificate path, as we have previously imported the root cert:

sslsite1

Now, let’s associate this certificate with an SSL binding for the default web site. In IIS Manager open the ‘Site Bindings’ settings and add an entry for HTTPS including our new certificate. Make sure to also enter sslsite1.com as host name.

binding

Now we can add a HTTPS endpoint to the existing VIP of the multissl cloud service in the Azure Management Portal:

Endpoint

As I don’t own the domain sslsite1.com, I will add an entry to my local machine’s hosts file (located in the c:\Windows\System32\etc\drivers directory) in order to map the domain to the VIP of the cloud service (to be found in the Dashboard section of the Azure Portal):

VIP

 

hosts1

After that’s done you can open https://sslsite1.com in a browser, showing the default IIS web page. Note, that you might get a certificate warning (in case you did not import the root certificate in the local machine’s Trusted Root Certificate Store.

In order to be able to distinguish this SSL site from the second one we are going to create, let’s change the iisstart.htm file in the web server’s c:\inetpub\wwwroot directory and add the domain name right after the opening <body> tag:

html

Refreshing the site in the browser should yield:

sslsite1.com

Configure the Second SSL Site

In order to create another SSL site we will need a different certificate to simulate the second domain, so let’s create one using domain name sslsite2.com:


makecert -pe -iv SSLRoot.pvk -n "CN=sslsite2.com" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -ic SSLRoot.cer SSLSite2.cer

Same as for the first web site, export the sslsite2.com certificate in the Certificate Management Console and export it to a file sslsite2.pfx (including the private key). Copy the .pfx file to the web server VM and import it in IIS Manager.

Now we have to create another website in IIS to host our second domain:

AddWebsite

Website2

In this sample we are creating the web site in a new directory c:\inetpub\wwwroot2 and copying the content of the default web site (from c:\inetpub\wwwroot) to the new directory. I replaced the text sslsite1.com by sslsite2.com in iisstart.htm in order to see that we are targeting a different site.

In the ‘Add Website’ dialog you can add a SSL binding directly. Important caveat to note is that it is not possible to use port 443 again, as it is already bound to the default IIS website for sslsite1.com. We are using port 444 in this example. Also make sure to use sslsite2.com as host name and also select the correct certificate for sslsite2.com.

Add a VIP to the Cloud Service

In order to expose the second SSL website with its own domain name (sslsite2.com) on the public Internet we need to create an additional VIP for the cloud service multissl.cloudapp.net. As this is not yet possible in the portal let’s open a PowerShell console and execute the following statements to first show the current endpoint information:


$deployment = Get-AzureDeployment -ServiceName "multissl"
$deployment.VirtualIPs

The result should look like this:

vip1

We can now add a VIP to the cloud service as follows (let’s also call it sslsite2.com):


Add-AzureVirtualIP -VirtualIPName "sslsite2.com" -ServiceName "multissl"

Now we can associate the new VIP to an SSL endpoint like this:


Get-AzureVM -ServiceName "multissl" -Name "webserver" | 
Add-AzureEndpoint -Name "ssl" -Protocol tcp -LocalPort 444 -PublicPort 443 -VirtualIPName "sslsite2.com" | 
Update-AzureVM 

Note, that we specify 444 as the local port (as configured in IIS on the web server). Externally the new VIP allows us to use port 443, which is the whole purpose of using multiple VIPs.

If we query the deployment again (as described above) the result will look like this:

vip2

Here we can see the new VIP’s public IP address which is 104.40.158.131 in our example. We need to add a corresponding mapping to the local hosts file for sslsite2.com:

hosts2

Before we can access the second site via the newly created endpoint from the Internet we need to add a rule in the web server’s Windows firewall to allow traffic coming in on port 444:

firewall

Voilà, opening https://sslsite2.com in the browser will show:

sslsite2.com

Summary

As you can see it’s fairly easy to add additional VIPs to a cloud service and associate them with corresponding endpoints. This is the recommended way to host multiple SSL endpoints using different domains and certificates in a single cloud service, all of them listening externally on port 443 and forward requests internally to different ports.

In production environments you wouldn’t use single instance VMs, but rather host multiple machines in a cloud service and work with load-balanced endpoints. You can do that with our VIPs above as well by using the -LoadBalancedEndpointSetName attribute in the Add-AzureEndpoint PowerShell Cmdlet and add multiple endpoints to the same VIP.

9 comments on “Hosting Multiple SSL Sites in Azure VMs
  1. Would these commands be safe to run as a deployment script or would it create a new IP each time? This seems like a great solution to automate hosting multiple https sites if there’s a way to check if it already exists.

    • Calling Add-AzureVirtualIP with an existing VIP name will return “vip already in use”, so you should be able to use it in a deployment script.

  2. Hi Carsten,
    Great article, thanks a lot. I would have several questions:
    1. What is limit in number of VIPs per cloud service? Could I have for example, 80 VIPs per cloud service and how it will billed by Azure?
    2. Is addition of VIPs supported for already running cloud service or it applies only for the newly created cloud services?
    3. Are there any limitations with cloud services with Reserved IP addresses?

  3. When I run Add-AzureEndpoint command in load balanced set. I keep getting ” The server encountered an internal error. Please retry the request”.

    cmdlet: Get-AzureVM -ServiceName “testvm-4” -Name “TestVM-5″| Add-AzureEndpoint -Name “SSLEnd” -LoadBalancedEndpointSetName “WebFarm” -Protocol tcp -LocalPort 444 -PublicPort 443 -VirtualIPName “HttpsIn2” -ProbePort 443 -ProbeProtocol “tcp”| Update-AzureVM

  4. One thing to be aware of is that, at least at the time of writing (Nov 2015), adding more than one VIP to a cloud service will stop Azure VM backup from running with the message:

    ‘The current deployment cannot be updated with the API version specified. This is because the current deployment contains multiple virtual IPs created with a newer version of the service management API.’

    I’ve been trying to work around this for days without progress. Remove the virtual IPs and backup starts working again. Add them back in and it stops.

  5. This second VIP will be DHCP, correct? What if the server gets shutdown or Microsoft has an outage that causes a deallocation?

    • Right, you can reserve only the primary VIP, the second will be some IP from the documented address range of the Azure datacenter. An outage or reboot will not cause the IPs to change though, only deprovisioning will do so for non-reserved VIPs.

      • You can reserve any Virtual IP:

        On the New-AzureReservedIP use the -VirtualIPName to reserve the virtual IP address you have already created.

Leave a Reply

Your email address will not be published. Required fields are marked *