JAM stack: Deploying a S3 website form commandline.

Hosting the client facing page is an important part of creating a performant JAM stack app, To do this I will be using Amazon's AWS S3 offering and the AWS CLI.

From here I will assume that you have the AWS CLI installed and have it configured to use an account that is capable of creating and configuring S3 buckets.
I'm using Powershell emulated through cmndr on Windows as my command line.

Create the bucket

The first thing we need is to create the bucket. If every thing is fine it will look like this. 
(replace kleeut-jamblog with your bucket name, they need to be unique)
 aws s3api create-bucket --acl public-read --bucket kleeut-jamblog --create-bucket-configuration LocationConstraint=ap-southeast-2  
 {  
   "Location": "http://kleeut-jamblog.s3.amazonaws.com/"  
 }  

Gotchas:

The error messages are pretty good, these are the ones I've commonly run into.

If you're already run the command or for you own the bucket you'll see:
 An error occurred (BucketAlreadyOwnedByYou) when calling the CreateBucket operation: Your previous request to create the named bucket succeeded and you already own it.  

If someone else owns the bucket:
 An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.  

Configure the bucket

Turn on static hosting 

A public bucket is not served as a static website 
 aws s3 website s3://kleeut-jamblog --index-document index.html --error-document error.html  
The index document is the root page that is served when a user accesses the root page.
The error document is displayed whenever S3 would return a 4xx status code.

 Set bucket policy

Just configuring the bucket is not enough. The bucket also needs to be configured to make all files that are added to the bucket publicly readable.

Create a file named bucketPolicy.json with this content.
 {  
   "Version":"2012-10-17",  
   "Statement":[{  
    "Sid":"PublicReadGetObject",  
      "Effect":"Allow",  
     "Principal": "*",  
     "Action":["s3:GetObject"],  
     "Resource":["arn:aws:s3:::kleeut-jamblog/*"  
     ]  
    }  
   ]  
  }  
Apply this to the bucket by running:
 aws s3api put-bucket-policy --bucket kleeut-jamblog --policy file://bucketpolicy.json  

Add files

Single files

Start by adding some basic files in to the bucket to confirm everything is working.
 aws s3 cp .\index.html s3://kleeut-jamblog/index.html  
 aws s3 cp .\error.html s3://kleeut-jamblog/error.html  
Navigate to http://{your bucket name}.s3-website-ap-southeast-2.amazonaws.com/

e.g: http://kleeut-jamblog.s3-website-ap-southeast-2.amazonaws.com/

and you should see your index.html file rendered for everyone to see.


Enter a page that doesnt exist and you'll see your error page.

Directory

Uploading single files is a bit of a pain and wont scale well to a real life SPA.
In order to copy multiple files and folder structures the copy command has the --recursive flag. 
 aws s3 cp .\build s3://kleeut-jamblog --recursive  
However the sync command is a better choice than using the copy command. As it provides an option to remove files from the bucket that are not present in the local directory.
 aws s3 sync .\build\ s3://kleeut-jamblog --delete  

Conclusion

This has gone over how to set up a simple static site in S3. Using only the command line.
There are a few things missing from being able to make this a production website, notably a custom domain name and a TLS certificate to allow the site to be served over https. To make it a production JAM stack app we'll need some API's to go along with it.

Comments

Popular posts from this blog

Solving `Empty reply from server` in DotNet Core

Testing functions that use local storage with Jest

Building a verify JWT function in TypeScript