ASP.NET Core apps on AWS

Laimonas Simutis
4 min readJan 9, 2020
Random image that is unrelated to the post, but looks like it might

Personal code projects are one of the best ways to keep your skills fresh and do something different from your day to day job. Most of the times I put together a project locally, work on it, push code to github but never make it accessible publicly. Recently I did ended up wanting to put my code up behind a domain name I already own and have others use it.

I put together a quick list of steps I took to get ASP.NET Core site up behind a custom domain and have it hosted and accessible over HTTPS. My goal was to keep the costs as low as possible, high redundancy/availability were not the primary concerns.

Here is what I had on the AWS side to start:

  • domain records managed by route 53
  • SSL cert for the domain

Assuming your app does not need the database, then you just need somewhere to run your .net core application. I settled with this setup:

  • EC2 t2.micro linux instance ($8.5/month)
  • Cloudfront distribution with custom origin being pointed to EC2 instance’s public hostname.
  • Route53 entries for www subdomain pointing to cloudfront distribution

Under $10/month you have a playground to experiment with cloudfront, EC2 instance, docker, etc. I thought that was a decent enough expenditure.

Cloudfront for REST APIs

Cloudfront is most commonly mentioned in the context of being a content distribution network (CDN) and caching content. But you can use it as a front for your REST APIs as well. Couple things to keep in mind when you do this:

  • make sure you don’t cache your dynamic endpoints
  • make sure to pass cookies/query parameters to the origin (in this case EC2 instance) if your app uses/needs such things

Response caching is critical to get right. You don’t want to return one user’s responses to the other user. In my case, the .net core app I deployed contained frontend endpoints that could be cached and dynamic endpoints that should not be cached. You can create multiple behaviors for a given distribution and adjust settings inside the behavior to match the desired caching setup:

Multiple behaviors that differentiated cached content

Two paths in my app that should not be cached were oauth handler path “signin-google”, and REST API paths, “api/*”. Here is the setting for the API behavior, for example:

Note how “Cache Based on Selected Request Headers” is set to All which disables caching essentially.

Deploying your code to an EC2 instance

When experimenting, my motto is to get up and running fast and automate infrastructure as I go. I knew that docker images should work well here. I went ahead and:

  • created a container registry on AWS ECR
  • installed docker on EC2 instance
  • pushed locally built docker image to ECR and then pulled images from ECR onto the EC2 instance

Creating registry is easy enough by following AWS console prompts. Building docker file locally is done via Dockerfile, I wrote a post about this before. AWS console provides a set of steps to take to pull the image down, you just need to make sure you assigned an IAM role to the instance that has the appropriate permissions to pull the images down. More information can be found here.

Once you have the docker image, you need to run it and expose the port where your app is listening.

There are a lot of moving parts here and I am glossing over myriad of details (how to build docker images locally, exposing ports on docker container and EC2 instance, etc). But I wanted to highlight the Cloudfront as a front for the APIs and how that made my setup much cheaper than if I had an ALB in front of an EC2 instance.

If this was a production grade project that needed proper up time guarantees, I would have gone with autoscaling groups for instances and multiple instances setting behind an application load balancer but for the toy project, this works more than well enough.

Iterating on the application

With a few iterations the site is up and running and I have been using daily (it’s a options trading helper of sort that I built, perhaps will talk about it more later). Now as I work on it, I will be automating the deployment of the updates and hopefully will post about it as I go in the future.

Here are the steps involved today to deploy the code changes (all manual):

  • run a single script locally that issues docker build which builds the app and generates container image with the apps executable. The same script contains code that performs AWS login and pushes the container to the ECR
  • ssh into the EC2 instance and run a single script that pulls down latest image, stops container running the app, starts a new container with the latest image

Not a big deal, but would be nice to automate all of this. I will start with the first part: building docker image and pushing to ECR on each commit.

--

--