Hosting multiple websites in a web role
Microsoft released Microsoft Azure as a production service in February 2010. A common complaint was that it was too expensive to develop small websites because a web role could support only a single website. The cause of this limitation was that a web role hosted a website using a hosted web core rather than the full IIS.
With the Microsoft Azure SDK v1.3 release, Microsoft Azure added support for full IIS for web roles. This means that a single web role can host multiple websites. However, all of these websites share the same Virtual IP address, and a CNAME record must be used to map the domain name of the website to the servicename.cloudapp.net
URL for the web role. Each website is then distinguished inside IIS by its distinct host header.
The Providing a custom domain name for a Cloud Service recipe shows how to use a CNAME record to map a custom domain to a Cloud Service domain. Note that full IIS is also available on worker roles.
Tip
The approach described in this recipe, as it is still valid, is probably not the best you can do with Azure. If you need to host multiple websites in a single role (and in a single unit of scale), the Microsoft Azure Websites could be the best solution to accomplish this. We will talk about Websites in a dedicated chapter, and it is the newest and probably the most advanced PaaS on the market.
The Sites
element in the ServiceDefinition.csdef
service definition file is used to configure multiple websites. This element contains one child Site
element for each website hosted by the web role. Each Site
element has two attributes: name, which distinguishes the configuration, and physicalDirectory
, which specifies the physical directory for the website. Note that multiple websites can reference the same physical directory. Each Site
element has a Bindings
child element that contains a set of Binding
child elements, each of which identifies an endpoint used by the website and the host header used to distinguish the website. Each endpoint must correspond to an input endpoint specified in the EndPoints
declaration for the web role. It is possible to define virtual applications and virtual directories for a website, using the VirtualApplication
and VirtualDirectory
elements, respectively. This configuration is a subset of the standard IIS configuration.
The following example shows a fragment of a service definition file for a web role that hosts two websites:
<WebRole name="MultipleWebsites"> <Sites> <Site name="WebsiteOne" physicalDirectory="..\Web"> <Bindings> <Binding name="HttpIn" endpointName="HttpIn"hostHeader="www.websiteone.com" /> </Bindings> </Site> <Site name="WebsiteTwo" physicalDirectory="..\Web"> <VirtualApplication name="Payment"physicalDirectory="..\..\Payment"> <VirtualDirectory name="Scripts"physicalDirectory="..\Web\Scripts" /> </VirtualApplication> <Bindings> <Binding name="HttpIn" endpointName="HttpIn"hostHeader="www.websitetwo.com" /> <Binding name="HttpsIn" endpointName="HttpsIn"hostHeader="www.websitetwo.com" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="HttpIn" protocol="http"port="80" /> <InputEndpoint name="HttpsIn" protocol="https"port="443" /> </Endpoints> <ConfigurationSettings /> </WebRole>
This configuration specifies that the web role hosts two websites: www.websiteone.com
and www.websitetwo.com
. They share the same physical directory, but www.websitetwo.com
also uses a virtual application with its own virtual directory. Both websites are accessible using HTTP, but www.websitetwo.com
also exposes an HTTPS endpoint.
In this recipe, we'll learn how to host multiple websites in a single Microsoft Azure web role.
How to do it...
We are going to see how to implement the two websites in a Cloud Service. We do this as follows:
- Use Visual Studio to create an empty cloud project.
- Add a web role to the project (accept the default name of
WebRole1
).
The changes from steps 3 to 8 affect the ServiceDefinition.csdef
service definition file:
- Set the
name
attribute of theSite
element toWebSiteOne
. - Add a
physicalDirectory
attribute, with the"..\..\..\WebRole1"
value, to theSite
element. - Add a
hostHeader
attribute, with thewww.websiteone.com
value, to theBinding
element for theSite
element. - Copy the entire
Site
element and paste it under itself. - Change the
name
attribute of the newSite
element toWebsiteTwo
. - Change the
hostHeader
attribute of the newSite
element towww.websitetwo.com
. - Add the following entries to the
hosts
file present in the%SystemRoot%\system32\drivers\etc
folder:127.0.0.1 www.websiteone.com 127.0.0.1 www.websitetwo.com
- Build and run the Cloud Service.
- Change the URL in the browser to
www.websiteone.com
, and refresh the browser. - Change the URL in the browser to
www.websitetwo.com
, and refresh the browser.
How it works...
On completing the steps, the WebRole
element in the ServiceDefinition.csdef
file should be as follows:
<WebRole name="WebRole1"> <Sites> <Site name="WebsiteOne" physicalDirectory="..\..\..\WebRole1"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1"hostHeader="www.websiteone.com"/> </Bindings> </Site> <Site name="WebsiteTwo" physicalDirectory="..\..\..\WebRole1"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1"hostHeader="www.websitetwo.com"/> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1"protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> </Imports> </WebRole>
In steps 1 and 2, we created a Cloud project with a web role.
In steps 3 and 4, we configured the Site
element for the first website. In step 3, we provide a distinct name for the element, and in step 4, we specified the physical directory for the website.
In step 5, we configured the Binding
element for the Site
element by specifying the host header we use to distinguish the website.
In step 6, we created the Site
element for the second website. In steps 7 and 8, we completed the configuration of the second website by providing a name for its configuration and specifying the host header we use to distinguish the website. Note that in this example, we used the same physical directory for both websites.
In step 9, we modified the hosts
file so that we can use the configured host headers as URLs.
We built and ran the Cloud Service in step 10. We will encounter an error in the browser as there is no default website at 127.0.0.1:81
(or whichever port the Microsoft Azure Compute Emulator has assigned to the Cloud Service). In steps 11 and 12, we confirmed this by replacing 127.0.0.1
in the browser URL with the URLs we configured as host headers for the two websites.
Tip
Note that although we only created two websites in this example, we could have configured additional websites.
There's more...
When we use this Cloud Service, we must use CNAME records to map the two domains to the ourservice.cloudapp.net
URL of our Cloud Service. Just as we cannot access the Cloud Service locally at 127.0.0.1
, we cannot access the Cloud Service at ourservice.cloudapp.net
. We will see how to use CNAME to do this mapping in the Providing a custom domain name for a Cloud Service recipe.
See also
Have a look at the following MSDN links and blog posts to get additional information:
- Further information about hosting multiple websites in a web role at http://msdn.microsoft.com/en-us/library/azure/ee758708.aspx
- Blog post about custom build and CSPACK usage for advanced scenarios at http://michaelcollier.wordpress.com/2013/01/14/multiple-sites-in-a-web-role/