Website Setup Using AWS

Introduction

The objective of this guide is to walk through the process of setting up a static website and creating redirects using Amazon Web Services (AWS). This involves the following steps:

  • Registering and setting up a domain using Route 53.
  • Creating an SSL certificate using ACM.
  • Setting up a storage bucket on Amazon S3.
  • Configuring Amazon CloudFront for content delivery.
  • Redirecting certain paths to other URLs.

Instructions

Set up Domain with Route 53

Register or transfer your domain to Route 53.

Once the domain is in Route 53, create a hosted zone for the domain.

Make note of the NS records AWS assigns to your domain, you'll need these later.

aws route53 create-hosted-zone --name example.com --caller-reference 2023-06-14-01

If transferring or migrating from a different service please refer to this document.

Create SSL certificate with Amazon Certificate Manager (ACM)

In the ACM console, request a public certificate.

Input your domain name and validate ownership, either through DNS validation or email validation. If your domain is already in Route 53, DNS validation can be done automatically.

Once validated, the certificate is issued. Note down the ARN (Amazon Resource Name) for the certificate.

This process is not typically done through CLI due to the complexity of the certificate validation process.

Set up Amazon S3 bucket and enable Static Hosting

Create a new S3 bucket with the same name as your domain and enable static website hosting on the bucket. Set "index.html" as the index document.

Use the following commands:

aws s3 mb s3://example.com --region us-west-2
aws s3 website s3://example.com/ --index-document index.html

Create a bucket policy file bucketpolicy.json to enable public read (Alternatively, you can access S3 from AWS Management Console and turn off “Block all public access” under “Permissions”):

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "PublicReadForGetBucketObjects",
			"Effect": "Allow",
			"Principal": "*",
			"Action": ["s3:GetObject"],
			"Resource": ["arn:aws:s3:::s.country/*"]
		}
	]
}

Apply this policy to your bucket:

aws s3api put-bucket-policy --bucket example.com --policy file://bucketpolicy.json

Now, upload a simple redirect rule to your S3 bucket that redirects to https://example.com/redirect with an index.html in your local repository:

aws s3 cp index.html s3://stse.one/index.html --acl public-read --website-redirect https://harmony.one/2023

This will enable the default page of your bucket to lead to index.html which redirects to https://example.com/redirect.

Set up Amazon CloudFront Distribution

Create a new CloudFront distribution. Use the S3 bucket you created as the origin.

Configure the distribution to use the SSL certificate you created in ACM.

Set the Viewer Protocol Policy to "Redirect HTTP to HTTPS".

Note down the CloudFront distribution ID.

This process is complex to handle via AWS CLI, and typically done through the AWS Management Console for ease of use and due to the number of configuration options.

Link CloudFront to Route 53

In Route 53, create a new record set in your hosted zone.

aws route53 change-resource-record-sets --hosted-zone-id "/hostedzone/YOUR_HOSTED_ZONE_ID" --change-batch file://dnschange.json

In the above command, you need to replace YOUR_HOSTED_ZONE_ID with your Route 53 hosted zone ID. dnschange.json is a JSON file that specifies the changes to be made to the record sets. This file might look something like this:

{
    "Changes": [
        {
            "Action": "CREATE",
            "ResourceRecordSet": {
                "Name": "example.com.",
                "Type": "A",
                "AliasTarget":{
                    "HostedZoneId": "Z2FDTNDATAQYW2",
                    "DNSName": "d12345abcdef8.cloudfront.net",
                    "EvaluateTargetHealth": false
                }
            }
        }
    ]
}

In this JSON, replace Z2FDTNDATAQYW2 with the zone ID of your CloudFront distribution (found in the CloudFront console) and d12345abcdef8.cloudfront.net with your CloudFront distribution domain name.

Alternatively, using the AWS Management Console:

  1. In Route 53, create a new record set in your hosted zone.
  2. Set the type to "A – IPv4 address" and the Alias to "Yes".
  3. Set the Alias Target to the CloudFront distribution you created (after “Distribution Status” change from “InProgress” to “Deployed” in Cloudfront).

Create Redirects

Use the AWS CLI to create redirect rules. The command to use is:

aws s3 cp object s3://example.com/$1 --acl public-read --website-redirect $2

where $1 is the path you want to redirect and $2 is the URL to redirect to. You need to have a object in your local repository (note that this can be an empty file as the contents will be ignored; an object is required to be uploaded).

With this, you can have example.com/food redirected to your desired destination.

*** Remember to replace example.com with your own domain and make necessary adjustments in the path or redirect URL as per your requirements.

*** Remember to set the appropriate AWS credentials to your environment before proceeding. Validity of the credentials can be checked through simple commands (i.e. aws s3 ls).

h.country Setup

The above instruction is for hosting the end to end webserver in AWS. The current setup for h.country is different than the one explained above.

It looks as follows:

  • www.h.country is a webserver hosted in Aaron’s GCP
  • h.country is a S3 bucket hosted under Harmony’s account

The following redirects have been configured:

  • h.country vanity to www.h.country subpage: h.country/{path}www.h.country/page-{desired subpage}
  • www.h.country vanity to www.h.country subpage: www.h.country/{path}h.country/{path}www.h.country/page-{desired subpage}
  • h.country / www.h.country vanity to external website: h.country/{path}{desired external website} OR www.h.country/{path}h.country/{path}{desired external website}
  • h.country / www.h.country vanity to nonexisting www.h.country subpage: h.country/{path}www.h.country/page-{nonexisting subpage}www.h.country OR www.h.country/{path}h.country/{path}www.h.country/page-{nonexisting subpage}www.h.country

All subpages under www.h.country have “page-” prepended to their paths.

Thus, unless the path of www.h.country has “page-” prepend, the redirect will lead to h.country/{page}. If the resource {path} exists under h.country S3 bucket (s3://h.country/{path}), then a redirect will happen to the website-redirect that has been set to the resource. Note that if the redirect of the S3 resouurce is to a www.h.country but does NOT have “page-” prepend, it will redirect back to h.country, which will most likely not have the path object and then ultimately onto h.country.

This applies for all the redirects in any other S3 buckets. For an example, if we want to redirect harmony.one/q3 to https://www.h.country/page-q3-make-something-people-want-b-b-4de738ae0a5948e19cd308dd49b699b2:

aws s3 cp q3 s3://harmony.one/q3 --acl public-read --website-redirect https://www.h.country/page-q3-make-something-people-want-b-b-4de738ae0a5948e19cd308dd49b699b2

If h.country S3 bucket already has an object that redirects to https://www.h.country/page-q3-make-something-people-want-b-b-4de738ae0a5948e19cd308dd49b699b2, let’s say h.country/q3:

aws s3 cp q3 s3://harmony.one/q3 --acl public-read --website-redirect h.country/q3

Redirect Update Script

Due to this new setup, all preexisting redirects to www.h.country/{path} needed a “page-” prepend. The following scripts to the following:

#!/bin/bash

# Set the appropriate variables
bucket_name=harmony.one
prefix=page-
redirect_url=https://www.h.country/

# File to store the update details
output_file="update_details.txt"

# Emoji regex pattern (limited)
emoji_pattern=".*[\xF0-\xF4].*"

# Get a list of all objects in the bucket
objects=$(aws s3 ls "s3://$bucket_name" --recursive | awk '{print $4}')

# Iterate through each object
for object_key in $objects; do
  # Check if object_key contains an emoji
  if [[ ! $object_key =~ $emoji_pattern ]]; then

    # Check the file type
    file_type=$(aws s3api head-object --bucket "$bucket_name" --key "$object_key" --query 'ContentType' --output text)

    if [[ $file_type == "binary/octet-stream" ]]; then 
      # Get the existing redirect configuration for the object
      redirect_config=$(aws s3api head-object --bucket "$bucket_name" --key "$object_key" --query 'WebsiteRedirectLocation' --output text)

      # Check if the object has a website redirect to the specified URL
      if [[ "$redirect_config" != "None" ]] && [[ "$redirect_config" == "$redirect_url"* ]]; then
        echo "Updating redirect configuration for object: $object_key"

        # Extract the path from the existing redirect URL
        path=${redirect_config#"$redirect_url"}

        # Check if the path already contains the prefix
        if [[ "$path" != "$prefix"* ]]; then
          # Add the prefix to the path
          new_path="$prefix$path"

          # Create the updated redirect URL
          updated_redirect_url="$redirect_url$new_path"

          # Update the redirect configuration for the object
          aws s3 cp "s3://$bucket_name/$object_key" "s3://$bucket_name/$object_key" --website-redirect "$updated_redirect_url" --acl public-read

          # Append the details to the output file
          echo "$object_key, $redirect_config, $updated_redirect_url" >> $output_file
        else
          echo "Path already contains the prefix. Skipping update for object: $object_key"
        fi
      fi
    fi
  fi
done
update-path.sh2.0KB

*** This script is specific to harmony.one bucket. Please change the bucket_name to the desired S3 bucket.

Cache Invalidation (TODO)

gist Files

sa.h.country1.0KB