/catalog-example

React JS example to demonstrate Static Website Hosting in AWS and Azure

Primary LanguageJavaScriptMIT LicenseMIT

Catalog Example

This repository is an example how AWS S3 and Azure Storage provide static website hosting service. You could follow the listed steps to host the example website in AWS and Azure respectively. License

AWS and Azure both provide website hosting feature in their storage services. Such feature is considered as a managed service of website hosting so that the website owners can transfer some infrastructure workload, such as hardware maintenance and sizing, to the cloud providers. The costing is so flexible with minimal upfront. This solution is suitable for typical static websites and even Single Page Applications in which traffic volumes and peaks are often highly variable and fluctuating.

Both platforms provide CLI method to automate the deployment, in addition to web portal. This automation approach is useful for large scale of deployment, governance and integration in CI/CD. This below section will instruct how to run CLI to build the resource stack accordingly. The pricing is also described to demonstrate the cost efficiency.

Example Preview

The example website is a product catalog built by React JS. The detail will not be covered here. Setups of domain name, DNS and secure connection (https) are out of scope in this document.

Folder Structure

  • build: the production version of website files. It is built by npm. (not saved in this repository, refer to the Appendix)
  • doc: document files used by README
  • public: static webpage template by React JS
  • scripts: infrastruture setup scripts
  • src: React JS source codes

Table of Contents

AWS S3

AWS Architecture

This approach is to utilize CloudFront as a HTTPS access point to the public. CloudFront delivers the content from an S3 bucket. CloudFront stores access logs to another S3 bucket for monitoring. The whole setup is implemented by CloudFormation.

Before you start, create an IAM user credentials with sufficient priviledges to execute aws CLI.

  1. CREATE CloudFormation Stack to create S3 Bucket
aws cloudformation create-stack --stack-name <STACK NAME> --profile <USER PROFILE>  --template-body file://./scripts/aws_cf_s3_create_website.yaml --parameters ParameterKey=BucketNameParam,ParameterValue=<BUCKET NAME> ParameterKey=RegionCodeParam,ParameterValue=<REGION CODE>
  • <STACK NAME>: The stack name of this CloudFormation Stack
  • <USER PROFILE>: The profile name to run this command locally
  • <BUCKET NAME>: The S3 bucket to store the website content
  • <REGION CODE>: The region code of the S3 Bucket. The region should have been configured in the profile used above.
  1. After the stack is created completely, UPLOAD website files to the S3 Bucket

Stack Status Check:

aws clouformation describe-stacks --stack-name <STACK NAME> --profile <USER PROFILE>

Upload:

aws s3 cp ./build/ s3://<BUCKET NAME>/ --recursive --profile <USER PROFILE>
  1. Browse the assigned domain name from CloudFront
aws cloudfront list-distributions --query "DistributionList.Items[].DomainName" --profile <USER PROFILE>
  1. Browse the website. The URL of the website is in format of https://<DOMAIN PREFIX>.cloudfront.net. The whole domain name can be found in the above command.
  • <DOMAIN PREFIX>: CloudFront Domain Prefix which is assigned by CloudFront automatically.

Stack Deletion

If you would like to delete the whole stack of resources, e.g clean up or no longer use the website, you could run the command:

aws s3 rb s3://<BUCKET NAME> --profile <USER PROFILE> --force
aws s3 rb s3://<BUCKET NAME>-log --profile <USER PROFILE> --force
aws cloudformation delete-stack --stack-name <STACK NAME> --profile <USER PROFILE>

Pricing

Assume USD in ap-southeast-1 region (Singapore) as of 1st Oct 2020

Service Category Price
CloudFormation AWS Resources $0
S3 Standard - First 50TB / Month $0.025 per GB
S3 Standard - PUT,COPY,POST,LIST $0.005 per 1K requests
S3 Standard - GET,SELECT $0.0004 per 1K requests
S3 Data In $0
S3 Data Out to CloudFront $0
CloudFront Data Out to Internet $0.14 per GB
CloudFront HTTPS requests $0.009 per 10K requests

e.g. 1GB website content to serve 5M users, the monthly cost is estimated as $4.7.

Azure Storage

Azure Architecture

Before you start, create a principal with sufficient priviledges to execute az CLI. az login should have been executed successfully

  1. Create Resource Group
az group create --location <LOCATION NAME> --name <RESOURCE GROUP>
  • <LOCATION NAME>: Location Name in Azure. It can be viewed from a list of the command az account list-locations.
  • <RESOURCE GROUP>: A name of the resource group we are creating to put all related resources together.
  1. Create Storage Account
az storage account create --name <STORAGE ACCOUNT> --resource-group <RESOURCE GROUP> --location <LOCATION NAME> --sku Standard_LRS
  • <STORAGE ACCOUNT>: Storage Account Name to be created
  1. Create $web Blob Container
az storage container create --account-name <STORAGE ACCOUNT> --name '$web' 
  1. Enable Website Hosting in Blob Storage
az storage blob service-properties update --account-name <STORAGE ACCOUNT> --static-website --404-document error.html --index-document index.html
  1. Upload website files to the $web Blob Container
az storage blob upload-batch --account-name <STORAGE ACCOUNT> --source ./build/ --destination '$web'
  1. Create CDN Profile
az cdn profile create --name <CDN Profile> --resource-group <RESOURCE GROUP> --sku Standard_Microsoft
  • <CDN Profile>: Name of CDN Profile
  1. Create CDN Endpoint
az cdn endpoint create --name <CDN Profile> --resource-group <RESOURCE GROUP> --profile-name <CDN Profile> --origin <HOSTING HOST> --origin-host-header catalogegsite.z23.web.core.windows.net --enable-compression
  • <CDN Endpoint>: Name of CDN Endpoint
  • <HOSTING HOST>: Host of Storage Website Hosting. It can be retrieved by az storage account show --name <STORAGE ACCOUNT> --resource-group <RESOURCE GROUP> --query "primaryEndpoints.web" --output json
  1. Redirect HTTP requests to HTTPS
az cdn endpoint rule add --name <CDN Endpoint> --resource-group <RESOURCE GROUP> --profile-name <CDN Profile> --rule-name enforcehttps --order 1 --action-name "UrlRedirect"  --redirect-type Found --redirect-protocol HTTPS --match-variable RequestScheme --operator Equal --match-value HTTP
  1. Browse the website. The URL of the website is in format of https://<CDN Endpoint>.azureedge.net

Enable Access Log in Azure CDN

There is no az command to enable Access Log in Azure CDN. It can be enabled in Azure Portal.

  1. Register Microsoft Insights in the subscription
az provider register --namespace Microsoft.Insights
  1. Go to Azure Portal > CDN, click the created CDN name, then click Monitoring > Diagnostics setting. Select AzureCdnAccessLog and Archive to a storage account. Click Save to save the setting. Add AzureCdnAccessLog in CDN Diagnostics

  2. You can find the access log files in the selected Storage Blob Service's Container > insights-logs-azurecdnaccesslog folder.

Resource Deletion

If you would like to delete the whole group of resources, e.g clean up or no longer use the website, you could run the command:

az group delete --name <RESOURCE GROUP>

Pricing

Assume USD in southeastasia region (Southeast Asia) as of 1st Oct 2020

Service Category Price
Bandwidth Inbound Data Transfer $0
Bandwidth Outbound Data Transfer to CDN $0
Storage Blob LRS First 50TB/month Hot $0.02 per GB
Storage Blob LRS Data Write Hot $0
Storage Blob LRS Data Retrieval Hot $0
CDN Static Zone 2 - First 10TB/month $0.129 per GB

e.g. 1GB website content to serve 5M users, the monthly cost is estimated as $0.13.

Github Pages

With response to Dear Mr. Roger, here is added with a bonus section - How to deploy a static website to Github Pages, which is suitable for personal usage.

Prerequisite: Apply a Github account

  1. Install gh-pages for deployment
npm install gh-pages --save-dev
  1. Modify package.json to provide homepage and deployment commands.
...
    "homepage": "http://<GITHUB_USERNAME>.github.io/<GITHUB_REPO>",
...
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build"
...    
  • <GITHUB_USERNAME>: Github Username
  • <GITHUB_REPO>: Github Repository
  1. Create a remote repository in Github and initialize the website content with git
  • Git initialize: git init
  • Add a remote repository (after the repository in Github is created): git remote add origin <GITHUB_REPO_URL>.git , where <GITHUB_REPO_URL>: Github Repository URL
  1. Deploy the website content to Github Pages
npm run deploy
  1. Browse the website at http://<GITHUB_USERNAME>.github.io/<GITHUB_REPO> The example here is https://tekichan.github.io/catalog-example.

Appendix A - How to build

  • Build React JS Frontend: npm run build

Appendix B - References

Authors