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.
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.
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.
- 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
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.
- 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.
- 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>
- Browse the assigned domain name from CloudFront
aws cloudfront list-distributions --query "DistributionList.Items[].DomainName" --profile <USER PROFILE>
- 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.
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>
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.
Before you start, create a principal with sufficient priviledges to execute az
CLI. az login
should have been executed successfully
- 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.
- 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
- Create $web Blob Container
az storage container create --account-name <STORAGE ACCOUNT> --name '$web'
- 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
- Upload website files to the $web Blob Container
az storage blob upload-batch --account-name <STORAGE ACCOUNT> --source ./build/ --destination '$web'
- Create CDN Profile
az cdn profile create --name <CDN Profile> --resource-group <RESOURCE GROUP> --sku Standard_Microsoft
- <CDN Profile>: Name of CDN Profile
- 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
- 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
- Browse the website. The URL of the website is in format of https://<CDN Endpoint>.azureedge.net
There is no az
command to enable Access Log in Azure CDN. It can be enabled in Azure Portal.
- Register Microsoft Insights in the subscription
az provider register --namespace Microsoft.Insights
-
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.
-
You can find the access log files in the selected Storage Blob Service's Container > insights-logs-azurecdnaccesslog folder.
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>
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.
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
- Install gh-pages for deployment
npm install gh-pages --save-dev
- 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
- 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
- Deploy the website content to Github Pages
npm run deploy
- Browse the website at http://<GITHUB_USERNAME>.github.io/<GITHUB_REPO> The example here is https://tekichan.github.io/catalog-example.
- Build React JS Frontend:
npm run build
- Acknowledgement of React JS design from Material UI template
- Creating an Amazon S3 bucket for website hosting and with a DeletionPolicy
- Host a static website in Azure Storage
- Monitoring Metrics and Raw Logs for Azure CDN from Microsoft
- AWS Pricing Calculator
- Azure Pricing Calculator
- Teki Chan tekichan@gmail.com