Prior to the release of the Windows Azure 1.3 SDK, Web roles hosted your application in IIS Hosted Web Core (HWC).  While there were certainly ways to extend HWC, for the most part you were stuck with a single application bound to no more than a single HTTP or HTTPS endpoint.  This model enabled only a minimal number of configurations, and prevented you from fully benefiting from the full capabilities of IIS.  Here’s what the ServiceDefinition.csdef file looks like when using HWC:

  <?xml version="1.0" encoding="utf-8"?>
  <ServiceDefinition name="WindowsAzureProject15" 
     xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WebRole name="WebRole1">
      <Endpoints>
        <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      </Endpoints>
      <Imports>
        <Import moduleName="Diagnostics" />
      </Imports>
    </WebRole>
  </ServiceDefinition>

While you can still use this code today and run HWC in your Web role, you’ll miss you on a lot of great capabilities.

One of the capabilities that, surprisingly, people still doesn’t seem aware of in Windows Azure is the ability to run multiple websites in a Web Role.  In fact, this capability is easy to add once we add seven additional lines of code.

  <?xml version="1.0" encoding="utf-8"?>
  <ServiceDefinition name="WindowsAzureProject15" 
     xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
    <WebRole name="WebRole1">
      <Sites>
        <Site name="Web">
          <Bindings>
            <Binding name="Endpoint1" endpointName="Endpoint1" />
          </Bindings>
        </Site>
      </Sites>
      <Endpoints>
        <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      </Endpoints>
      <Imports>
        <Import moduleName="Diagnostics" />
      </Imports>
    </WebRole>
  </ServiceDefinition>

The difference here is found in lines #4 through #10.  We now have a <Sites> element that includes a default <Site> named “Web”.  When run (locally or in Windows Azure), this translates into an actual web site running in IIS.

Deployment

You can see that our website is now running in IIS.  And what’s nice is that the syntax used in the ServiceDefinition.csdef file is nearly identical to how this is traditionally accomplished in the system.applicationHost – there’s not much new we have to learn.

Run the Same Project in Two Sites in the Web Role

So, how can we take this further and run a second website in a Web role?  It’s as simple as adding an additional <Site> to the <Sites> element.

Copy lines #5 through #9 above, and past them below line #9.  You’re going to have to make a few updates:

  1. Change the site name.  You can’t have multiple sites with the same name.
  2. You’ll have to specify a physical directory for the second site.

Note: the only reason we don’t have to specify a physical path for the first site is because “Web” is consider a special case, and Visual Studio knows that it’s referring to the path of the Web role project.  You can confirm this by renaming “Web” to “Web1” – once you do this you’ll have to specify a physical path for the site.

  1. Create a host header entry for the binding element.  The reason for this is because both sites are listening on port 80.  This is the same behavior you’ll find in IIS – you cannot have more than one site listening on the same port without adding a host header.

Once you make these modifications, your <Sites> element will look something like this:

  <Sites>
    <Site name="Web">
      <Bindings>
        <Binding name="Endpoint1" endpointName="Endpoint1" />
      </Bindings>
    </Site>
    <Site name="Web2" physicalDirectory="..WebRole1">
      <Bindings>
        <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.litware.com" />
      </Bindings>
    </Site>
  </Sites>

While this syntax is correct, www.litware.com will not locally resolve to our application.  To make this work, we have to update our hosts file to assist in correctly resolving the address to 127.0.0.1 (the loopback address). Update the hosts file (C:WindowsSystem32driversetchosts) to include the following hostnames:

127.0.0.1 www.fabrikam.com
127.0.0.1 www.contoso.com
127.0.0.1 www.litware.com

After you’ve done this, you can confirm that they’re resolving correctly by pinging one of the addresses:

image

The reply should come from 127.0.0.1.

With this complete, hit F5 and run again.  You’re now running the same project in two different websites – take a look at IIS:

image

In fact, if you take a look at the bindings on Web2, you’ll see that the host name has been set to www.litware.com.

image

And if you type http://www.litware.com:81/ (or whatever port the compute emulator is using), you’ll see the website display.

image

This is pretty cool, especially when want to use the same application for multiple websites – you can handle the requests in such a way that you either pull from different databases or even display different CSS files to make the website display differently.

Note: Some of you may have noticed above that IIS showed www.litware.com as running under port 5100.  You may be wondering why it’s not on port 81, which is what we’re browsing to in IE.  This is because it’s the compute emulator that’s listening on port 81, and then routing to port 5100.  This is necessary so that incase we’re running more than one instance of our web application, both of which have the same host header, they’re not running on the same port.  Nifty, eh?

Now we can even go further.  Let’s take a look at how we can take a completely separate web application and run it in the same Web role.

Run Two Different Projects in the Web Role

Open up a new instance of Visual Studio 2010, and create a new Web Application.  I’d recommend you make a few changes to make it easily recognizable (e.g. change “Welcome to ASP.NET!” to something else).  Be sure to Build your solution (failure to do this will cause problems later).  Copy the Project Folder for the project, and then return to the ServiceDefinition.csdef file in your Windows Azure project.

Create a new <Site> element where the physicalDirectory value is the location of the Project Folder you copied a moment ago.  Also, update the site name and the hostHoder.  It should look something like this:

  <Site name="Web3" physicalDirectory="c:\Projects\WebApplication7\WebApplication7">
    <Bindings>
      <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.fabrikam.com" />
    </Bindings>
  </Site>

We’ve now create a third website, but this time – instead of pointing to the Web role project in our solution – we’ve pointed to a completely separate project that lives outside of our solution.  Hit F5 and take a look at IIS:

image

We now have three sites running, the third which includes the files from “WebApplication7”.  Try it out by updating the URL to http://www.fabrikam.com:81/ and you’ll see:

image

You can see that this is the not the Web role project itself, but the second project we created.  The packaging tools know to include all the files needed from the physicalDirectory location and make them a part of the CSPKG that is ultimately given to the fabric controller.

This is pretty awesome, cause it demonstrates that you can run two completely different websites in the same Web role with a minimal amount of work.

Now, let’s take this even one step further … because we can.

Run a Virtual Application Within a Site

There may be times when you want to run a Virtual Application within your site (see Wenlong Dong’s post Virtual Application vs Virtual Directory for some interesting information).  Given that the semantics of the <Sites> element is similar to system.applicationHost, it’s not hard to accomplish.

Create a brand new Web Application, and this time update <h2> with a different description (e.g. “This is my virtual application!”).  Build the solution, then grab the project’s path.  Return to your Windows Azure project and the ServiceDefinition.csdef file.  We’re going to add this virtual application to the “Web3” site.  We do this by adding a <VirtualApplication> element with name and physicalDirectory values.  Here’s what it will look like:

  <Site name="Web3" 
        physicalDirectory="c:\Projects\WebApplication7\WebApplication7">
    <VirtualApplication name="VirtualApp" 
        physicalDirectory="c:\Projects\WebApplication8\WebApplication8" />
    <Bindings>
      <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.fabrikam.com" />
    </Bindings>
  </Site>

The <VirtualApplication> element is on line #3.  Go ahead and hit F5, and take a look at IIS:

image

You can see that now, in Web3, our virtual application called VirtualApp is running.  And if we browse to http://www.fabrikam.com:81/virtualapp/, we’ll see that it is indeed “WebApplication8” that’s running.

image

So there you have it!

You’ve now seen how to:

  1. Run multiple websites that run off of the same project in the same Web role.
  2. Run multiple websites that use different projects in the same Web role.
  3. Run a virtual application within a website that uses a different project in a Web role.

Of course, when you deploy this to Windows Azure, you’ll want to use your own domain name and set the host headers accordingly.  For tips on how to do this – especially as as it relates to setting up CNAMEs for your domain – take a look at Steve Marx’s post on Custom Domain Names in Windows Azure.

  • Pingback: Tweets that mention Wade Wegner » Blog Archive » Running Multiple Websites in a Windows Azure Web Role -- Topsy.com

  • http://www.chadmoran.com Chad Moran

    Love it! Thanks so much Azure team for enabling this. Shame you have to push the whole solution every time you want to push just one site.

    • Wade

      If you’re frustrated about having to do this while developing, just enable WebDeploy on your sites – http://www.wadewegner.com/2010/12/using-web-deploy-with-windows-azure-for-rapid-development/.

      • http://www.chadmoran.com Chad Moran

        Oh wow. Thanks Wade!

      • http://www.shanmcarthur.net Shan McArthur

        The caveats for that approach make it completely unacceptable. You WILL lose your changes.

        • Wade

          Yep, that’s correct Shan – this is why I noted the caveats and only suggest this approach for development purposes.

  • Pingback: DotNetShoutout

  • LarryB

    How would the PhysicalDirectory translate to a deployed azure site? Would we not need to specify a relative path so that azure could find the location?

  • LarryB

    Also just found out the hard way that this does not appear to play so well with PHP fast-cgi implementations.

  • Tyler Brinks

    Great post as well as a helpful Cloud Cover demo!

    Let’s say you’re using multiple web roles in a single instance. One of those roles is for a CMS tool like Umbraco or Orchard for a marketing website and the other role is a web application (the app the marketing site says is so awesome).

    Is there a way, either with multiple sites or with a site and a virtual directory, to isolate a specific web role when publishing updates? I’d like to be able to make updates to the web app without having to update (and potentially overwrite) the CMS web role instance.

    What kind of control do you have over publishing individual roles when you have multiple web roles running in a single instance?

    Thanks!

  • http://www.techboy.co.uk Techboy

    Gread post and video. Easy to follow :-)

  • Pingback: Cloud Cover Episodes 31-38 | Windows Azure Tools

  • Pingback: Mais 2 patterns para Azure - MSDN Blogs

  • Brian Norman

    Has anyone experienced issues debugging the separate application with the virtual directory setup above? My application has no symbols loaded and I cannot get it to debug but the main application works fine?

  • Brian Norman

    eventually found if I went into iis and changed the virtual directory to use the main sites app pool it then worked. Not sure why as I had already manually attached all the open app pools anyway

  • Joe

    This is wonderful, and exactly what we’ve been waiting for to migrate some of our sites to Azure, but…

    “The packaging tools know to include all the files needed from the physicalDirectory location and make them a part of the CSPKG that is ultimately given to the fabric controller.”

    The issue is that when using a element, the packaging tools include *all* files from the referenced directory – not just the “needed” files. If you publish an unencrypted service package, you can dig down into it and see a copy of the entire folder structure from the site, including the cs source files, csproj file, obj folder, etc. While IIS on Azure seems to block many of these file types, it is possible to access some of them. For example, after deployment I can type http://www.mysite.com/obj/Release/MyWebApp.csproj.FileListAbsolute.txt into the browser address bar to pull a list of every file in the bin and obj directories. Also, setting “Build Action = None, Copy to Output Directory = Do not copy” on a file essentially has no effect – it will be included in the package, deployed to Azure, and (depending on the file’s type) be accessible via the browser.

    Beyond potential security implications, this issue also results in bloated service packages. To make matters worse, we happen to be using SVN for source control, which stores metadata and versioning information in hidden .svn directories within the project folder. If I manually publish each site to the file system, and then zip them all up together, I get a 40mb file. My cspkg file, on the other hand, is over 900mb due to all the .svn folders.

    Is there some magic we can work with MSBuild here? Ideally have it do a local publish of each referenced site, and then include the output from that in the cspkg file, instead of copying the source directories in their entirety. This would also have the added bonus of ensuring that each referenced site has been built, which is a minor inconvenience with the current setup. Unfortunately I’m clueless when it comes to MSBuild, so I would have no idea how to accomplish this…

    • Bugeo

      Hi Joe I find a solution to avoid the pubblication on azure of the whole project files.
      The solution is very simple: before to publish the azure project, publish each web project localy (using file system method)
      For example if you have 2 web project in the solution, publish each one localy
      - c:publishApp1
      - c:publishApp2

      In the ServiceDefinition.csdef each site has a “physicalDirectory” that point to the publish directory.
      For example:
      Site name=”Web1″ physicalDirectory=”c:publishApp1″
      Site name=”Web2″ physicalDirectory=”c:publishApp2″

      Now publis the azure project.

      • Joe

        This post is getting a bit long in the tooth, but I did find a way to automate this, so I thought I’d share it for anyone who happens to google their way here. Doing a manual file system publish of each site before creating the Azure package (as Bugeo suggests) can quickly become unmanageable when running a lot of sites in a single role. This is especially true if you’re working in a team environment where you might not be the only person making updates to the websites.

        These instructions assume:
        1) The Azure project and the website projects are in the same solution
        2) The Azure project is named “MyAzureProject”
        3) The website projects live alongside the Azure project in the file system hierarchy

        For example:

        MySolution
        |- MyAzureProject
        |- Website1
        |- …
        |- WebsiteN

        1) For each website included in the role, right-click the project and choose Properties. On the Build Events page, set the following values.

        Pre-Build Command Line:
        rmdir “$(ProjectDir)..\MyAzureProject\Sites\$(ProjectName)” /S /Q

        Post-Build Command Line:
        %WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe “$(ProjectPath)” /T:PipelinePreDeployCopyAllFilesToOneFolder /P:Configuration=$(ConfigurationName);PreBuildEvent=”";PostBuildEvent=”";PackageAsSingleFile=false;_PackageTempDir=”$(ProjectDir)..\MyAzureProject\Sites\$(ProjectName)”

        The post-build command will do a local file system publish of the website into the MyAzureProject\Sites\WebsiteProjectName directory each time you build. The pre-build command ensures that you don’t accidentally have stale outputs should the website project not build correctly.

        2) Right-click the Azure project and choose Project Dependencies. Make sure all of the website projects are selected. This will ensure that the website projects are always built (and published locally) before creating the Azure deployment package.

        3) Edit the ServiceDefinition.csdef file as Wade describes in the section “Run Two Different Projects in the Web Role.” The value for each physicalDirectory attribute should be “Sites\WebsiteProjectName” – which is the local publish destination we specified for the website project in step 1.

        Now when you publish your Azure package from MyAzureProject, all the included sites will auto-magically build and publish themselves, and all necessary files (and nothing more) will be included in the package. Additionally, if any included website fails to build, then the package creation will also fail (rather than silently “succeeding” and creating a package with missing or stale outputs).

        • http://www.inthink.co.uk MattD

          Excellent Joe!!!! Works a dream!

          Although you may need to add the parameter /p:AutoParameterizationWebConfigConnectionStrings=False to the msbuild line to stop it from parameterising your data connections … that or workout a strategy to manage parameterisation properly;)!

  • Joe

    Sorry, the third line should say: when using a <Site physicalDirectory=”…”> element…

  • Pingback: The Good, The Bad, and Windows Azure « Daily Reflections of a Software Engineer

  • Pingback: Q&A: LinkedIn questions on the Windows Azure Platform - MSDN Blogs

  • Bugeo

    I completely agree with you.

  • Pingback: Hosted Service as a Windows Azure CDN Origin Tips - Shawn Cicoria - CedarLogic

  • Pingback: Hosted Service as a Windows Azure CDN Origin Tips - MSDN Blogs

  • Victor

    In visual studio I need to have all the website I want in the web role in just one solution? Hard to work with this. Thanks.

  • Pingback: Windows Azure with Multiple Sites in One Role not transforming 2nd web.debug.config to web.config - Windows Azure Blog

  • Pingback: Pie in the Sky (November 11th) | MSDN Blogs

  • http://grvgtm.blogspot.com/ Mark

    Its nice one. Actually I am working in 1 Winzaure cloud project. I need your assistance guidance in it.
    First question, I configured all necessary property for symbolic link at cloud. Still its not working well. I’m using PHP 5.3.6 Version. Can u guide me. how I can enable symbolic link.
    Second question . When we upload/create cloud. We get administrator or guest environment.

    I tested my code on Window Server 2008. Its working well there but not in cloud.
    Thanks
    Mark

  • Jim

    Thanks for the article – but I am confused with “Hit F5 and take a look at IIS” Not sure where to see the IIS. Is this the same as CONTROL PANEL –> ADMINISTRATIVE TOOLS –> IIS?

  • http://www.tugberkugurlu.com tugberk

    Thanks for this great post.

    What I am wondering is that how I should configure my dns records. Let’s take your first multiple app sample and we would be running two sites under one role.

    In that case, what would be the dns record of http://www.litware.com? I went through the smarx’s blog post about that but I would like to know if I should take any additional step if I use multiple sites under one role.

  • Pingback: Multiple applications per web role | PHP Developer Resource

  • Jose

    Hello:
    One question, is necesary put togheter in one same solution all webSites?
    but need host some projects webSites in one Azure Web Role, but can’t join all in one solution.
    It is possible.

    Regards

  • jashoe

    Have you ever tried this with WCF rather than web sites?
    *) Create a WCF Service Web Role project
    *) Add a second site with a VirtualApplication tag that points to a directory containing a WCF service that was published to the file system
    I have tried this with the emulator and it seems to work fine. When I publish to Azure it seems to be confused by the multiple sites. It throws an exception on deploy trying to access e:\sitesroot\2 – but there is no such directory, the sites folders are 1 and 3.

    I am trying to create a solution that pulls WCF services into an Azure package and allows me to use the VirtualDirectory and VirtualApplication tags to build up URLs to access the services.

  • Pingback: Tips for Publishing Multiple Sites in a Web Role « Michael S. Collier's Blog

  • http://www.facebook.com/d3l.hamilton Derek Hamilton

    Is this considered valid?