Build a serverless website with SAM on AWS
Tags: serverless, aws
Published: 2019-07-22 20:50:38

---
title: Build a serverless website with SAM on AWS
published: true
tags: serverless, aws
canonical_url: https://izifortune.com/serverless-website-sam-aws/
---
A website can be considered serverless when it doesn't need, directly, any server to operate. Serverless is quickly becoming a popular choice for running your services and also your entire website. Adopting a serverless architecture enables you and your organisation to focus on delivering business value. Every application must have an inherent amount of irreducible complexity states the [Law of conservation of complexity](https://en.wikipedia.org/wiki/Law_of_conservation_of_complexity), the only question is who will have to deal with it. Using serverless we are offloading this complexity to someone else can take care of this for us.

Working at RyanairLabs, I have the opportunity to work with amazing people every day and to try out s*erverless architecture* for the busiest travel website in Europe. Multiple pages of the *Ryanair* website are built using serverless technologies. Check out how we are using AWS serverless technologies in my talk at [AWS Summit London](https://www.youtube.com/watch?v=8jSu31nQi1g&feature=youtu.be).

## Serverless services

AWS has a wide range of serverless services entirely managed by AWS. What we will be focusing here are the basic building blocks to deploy a serverless website. The services are:

![AWS serverless services for a website](https://izifortune.com/dist/static/a0b9dd49dd3e05654ee8ab210d71a0b9/9f1f4/simple-architecture.png)

*Cloudfront*: a high available CDN delivering your content worldwide through edge locations. We will use *Cloudfront* to take advantage of the edge caching for our website assets, routing each user request through the nearest edge location, without the need of contacting back the origin each time. *Cloudfront* also ensures the first level of security for our website, establishing a secure connection with the clients and by using [WAF](https://aws.amazon.com/waf/).

*S3* an object storage service designed to be easy to use and managed. A website page is just a collection of static resources glued together by HTML. While developing web applications, a popular choice is to use a single page application (SPA) frameworks to reduce server-side complexity and improve interactivity. Ryanair website, for example, is built using Angular and Angularjs. Another rising technology is Javascript API Markup (JAM), fueled by static site generators. Both those technologies share a simple approach: they produce static assets which can be easily stored and served from an S3.

*Lambda at the Edge (L@E)*, you can execute any function closer to the viewer to add any additional logic between the edges and the origin. *L@E* acts as a glue between *Cloudfront* and the origin(s).

## SAM

We will use [sam-cli](https://github.com/awslabs/aws-sam-cli), an open-source framework for building a serverless application by AWS to reduce the boilerplate while working with Lambda @ Edge in the next articles.

The assumption is that we have already configured aws-cli and sam-cli, if that is not the case you can follow the guide [here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)

## Basic Infrastructure template

Building an application using sam-cli we will be using *Cloudformation* templates to describe our infrastructure resources. It gives us the ability to replicate, reuse and share infrastructure between projects quickly. A *Cloudformation* template powers all the Frontend projects that we are running in RyanairLabs, treating your infrastructure enables us to understand changes quickly, version them and collaborate on the infrastructure.

Working with *sam-cli* or *Cloudformation* we tend to keep all the resources of a project in a single file making it easier to manage and deploy the resources. What we are looking to generate in our first iteration is a simple infrastructure that can serve any assets.

![Basic infrastructure](https://izifortune.com/dist/static/a0b9dd49dd3e05654ee8ab210d71a0b9/9f1f4/simple-architecture.png)

Let's start by creating the template file called `template.yaml` with some of the basic services that we will need:

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Serverless website

Resources:
  CloudFrontOriginAccessIdentity:
    Type: 'AWS::CloudFront::CloudFrontOriginAccessIdentity'
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: 'Serverless website OA'

  CloudfrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        Comment: "Cloudfront distribution for serverless website"
        DefaultRootObject: "index.html"
        Enabled: true
        HttpVersion: http2
        # List of origins that Cloudfront will connect to
        Origins:
          - Id: s3-website
            DomainName: !GetAtt S3Bucket.DomainName
            S3OriginConfig:
              # Restricting Bucket access through an origin access identity
              OriginAccessIdentity: 
                Fn::Sub: 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}'
        # To connect the CDN to the origins you need to specify behaviours
        DefaultCacheBehavior:
          # Compress resources automatically ( gzip )
          Compress: 'true'
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
          ForwardedValues:
            QueryString: false
          TargetOriginId: s3-website
          ViewerProtocolPolicy : redirect-to-https

  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      # Change bucket name to reflect your website
      BucketName: <YOURSWEBSITE.COM>

  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
      # Restricting access to cloudfront only.
        Statement:
          -
            Effect: Allow
            Action: 's3:GetObject'
            Resource:
              - !Sub "arn:aws:s3:::${S3Bucket}/*"
            Principal:
              AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}"

```

Going through the  template file defined we have different services listed here:

`CloudfrontOriginAccessIdentity`*,* used to restrict access to the *Bucket* files only for requests coming through *Cloudfront*. We don't have to make our *Bucket* public or neither enable website hosting by using an *OriginAccessIdentity*. The *OriginAccessIdentity* will be used in the *CloudfrontDistribution Origin* and the S3*BucketPolicy.*

`CloudfrontDistribution`*,* it is *AWS* *CDN* to deliver data and content with low latency globally. There are a series of attributes in the *DistributionConfig* which controls the *CDN.* I left different comments on the file to explain further if you want to have a look at a complete list of the attributes you can follow the [User Guide]([https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html)).

`S3Bucket`*,* this is the *Bucket* where we will store all the assets of the website. Remember to give the *BucketName* a correct and unique identifier for example we can use the domain name of the website to help you remember which *Bucket* belongs to which website.

`S3BucketPolicy`*,* which defines who can access and what type of operations are permitted in the *Bucket.* Using the *OriginAccessIdentity* we are restricting read access only to *Cloudfront*.

## Deploying infrastructure

We can already start deploying our first serverless website only with the four resources listed before. We will host the website assets on the *S3Bucket,* Cache and serve content in *Cloudfront.* To deploy the infrastructure with sam-cli we need to generate first an *S3 Bucket* used to store the deployment package containing all the different inputs for your infrastructure.

On the commands below *remember* always to substitute <YOURSWEBSITE.COM> with the actual domain name of your website.

```bash
aws s3 mb s3://<YOURSWEBSITE.COM>-sam --region=us-east-1
```

After the Bucket is created we can package the application:

```bash
sam package --output-template-file packaged.yaml --s3-bucket <YOURSWEBSITE.COM>-sam
```

And finally deploy the application:

```bash
sam deploy --template-file packaged.yaml --stack-name <yourwebsite> --capabilities CAPABILITY_IAM --region us-east-1
```

We are using *us-east-1* as a default region for our infrastructure to reduce some of the limitations that we will encounter later on while defining *Lambda @ Edge*, where they can only be deployed into that region.

Creating the *Cloudfront* distribution will take some time, generally between 20-30 mins at first. The Distribution, after the deployment is completed, will have an AWS generated domain name with the format [`d3k1beyfkv2133.cloudfront.net`](http://d3k1beyfkv9165.cloudfront.net/) usable for making our first request to the website.

To test out that everything is working we can upload an `index.html` in the root folder of the *S3Bucket eg:*

```html
<html>
<body>
  <h1>Hello serverless</h1>
  <img src="https://github.com/awslabs/serverless-application-model/blob/master/aws_sam_introduction.png">
</body>
</html>
```

To upload the file we can use the *aws-cli* command:

```bash
aws s3 cp index.html s3://<YOURWEBSITE.COM> --acl public-read
```

Once the file is uploaded if we now navigate to the *Cloudfront DomainName* we should be able to see:

![Hello serverless page](https://izifortune.com/dist/static/ad25eb5c1d41a31fa5f41c7ef663e5e9/f55ca/hello-serverless.png)

In the next articles to come, we will explore how we can serve multiple pages, secure, handle rewrites, associate a domain and finally how to correctly deploy assets on our serverless website. This is a lot to cover in a single article so don't forget to follow me on twitter [@izifortune](https://twitter.com/izifortune) to get updates.

**PS:  AWS CloudDevelopmentKit**

The AWS CDK is now generally available, if you are looking to have programmatic access to create AWS resources have you can have a look at the examples below: [https://aws.amazon.com/blogs/aws/aws-cloud-development-kit-cdk-typescript-and-python-are-now-generally-available/](https://aws.amazon.com/blogs/aws/aws-cloud-development-kit-cdk-typescript-and-python-are-now-generally-available/)