KINDERAS.COM

Hosting a static web-app with AWS S3 and Cloudfront

This is a step by step guide on hosting a static web-site on AWS S3 and serving it through AWS Cloudfront over https.

This article contains much of the same content as the «Hosting a static web-app on a custom domain with AWS S3 and Cloudflare» article, the main difference is that this article uses AWS Cloudfront instead of Cloudflare.

Setting up a basic web-app using AWS S3

The first step is to create the code for a web app. For this example, I’ll be using a simple index.html file which prints “An example web app …..”. The only thing to note here is that you do need an «index» file to act as the entry point / root for your web-app.

Configuring Amazon S3

Log in to the AWS console and navigate to the S3 service. Here you’ll want to create a new bucket, and if you ever want to expose this app on a custom domain, then the name of the bucket must exactly match the name of your web app. It’s important that the name of the bucket matches the name of the URL exactly, not including the protocol (HTTP(s)). This is because S3 uses the bucket name for routing. Let’s for instance say that we want the url to be test.kinderas.com.

Since the example URL is test.kinderas.com, we’ll create a bucket with that name. Choose a region and click next and then next again.

On the third screen in the bucket creation wizard, uncheck the boxes under «Manage public Access control lists (ACLs) for selected buckets». If you forget this you can do it later by selecting the bucket and clicking the «Edit public access setting» button on the overview page.

Allow the bucket to be public

In order to have S3 use this bucket for website hosting, we need to configure a couple of things. Click on the name of the bucket and select the «Properties» tab on the top. Find the «Static website hosting» tab and click it. For the «index document» enter the filename of the entry point file, in this example, this is called «index.html». You can also upload a file which is used for errors.

Note the «Endpoint» URL at the top of the dialog. We’ll need this URL for configuring the Cloudfront distribution.

Website hosting dialog

Now we need to upload our web-app to have something to use for testing. Select the «Overview» tab in your bucket and upload your app, making sure that the «index.html» file is at the root of the bucket.

The web-app will not work just yet. If you visit the endpoint URL from the static website dialog it will just give you a permission error. To make it work we’ll need to allow access to the bucket from the outside world.

Select the «Permissions» tab from the top of the bucket settings and then select the «Bucket policy» tab. You should now see the «Bucket policy editor». Paste the JSON below into the editor and do notice the «YOUR BUCKET NAME HERE» part, replace that part with your bucket name. Also replace the «SOME LONG STRING» with an actual (different) long string. This string will be used in Cloudfront to make sure no one can visit the S3 bucket directly over http. See the image below for a full example using the name from the example web-app.

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "PublicReadGetObject",
			"Effect": "Allow",
			"Principal": "*",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::YOUR BUCKET NAME HERE/*",
			"Condition": {
				"StringEquals": {
					"aws:UserAgent": "SOME LONG STRING"
				}
			}
		}
	]
}

Website hosting dialog

Configuring Cloudfront

Navigate to Cloudfront in the AWS console and click the «Create Distribution» button. You’ll want a «Web» distribution.

Origin settings

Origin Domain Name:

Paste the URL (without http) from S3 the website hosting dialog here.

Origin Custom Headers:

The header name should be User-Agent and the value is that «SOME LONG STRING» you added in the S3 Bucket Policy json.

Default cache behavior setting

If you don’t want caching then set «Minimum TTL», «Maximum TTL» and «Default TTL» to 0 (zero). You can also configure how to handle http to https requests and forwarding cookies and query strings here.

Distribution Settings

(optional) If you want to use a custom domain name you need to list it in the «Alternate Domain Names». You should also create a custom certificate if you want to use a custom domain.

When you’re done click «Create distribution» and wait…quite a while. What it’s done you can visit your web-app at either the custom domain or the default Cloudfront domain, you’ll find this by opening the distribution and looking for «Domain Name».

Website hosting dialog

Optimizing your AWS Lambda bundle size - Quicktip

When working with Node.js on AWS Lambda there are some limits one should be aware of. One of these concerns the bundle size, in other words the total file size of your code folder running on the Lambda function. Currently your code bundle must be below 250 MB (unzipped, including layers).

The notorious «node_modules» folder might cause you some grievance in the bundle size departement. Especially if you’re importing the aws-sdk and/or other humongous dependencies. However, there is one really simple method you can use to minimize the size of the «node_modules» folder.

In two steps

  1. Move all the dependencies not needed for actually executing the code* to either «devDependencies» or «optionalDependencies». This might be things like TypeScript, testing frameworks, serverless and so on.
  2. When you build for deploy, install dependencies using «npm install —only=prod —no-optional». This will skip all those dependencies you moved in step 1.
  3. Watch your «node_modules» folder shrink in size

(*) Node.js projects often contain dependencies used for building and testing the project during development. Packages like TypeScript, Jest, Mocha, Serverless are usually not needed when the code is running in the AWS Lambda environment. Hence the code for such dependencies will just add unnecessary bytes to the bundle size and should be omitted from the production bundle.

Carry on.

AWS: Hosting a static web-app on a custom domain with AWS S3 and Cloudflare

This is a step by step guide on hosting a static web-app on Amazon S3 and exposing it using a custom (https) domain through Cloudflare.

This article assumes some prior knowledge of both Amazon S3 and Cloudflare.

The example web-app used in the article will be hosted using a subdomain, however, the same approach will work for root domains as well.

About Amazon S3 and Cloudflare

If you are familiar with both S3 and Cloudflare you can skip this section.

Amazon S3 is a hosted storage service which allows you to upload files and configure permissions for these files. S3 also allows a so called bucket (a container for files) to be used as a static web hosting service. You can read more about Amazon S3 by visiting their site. https://aws.amazon.com/s3/

Cloudflare is a service which offers CDN, DNS and many other products. We’ll be using it for its DNS product in this article. Read more about Cloudflare on their own site. https://www.cloudflare.com

Setting up a basic web-app

The first step is to create the code for a web app. For this example, I’ll be using a simple index.html file which prints “An example web app …..”. The only thing to note here is that you do need an «index» file to act as the entry point / root for your web-app.

The example web-app is be hosted at https://web-app-test.kinderas.com.

Configuring Amazon S3

Log in to the AWS console and navigate to the S3 service. Here you’ll want to create a new bucket with the same name as the URL for your web app. It’s important that the name of the bucket matches the name of the URL exactly, without the protocol (HTTP(s)), since S3 uses the bucket name for routing.

The example URL is web-app-test.kinderas.com, so we’ll create a bucket with that name. Choose a region and click next and then next again.

The bucket name must match the URL

On the third screen for the bucket creation wizard, uncheck the boxes under «Manage public Access control lists (ACLs) for selected buckets». If you forget this you can do it later by selecting the bucket and clicking the «Edit public access setting» button on the overview page.

Allow the bucket to be public

In order to have S3 use this bucket for website hosting, we need to configure a couple of things. Click on the name of the bucket and select the «Properties» tab on the top. Find the «Static website hosting» tile and click it. For the «index document» enter the filename of the entry point file, in this example, this is called «index.html». You can also upload a file which is used for errors.

Note the «Endpoint» URL at the top of the dialog. We’ll need this URL for testing and for configuring the domain in Cloudflare.

Website hosting dialog

Now we need to upload our web-app to have something to use for testing. Select the «Overview» tab in your bucket and upload your app, making sure that the «index.html» file is at the root of the bucket.

Website hosting dialog

The web-app will not work just yet. If you visit the endpoint URL from the static website dialog it will just give you a permission error. To make it work we’ll need to allow access to the bucket from the outside world.

Select the «Permissions» tab from the top of the bucket settings and then select the «Bucket policy» tab. You should now see the «Bucket policy editor». First We’ll create a simple policy to verify that the basic are working. Paste the JSON below into the editor and do notice the «YOUR BUCKET NAME HERE» part, replace that part with your bucket name. See the image below for a full example using the name from the example web-app.

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "PublicReadGetObject",
			"Effect": "Allow",
			"Principal": "*",
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::YOUR BUCKET NAME HERE/*"
		}
	]
}

Replace the bucket name with your own bucket name

The policy above grants public access to anybody wanting to visit your web-app at the S3 generated URL. If this is all you want, then you are done. However, if you want to use browser features dependent on https you’ll want to read on.

Next, we’ll modify the permissions to only allow traffic from Cloudflare. We’ll do this by adding a condition to the policy stating that only IP addresses from Cloudflare should be able to access the bucket.

The new full policy looks like this (below). Notice the «YOUR BUCKET NAME HERE» on line 9. You know what to do. Update it, save it. You will no longer be able to access the bucket from the S3 URL. Moving on to the Cloudflare setup below the policy gist. In the gist we are whitelisting the Cloudflare URLs found here: https://www.cloudflare.com/ips/

Configuring Cloudflare

Important note about security! Configuring Cloudflare to expose your web-app on an https URL does not mean that the traffic from Cloudflare to the S3 bucket is encrypted. It only implies to the browser that the web-app is hosted on an https server, allowing certain features which would otherwise be unavailable.

Log in to Cloudflare and navigate to the DNS tab. You’ll need the URL from the static website dialog in the S3 setup section.

Add a new CNAME record. In this example, I’m using a subdomain so I’ll add «web-app-test» for the «Name» field and then the URL (without http://) from the static website dialog in the S3 setup in the «Domain» field. Leave the little orange cloud on. Click «Add record».

CloudFlare setup

If you have the Crypto -> SSL section of Cloudflare set to “Full” you’ll need to take an additional step. If it’s set to “Flexible” you are done and the URL should work. Please don’t change this setting in the SSL tab to Flexible if it’s set to Full, doing this will affect your entire domain!

[Optional - see above]. In Cloudflare, go to «Page Rules» and create a new rule. The rule should state that when a request to the web-app is encountered it should use “Flexible” SSL. See the image below for how this applies to the example URL.

CloudFlare setup

You can now test your web-app at the proper URL, for this example that would be https://web-app-test.kinderas.com

Sources

AWS: Using Elastic Beanstalk as a private backend for the API Gateway

When working with an API Gateway in Amazon Web Services (AWS) you typically don’t want the services themselves to be publicly available on the Internet. A public service would only create the need for extra layers of protections such as client certificates or service keys, neither of which would properly prevent a, for example, a DoS attack. A better approach is to either use Lambdas (which are private by default) or (if you can’t use Lambdas) simply keep the services within a private cloud (a «VPC» in Amazon terminology) and provide access to them only through the API itself.

This quick-guide intends to explain the basics of configuring a private backend/service utilizing an Elastic Beanstalk app (EBS) residing within a VPC. The methods of the EBS will be made available through the API Gateway using a VPC Link.

Note: As of this writing the AWS API Gateway only allows a maximum of 5 VPC Links for one API Gateway in the same account. You can ask to have this limit increased through AWS support.

VPC

First, you will need to configure a Virtual Private Cloud (VPC), I will not cover this step here since it would require a separate post. However, I would recommend that you take a look at the following video for directions if you’re unsure how to accomplish this step.

Elastic Beanstalk

The second step is setting up an Elastic Beanstalk (EBS) application. (This guide assumes you’re using the AWS console). One of the advantage of using EBS over pure EC2 instances is that EBS comes with a bunch of pre-configured features such as auto scaling and rolling updates. You can achieve the same goal (private service) using a just some EC2 instances and a Network Load Balancer (click the link to see how) of course, but for this guide I’ll assume that you are using an EBS application.

The first step is to create an EBS application, followed by creating a new environment. The environment is actually where all the configuration takes place. Refer to https://aws.amazon.com/elasticbeanstalk for more information on how EBS actually works.

When setting up a new environment choose the “Web server environment” for now. Give your environment a name and choose a platform (I’m using Node.js). Just use the “Sample application” if you don’t have a finished app bundle.

Important: Click the «Configure more options» button, not the «Create Environment»!

Beanstalk setup

After you have clicked the «Configure more options» button you’ll find yourself on the «Configure » page and you’ll see three radio buttons titled «Configuration presets». Choose the «High availability» option. This will give us the option to configure a Load Balancer. Now open / «modify» the «Load Balancer» tile. Choose the «Network Load balancer» and click «Save». The API Gateway VPC Link will only work with Network load balancers.

In the «Network» tile (left bottom one), select the VPC you have already created. Under «Load Balancer settings» the «Visibility» setting should be «Internal» since this service should not be accessible from the Internet. Select the private subnets (for all zones in your VPC) for both the load balancer and the subnets. No public subnets should be checked. Click «Save».

Setup anything else like scaling and so on and then click “Create environment».

API Gateway

Create an API Gateway if you haven’t done so already.

  1. In the left menu, select «VPC links»
  2. Give the VPC link a name and select the Load Balancer you created under the EBS section in the «Target NLB». It will only show the (cryptic) name of the load balancer here, but if you go to the EC2 service, and select «load balancers» you can match any tags to the Load Balancer name.
  3. Click «Create».

While you wait for the connection to be created you can configure the API. I would recommend using stage variables to store a reference to the VPC link id. This would allow you to easier maintain several stages pointing to separate backends. AWS documentation for using stage variables to refer to a VPC link.

To configure a method in the api using the VPC link, see the following image.

Beanstalk setup

In this example the «VPC link» is set as a stage variable, the same goes for the «Endpoint URI». As already stated, but worth repeating, this is a good idea because it makes it considerable easier to deal with multiple stages. You have to set this up for each of the methods in your api.

That’s it.

A simple drawing app using JavaScript

The HTML Canvas element was introduced by Apple in 2004. It was originally created to power the Dashboard concept introduced in OS X 10.4. The Canvas element was a part of Apple WebKit from 2004, in 2005 it became a part of Mozilla browsers and then Opera. Today, all browsers worth using sports support for the Canvas element. In this article I’ll investigate demo involving a simple line drawing on a Canvas element.

Two people drawing with different input devices

To be a proper red line drawing application today there are several considerations to be taken into account.

  • You must support both touch devices and dusty old mouse enabled devices
  • You must take Hi-res or retina devices into consideration. You wouldn’t want blurry red lines now would you.
  • The thing needs to be performant

Take a look at the full CoffeeScript code for the demo. It has a bunch of comments.

Supporting touch and mouse events

if 'ontouchstart' of window
      # .. then switch to touch mode
      @mode = 'touch'

From line 8 in the code. Here we check if the event «ontouchstart» exists in the window object. If it does we know that this device supports touch events. We then keep this result in the «mode» property for use later on. Easy peasy. Let’s add som listeners.

if @mode is 'touch'
  canvas.addEventListener 'touchstart', @, false
  canvas.addEventListener 'touchmove', @, false
  canvas.addEventListener 'touchcancel', @, false
else
  canvas.addEventListener 'mousedown', @, false
  canvas.addEventListener 'mouseup', @, false

We use the «mode» property and add touch and mouse listeners. Note that we do not add any listeners for when the mouse is moving, this we do in the mouse up and down events. See the section at the end of the article as an explanation as to why.

So, what the hell does it mean to add a listener to “@”? In CoffeeScrip the “@” is the same as “this” in JavaScript. By adding event listeners to “this” we can implement the half-magical «handleEvent» method. This method will not only handle all events on “this”, but it will also maintain scope, removing the need for «Function.bind». If you didn’t know that, you mind has just been blown - right?! Moving on.

Supporting retina quality graphics

This is a tiny bit trickier, but not much. What we need is to know the scale factor of the display of the device. We can then use this number to calculate the size of the canvas itself and how lines are drawn.

Let’s start with finding the scale factor.

@scaleFactor = window.devicePixelRatio || 1;

If there is a property on window called «devicePixelRatio» we use that value, if not we default to 1, which basically means that it’s a “normal” display or a piece of shit old browser. The «devicePixelRatio» will output a multiplier, like 2 for the iPad Mini Retina. This number gives us the value on which to multiply.

Scaling the canvas element correctly

Calculating the size of the actual canvas element looks something like this (if you want the canvas to span the entire browser window).

canvas.width = window.innerWidth * @scaleFactor
canvas.height = window.innerHeight * @scaleFactor

On a “normal” display the width of the canvas would be equal to the inner width of the window. On an iPad Mini Retina it would be «innerWidth x 2», because the «scaleFactor» of the iPad Mini Retina is 2.

It’s important to note that the canvas element is now twice or more the size of what you intend to display it at. You fix that by setting the style width and height to the intended display size, which in the case of an iPad Mini Retina will be half the size of the canvas backing store (the actual drawing size).

Scaling the drawing context

@ctx = canvas.getContext '2d'
@ctx.strokeStyle = 'rgba(255,0,0,1)'
@ctx.lineWidth = 5 * @scaleFactor

The «ctx» property holds the 2d drawing context of the canvas. On the second line we tell the context that any lines drawn, should be red - of course. On the third line the thickness of the line is set and like we did with the canvas backing store we multiply with the scale factor. Remember that a canvas on the iPad Mini Retina is twice the size of what it’s displayed as (yep, yep). If we didn’t multiply the line thickness if would actually display at 2.5..and that would be stupid because we want it to look the same everywhere, except it will look sharper on retina displays.

@ctx.moveTo e.touches[0].pageX * @scaleFactor, e.touches[0].pageY * @scaleFactor
#...
@ctx.lineTo e.touches[0].pageX * @scaleFactor, e.touches[0].pageY * @scaleFactor

The same multiplication also needs to happen every time we either move the drawing pointer or draw a line. If we didn’t do this the line would be drawn with an offset of the finger or the cursor - again, we don’t want that. And that’s it, ha!

Other stuff

For mouse mode, it’s also a good idea to remove the «mosemove» listener when the move isn’t pressed. This way you won’t get a bunch of events firing all over the place when you really don’t need them.

That’s all folks.