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.
RDP into the VM and install the Web Server (IIS) role via Server Manager.
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:
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 18.104.22.168.22.214.171.124.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:
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:
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.
Now we can add a HTTPS endpoint to the existing VIP of the multissl cloud service in the Azure Management Portal:
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):
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:
Refreshing the site in the browser should yield:
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 126.96.36.199.188.8.131.52.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:
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:
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:
Here we can see the new VIP’s public IP address which is 184.108.40.206 in our example. We need to add a corresponding mapping to the local hosts file for sslsite2.com:
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:
Voilà, opening https://sslsite2.com in the browser will show:
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.