aws-cdk

Hosting Static Website With S3 Bucket and Cloudfront

Hosting Static Website With S3 Bucket and Cloudfront

index

Hosting Static Website With S3 Bucket and Cloudfront

AWS CDK

AWS CDK is a software development framework that allows developers to define cloud infrastructure using programming languages including TypeScript, JavaScript, Python, Java, and C#. It helps reduce manual tasks, improves collaboration among teams, and enables the creation of reusable and version-controlled infrastructure components.

AWS CDK integrates with AWS CloudFormation, which provisions the resources defined in the code using best practices for reliability, scalability, and security.

AWS CDK offers developers various benefits, including the ability to simplify infrastructure management, improve efficiency by using high-level APIs, and leverage familiar programming languages. The framework integrates with AWS services, follows best practices for reliability and security, and enables cost optimization through the definition of optimized infrastructure components.

To-Do App Architecture Design

I would like to present to you the straightforward To-Do web application and its architecture, which I intend to distribute as a static web page from an S3 bucket without necessitating its hosting as a static website. AWS, being a reputable cloud computing service provider, offers various services for making static web pages accessible to the public. Among the available options is the use of the CloudFront service.

To-Do app AWS Architecture

AWS CloudFront

Amazon Web Services (AWS) offers a content delivery network (CDN) solution known as AWS CloudFront. It is intended to provide consumers all around the world with minimal latency and fast transfer speeds for delivering static and dynamic web content, including HTML, CSS, JavaScript, videos, and other files.

It also provides security features and seamless integration with other AWS services such as Amazon S3 and Elastic Load Balancing, which makes content delivery easier to manage and configure.

Coding Time

I invite you to peruse the entire code on my GitHub, repository and meticulously execute the following steps to deploy the To-Do web application onto an S3 bucket using AWS CDK:

  1. Generate an AWS CDK typescript solution.

  2. Establish an S3 bucket to contain the To-Do application code.

  3. Deploy the To-Do application code into the designated S3 bucket.

  4. Establish a CloudFront distribution to host a static To-Do web application.

  5. Deploy the AWS CDK solution to host the To-do application.

  6. Generate an AWS CDK typescript solution


I am going to use the AWS CDK node.js library “aws-cdk” and the typescript language to code. They provide the CLI command to build a new CDK solution in typescript as below. For additional information, I would like to refer you to the AWS web page., where you can find more detailed information.

cdk init aws-cdk-to-do-app - language typescript

  1. Establish an S3 bucket to contain the To-Do application code.

After we create our CDK solution, we should create our S3 bucket like the below:

 private createS3Bucket(): IBucket {  
        return new Bucket(this.scope, 'aws-todo-app-frontend-bucket', {  
            bucketName: 'aws-todo-app-frontend-bucket-1234567875',  
            encryption: BucketEncryption.S3_MANAGED,  
            publicReadAccess: false  
        })  
 }

3. Deploy the To-Do application code into the designated S3 bucket

Now we should move the To-Do app HTML code into the S3 bucket. The BucketDeployment class is provided by the CDK library for this purpose. I will copy the code under the “./to-do-app” folder, which I created, save the to-do-app HTML code, and deploy it in the S3 bucket.

 private deployS3Bucket(s3Bucket: IBucket) {  
        new BucketDeployment(this.scope, 'deploy-aws-todo-app-frontend', {  
            sources: [Source.asset('./to-do-app')],  
            destinationBucket: s3Bucket  
        });  
  }
  1. Establish a CloudFront distribution to host a static To-Do web application.

CloudFront Distribution needs to be able to reach the S3 bucket, this can be achieved by providing an OAI, or Origin Access ID, which grants CloudFront permission to call our S3 bucket. And an origin to reach, here below, is an S3Origin created.

 private createOriginAccess(s3Bucket: IBucket): S3Origin {  
        const originAccess = new OriginAccessIdentity(this.scope, 'OriginAccessControl', {comment: 'AWS To-do App OAI'});  
        return new S3Origin(s3Bucket, {originAccessIdentity: originAccess})  
 }

Now we can create our CloudFront distribution with some error response definitions.

  private createCfnDistribution(s3Origin: S3Origin): Distribution {  
        return new Distribution(this.scope, 'aws-to-do-app-cfn-distribution', {  
            defaultBehavior: {  
                origin: s3Origin,  
                viewerProtocolPolicy: ViewerProtocolPolicy.ALLOW_ALL,  
                allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS  
            },  
            errorResponses: [  
                {  
                    httpStatus: 403,  
                    responsePagePath: '/index.html',  
                    responseHttpStatus: 200  
                }  
            ],  
        })  
   }
import {Construct} from "constructs";
import {Bucket, BucketEncryption, IBucket} from "aws-cdk-lib/aws-s3";
import {BucketDeployment, Source} from "aws-cdk-lib/aws-s3-deployment";
import {AllowedMethods, Distribution, OriginAccessIdentity, ViewerProtocolPolicy} from "aws-cdk-lib/aws-cloudfront";
import {S3Origin} from "aws-cdk-lib/aws-cloudfront-origins";

export interface FrontendResources {
}

export class FrontendResources {
    private readonly scope: Construct;
    private props?: FrontendResources | null;

    constructor(scope: Construct, props?: FrontendResources) {
        this.scope = scope;
        this.props = props ?? null;
        this.create();
    }

    private createS3Bucket(): IBucket {
        return new Bucket(this.scope, 'aws-todo-app-frontend-bucket', {
            bucketName: 'aws-todo-app-frontend-bucket-1234567875',
            encryption: BucketEncryption.S3_MANAGED,
            publicReadAccess: false
        })
    }

    private deployS3Bucket(s3Bucket: IBucket) {
        new BucketDeployment(this.scope, 'deploy-aws-todo-app-frontend', {
            sources: [Source.asset('./to-do-app')],
            destinationBucket: s3Bucket
        });
    }

    private createOriginAccess(s3Bucket: IBucket): S3Origin {
        const originAccess = new OriginAccessIdentity(this.scope, 'OriginAccessControl', {comment: 'AWS To-do App OAI'});
        return new S3Origin(s3Bucket, {originAccessIdentity: originAccess})
    }

    private createCfnDistribution(s3Origin: S3Origin): Distribution {
        return new Distribution(this.scope, 'aws-to-do-app-cfn-distribution', {
            defaultBehavior: {
                origin: s3Origin,
                viewerProtocolPolicy: ViewerProtocolPolicy.ALLOW_ALL,
                allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS
            },
            errorResponses: [
                {
                    httpStatus: 403,
                    responsePagePath: '/index.html',
                    responseHttpStatus: 200
                }
            ],
        })
    }

    private create() {
        const s3Bucket = this.createS3Bucket();
        this.deployS3Bucket(s3Bucket);
        const s3Origin = this.createOriginAccess(s3Bucket);
        this.createCfnDistribution(s3Origin);
    }
}
import * as cdk from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {FrontendResources} from "./resources/frontend-resources";

export class AwsCdkToDoAppStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);

        new FrontendResources(this);
    }
}

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { AwsCdkToDoAppStack } from '../lib/aws-cdk-to-do-app-stack';

const app = new cdk.App();
new AwsCdkToDoAppStack(app, 'AwsCdkToDoAppStack', {
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }
});

5. Deploy CDK solution

To see the changes, CDK deployment is required. First, you should check your credentials and connect to your target AWS account. Then, for CDK deployment, you can simply run those commands.

If we run for the first time, you need to deploy the CDK toolkit stack at least once with the bootstrap command and then deploy like below:

cdk bootstrap  
cdk deploy

The To-Do app is hosted on the AWS cloud!

To-Do app hosted from AWS cloud

In conclusion, hosting a to-do web application as a static web page using an S3 bucket and AWS CDK is a straightforward process. By following the steps outlined in this article, all developers can easily publish their static web page and deliver it to consumers worldwide with minimal latency and fast transfer speeds. You can also add some CI/CD pipeline to improve software delivery.

If you intend to serve your webpage on a DNS server with a specific domain, you may consider using the AWS Route 53 solution to create a public HostZone and DNS record. This will enable you to serve your webpage under a domain name of your choice.

Furthermore, if you wish to provide your webpage with SSL, I would like to inform you that the AWS CDK library provides the functionality to create a global (us-central-1) certificate for your use.

This page is open source. Noticed a typo? Or something unclear?
Improve this page on GitHub


Is this page helpful?

Related ArticlesView All