Deploy Multiple Sites to single AWS Instance

Demis Bellot edited this page Oct 25, 2016 · 7 revisions

This page has moved to docs.servicestack.net


by Darren Reid

Why deploy multiple sites to a single AWS instance?

Deploying to Cloud and PaaS providers can provide a lot of utility by taking advantage of their integration, elasticity and autoscaling benefits. In a lot of cases Cloud providers are catered towards supporting popular flagship applications requiring very high levels of traffic. However, there are many times where your website only needs to cater for a specific use-case serving a niche audience, which would benefit from the simplicity and control of deploying and hosting multiple Websites on a single AWS instance.

Amazon’s current tools for AWS, like AWSDeploy is designed around one application per VM instance. Whilst this makes autoscaling easier for them to manage, it also ends up being a lot more costly and wastes a lot of overhead for when your servers have the additional headroom that can easily support having multiple sites:

Simple deployments with TeamCity and Octopus Deploy

The optimal setup we found to automate ASP .NET deployments to AWS were to use TeamCity for the Build and Continuous Integration and Octopus Deploy for automating deployments. If you are not familiar with them, both TeamCity and Octopus Deploy are best-in-class commercial tools with generous free-usage quotas, providing a flexible and hassle-free experience. TeamCity specializes in supporting a vast number of different development environments whilst Octopus Deploy is highly specialized in providing a flexible deployments for .NET applications centered around NuGet packages, with automatic versioning and backups as well as rich insights into the deployment process.

Both these tools work well together thanks to Octopus Deploy's integration with TeamCity which offers a TeamCity plugin containing custom build tasks to integrate with Octopus Deploy.

TeamCity Installation and Setup

TeamCity can be downloaded from here. The only requirement is that it's able to access your version control system and the Octopus Deploy server. The Install wizard walks you through the installation which also has Installation instructions that you can refer to.

Once installed, there are a few steps to add to ensure it is configured and ready to use with Octopus Deploy.

  1. Setup TeamCity as a native NuGet server
  2. Install Octopus Deploy TeamCity plugin (How to install a Plugin, download Octopus Deploy TeamCity plugin)

For this tutorial I’ve used TeamCity 8.1 and Octopus Deploy 2.5.6.

To turn on TeamCity’s native NuGet server, go to Administration at the top right, select NuGet Settings on the left menu and click the Enable button.

If you are missing the public feed and want Octopus Deploy to not have to use authentication, you have to enable the use of Guest users. Under Server Administration, select Authentication and Allow login as guest user under General Settings.

You will also need to enable the use of NuGet.exe in your restore and build steps, select the NuGet.exe tab from the NuGet Settings screen and either Fetch or Upload NuGet.

If you are using TeamCity version 8 or greater, you can use the Plugin List menu under Server Administration to help you upload a plugin.

Once installed, restart the TeamCity server by restarting its windows service, the plugin should now appear in the Plugin List.

Team City project build configurations

Now that we have TeamCity configured, we can create a project and build configurations that will produce our NuGet packages for Octopus Deploy to consume.

An overview of the setup we’re using is for every web application, we are going to have a project with at least 2 build configurations. One for building the application NuGet package and one for deploying it to Octopus Deploy. The simplest Build Application build configuration will itself, have two steps, Restore NuGet Packages and Build Package. Restore from NuGet is used under the assumption that we want to automatically restore our application dependencies using NuGet 2.7+ and pull them in at build time if they aren’t already cached.

As a quick guide, this is using the following configuration:

  • Runner type:
    • NuGet Installer
  • NuGet.exe:
    • 2.8.2 (anything above 2.7 should be fine)
  • Package sources:
    • NuGet V2 API url (include your own if needed here)
  • Restore Mode:
    • Restore (required NuGet 2.7+)

Everything else is left as default or application specific like Path to solution file. Here is a screen shot of this configuration used for the StackApis example application.

The next step in the first build configuration is to package the application into a NuGet package. The configuration for this step is as follows.

  • Runner type:
  • Visual Studio
  • Visual Studio:
  • Microsoft Visual Studio 2013
  • Targets:
  • Rebuild;
  • Run OctoPack:
  • true
  • OctoPack package version:
  • 1.0.%build.number%

The rest of the settings are project specific or defaults. Here's a screenshot of the StackApis configuration:

To make it more automated, a "Trigger" should be added so that every time a checkin occurs on the configured VCS, a build is queued. Select Triggers from within the Build Configuration screen to add a VCS Trigger.

If you are missing the Octopus Packing section seen in the screenshot above, it means you don’t have the Octopus Deploy TeamCity plugin installed or it isn’t working.

Another requirement is that the application you want to package will require a new NuGet dependency on OctoPack. OctoPack is a package for Octopus Deploy which adds a new build target to your application to be used with the TeamCity plugin.

You can add it to your application with the following NuGet command in Visual Studio:

PM> Install-Package OctoPack

Once added, the TeamCity plugin will do the rest if the checkbox is ticked. It is worth mentioning that because OctoPack is running as a new target, it can be manually incorporated into an existing building configuration using MSBuild by just adding the target. It’s also an open source project so more information can be found on the OctoPack Github page.

The next build configuration has a single step which is responsible for notifying Octopus Deploy to proceed with the deployment of a specific project to a specific environment. The reason we have these steps has two different build configurations is due to the requirement of having the NuGet packages published on the TeamCity NuGet feed. These packages will not appear until the build configuration that produces the package has completed. By separating them, we’re ensuring that TeamCity will have published the latest package version ready for Octopus Deploy.

Due to use of API keys and specific values that need to exist in Octopus Deploy first, we need to leave this next TeamCity step until after Octopus Deploy is setup. Once you have Octopus Deploy setup, skip to the TeamCity integration section.

Octopus Deploy installation and initial setup

Octopus Deploy is a NuGet package centric continuous deployment system for .NET applications that is extremely flexible when it comes to deployment configurations. It has a strong focus on user experience, installation and setup is very quick intuitive. They even have a great set of introduction videos that take you through getting up and running with Octopus Deploy. Also well maintained documentation and active forums if you get stuck.

See this Installation Video Guide to walk you through Installing Octopus Deploy, once Installed you’ll be able to access its web interface to manage your Environments, Projects and Libraries. For the moment, we’ll want to Create an Environment for our AWS instance. Create an environment for your applications, e.g. Production.

We’ll also need to add TeamCity as a NuGet feed. To do this, navigate to Library and select External Feeds:

Like most of the UIs in Octopus Deploy, it’s pretty intuitive and self-explanatory. The URL for the feed can be retrieved from the TeamCity Administration page on NuGet Settings. Select the public feed, or private feed and provide a valid TeamCity user credentials.

Octopus Deploy needs somewhere to deploy too so we need to create an Environment and add our AWS instance as a Tentacle. A ‘Tentacle’ is just a machine that can be deployed too from Octopus Deploy. To do this, we need to be able to remotely access the AWS instance to install the tentacle client, the easiest way to do this is using RDP.

Once installed, the remote machine will appear in your host Octopus Deploy server under the environment is was added too.

You’ll want to add this machine to a Role, in this example, the machine has just one role, ServiceStackExamples. Roles are "tags" that are used to target deployments steps which will look at soon.

Setting up Octopus Deploy Projects

The project is where specific “Process Steps” can be added as a part of your automated deployment process. These can include one or more NuGet Packages as well as PowerShell steps, email, Deploy to Azure, FTP or even a manual intervention step. For our simple project we will need the Deploy NuGet Package step as well as an additional PowerShell step which we’ll look at later.

To create a new project, first view all projects under the Projects->All menu and then select Add Project at the top right. In this example, the project is called StackApis.

Now that we have created an environment and a project, we need to add some steps. Add a Deploy NuGet Package step to your project.

Process steps are extremely configurable pieces that can do as little or as much as you’ll need. The first thing we need to do is pick a target role/roles. In our example, this is ServiceStackExamples. This configures this deployment step to target machines with the “ServiceStackExamples” role attached to it.

We will also have to tell the step where to access our application via a NuGet feed. If you added TeamCity’s NuGet feed as an External Feed in the previous instructions, it should be available from the NuGet feed drop down list. You will also need to specify the name of the package. If you are using OctoPack to package up your application, this should be the same name as your application.

OctoPack has created a .nuspec file that includes all your application files and configured the ID of your package also, this was what this option is referring too.

At the very bottom we can also restrict the step to only be used in a limited set of environments. We will be adding Production here as we only want this step to be process for the Production environment.

Each process step can also have additional features added, for the deployment step, we get the following list.

For this example, we are deploying an ASP.NET application, so one additional 'Feature' we will need, is an IIS web site and application pool for the application. This will handle things like bindings, application pool identity, SSL and other aspects of managing IIS. We don’t need SSL in this instance, so we’ll just go with a basic configuration.

Octopus Deploy has an introduction video for setting an ASP.NET deployment here.

AWS Performance issues with Elastic Block Store

One issue that was discovered during this process was high latency on the applications we have deployed when compared to applications deployed by the AWSDeploy tool. This was due to permissions of the folder being deployed too by Octopus Deploy. To fix this issue, we added an additional step and PowerShell script to add the appropriate permissions to the folders where the latest version of the application was deployed.

Add a new step that runs after the deployment step created in the section above. Select Run a PowerShell script as the process step template. Add the same machine role as deployment step and add the following PowerShell script:

$Acl = Get-Acl "C:\inetpub"
$ArIIS = New-Object  system.security.accesscontrol.filesystemaccessrule("IIS_IUSRS","ReadAndExecute","Allow")
$appPoolName = $OctopusParameters['Octopus.Action[Deploy Package].IISWebSite.ApplicationPoolName']
Write-Output $appPoolName
$Acl.SetAccessRule($ArIIS)
$appPath = $OctopusParameters['Octopus.Action[Deploy Package].Output.Package.InstallationDirectoryPath'] 
Set-Acl $appPath $Acl
$appPoolAclParam = "IIS AppPool\$appPoolName`:(OI)(CI)M"
cmd /c icacls "$appPath" /grant "$appPoolAclParam"

Most of the script above is generic except for 2 parts where the exact name of the previous deployment step is used to access an Octopus Deploy variable. Octopus.Action[<insert name of your process step>] can be updated to target the correct step. The "Insert a variable" menu on the right of the script input box can help when trying to find the right variable you need to use in your scripts.

This script updated the permissions and gives Modify access to folder where your application is deployed and to the application pool identity that is running your application.

TeamCity Integration

Now that our project is setup in Octopus Deploy, we will need an API key from Octopus Deploy to be used by TeamCity to fire off the deployment step. To get the API key, access your user profile from the top right of the Octopus Deploy dashboard and select the API keys tab.

Note, make sure you save the API key somewhere as we will need to paste it into TeamCity build configuration.

Now navigate to your TeamCity build server and create a new build configuration that runs after the initial Build Package step in your TeamCity project. This build configuration does not need a VCS source, but it does need a single build step and a trigger.

Create a new build step with the following configuration.

  • Runner type:
  • Octopus Deploy: Create release
  • Octopus URL:
  • API key:
  • The API key you just created
  • Octopus version:
  • 2.0+
  • Release number:
  • 1.0.%dep..system.build.number%
  • Deploy to:
  • <Octopus Deploy environment name, eg Production>

Below is a screenshot of the StackApis Deploy step in TeamCity:

Notes on Release number, by using the method shown above, running the deploy step manually even with correct snapshot and artifact dependencies will not work due to Octopus Deploy failing as the version from a previous build would already exist. This might be a matter of preference, but since Octopus Deploy as very nice ways of doing re-releases and rollbacks, it makes sense to only fire the deployment of a new version of the package from Octopus Deploy itself and not from TeamCity. If you want to have this control from TeamCity, the Release number can be changed to x.x.%build.number%, this will get automatically incremented even if run manually. If you are having issues with build and release numbers, it can be left blank for Octopus Deploy to increment, however this might make it harder to related TeamCity build numbers with release numbers.

You will also need to add a trigger to this step so it is fired on the completion of a successful build of the previous build configuration which produced the NuGet package. One way to achieve this is to first add a snapshot and artifact dependency on the Build package step.

Once these dependencies are setup, add a trigger.

This means the build configuration will run after a successful build of the package.

If you now navigate to your project in TeamCity, you should see two build configurations. Here is an example of StackApis:

Now if we Run the Build step above from TeamCity, the Deploy step should also fire. If they are successful, we should be able to navigate to our Octopus Deploy Projects dashboard to hopefully see the following.

This means your TeamCity deploy step successfully kicked off your Octopus Deploy step. This may take a while as it requires your application package to be transferred to your AWS instance and this will vary based on bandwidth available and size of your application.

With any luck, your deployment will be a success, however Octopus deploy does log quite a lot of information about the tasks being performed so the best place to look for troubleshooting is the Task Log. Click on your latest release and select the Task Log tab. To see more information, select Verbose at the top right of the Task Log. This will show you information like remote paths, machines, versions etc etc.

Adding more applications

Since TeamCity and Octopus Deploy are setup, adding additional applications becomes easier. Getting multiple applications onto the one AWS instance, or any other Octopus Deploy Tentacle, is a matter of creating new projects for both TeamCity and Octopus Deploy targeting the same environment.



  1. Getting Started

    1. Creating your first project
    2. Create Service from scratch
    3. Your first webservice explained
    4. Example Projects Overview
    5. Learning Resources
  2. Designing APIs

    1. ServiceStack API Design
    2. Designing a REST-ful service with ServiceStack
    3. Simple Customer REST Example
    4. How to design a Message-Based API
    5. Software complexity and role of DTOs
  3. Reference

    1. Order of Operations
    2. The IoC container
    3. Configuration and AppSettings
    4. Metadata page
    5. Rest, SOAP & default endpoints
    6. SOAP support
    7. Routing
    8. Service return types
    9. Customize HTTP Responses
    10. Customize JSON Responses
    11. Plugins
    12. Validation
    13. Error Handling
    14. Security
    15. Debugging
    16. JavaScript Client Library (ss-utils.js)
  4. Clients

    1. Overview
    2. C#/.NET client
      1. .NET Core Clients
    3. Add ServiceStack Reference
      1. C# Add Reference
      2. F# Add Reference
      3. VB.NET Add Reference
      4. Swift Add Reference
      5. Java Add Reference
    4. Silverlight client
    5. JavaScript client
      1. Add TypeScript Reference
    6. Dart Client
    7. MQ Clients
  5. Formats

    1. Overview
    2. JSON/JSV and XML
    3. HTML5 Report Format
    4. CSV Format
    5. MessagePack Format
    6. ProtoBuf Format
  6. View Engines 4. Razor & Markdown Razor

    1. Markdown Razor
  7. Hosts

    1. IIS
    2. Self-hosting
    3. Messaging
    4. Mono
  8. Security

    1. Authentication
    2. Sessions
    3. Restricting Services
    4. Encrypted Messaging
  9. Advanced

    1. Configuration options
    2. Access HTTP specific features in services
    3. Logging
    4. Serialization/deserialization
    5. Request/response filters
    6. Filter attributes
    7. Concurrency Model
    8. Built-in profiling
    9. Form Hijacking Prevention
    10. Auto-Mapping
    11. HTTP Utils
    12. Dump Utils
    13. Virtual File System
    14. Config API
    15. Physical Project Structure
    16. Modularizing Services
    17. MVC Integration
    18. ServiceStack Integration
    19. Embedded Native Desktop Apps
    20. Auto Batched Requests
    21. Versioning
    22. Multitenancy
  10. Caching

  11. Caching Providers

  12. HTTP Caching

  13. CacheResponse Attribute

  14. Cache Aware Clients

  15. Auto Query

  16. Overview

  17. Why Not OData

  18. AutoQuery RDBMS

  19. AutoQuery Data

  20. AutoQuery Memory

  21. AutoQuery Service

  22. AutoQuery DynamoDB

  23. Server Events

    1. Overview
    2. JavaScript Client
    3. C# Server Events Client
    4. Redis Server Events
  24. Service Gateway

    1. Overview
    2. Service Discovery
  25. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  26. Plugins

    1. Auto Query
    2. Server Sent Events
    3. Swagger API
    4. Postman
    5. Request logger
    6. Sitemaps
    7. Cancellable Requests
    8. CorsFeature
  27. Tests

    1. Testing
    2. HowTo write unit/integration tests
  28. ServiceStackVS

    1. Install ServiceStackVS
    2. Add ServiceStack Reference
    3. TypeScript React Template
    4. React, Redux Chat App
    5. AngularJS App Template
    6. React Desktop Apps
  29. Other Languages

    1. FSharp
      1. Add ServiceStack Reference
    2. VB.NET
      1. Add ServiceStack Reference
    3. Swift
    4. Swift Add Reference
    5. Java
      1. Add ServiceStack Reference
      2. Android Studio & IntelliJ
      3. Eclipse
  30. Amazon Web Services

  31. ServiceStack.Aws

  32. PocoDynamo

  33. AWS Live Demos

  34. Getting Started with AWS

  35. Deployment

    1. Deploy Multiple Sites to single AWS Instance
      1. Simple Deployments to AWS with WebDeploy
    2. Advanced Deployments with OctopusDeploy
  36. Install 3rd Party Products

    1. Redis on Windows
    2. RabbitMQ on Windows
  37. Use Cases

    1. Single Page Apps
    2. HTML, CSS and JS Minifiers
    3. Azure
    4. Connecting to Azure Redis via SSL
    5. Logging
    6. Bundling and Minification
    7. NHibernate
  38. Performance

    1. Real world performance
  39. Other Products

    1. ServiceStack.Redis
    2. ServiceStack.OrmLite
    3. ServiceStack.Text
  40. Future

    1. Roadmap
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.