The Anatomy of postmanpat.dev
As postmanpat.dev is a portfolio/blog website, I needed a simple, quick and easy pipeline for a Gatsby site. The pipeline needed to satisfy the following requirements:
- Utulize AWS free tier resources
- Main codebase to reside in GitHub (as oppose to AWS CodeCommit)
- Able to build and deploy upon push to the repository
- Cost efficient
- Low maintenance
- Secure
- Simple automatic deployment of resources
In exploring several options, including deployment and hosting via an EC2 instance, I found the following solution to be the most simple and cost efficient, requiring minimal usage and upkeep of AWS resources whilst maintaining the codebase in GitHub.
CI/CD Architecture

postmanpat.dev is hosted from an AWS S3 bucket with a CI/CD pipeline utulizing Github Workflows to build, compile and deploy to S3 via an Ubuntu instance. Upon new pushes or merges to the main repository, the GitHub Workflow will trigger a new page build and automatically deploy to the S3 bucket. The content is then served via AWS Cloudfront (S3 Origin) and Route53 (Domain resides in GoDaddy).
GitHub Workflow File
Below is the Github Workflow file used to build and deploy to AWS S3. It carries out the following actions:
- Setup Ubuntu instance (AWS CLI is included natively withint this instance)
- Setup AWS variables
- Install nodeJS
- Install project dependencies
- Install Gatsby CLI
- Install Gatsby S3 Plugin
- Deploy to S3 via Gatsby CLI command
name: Deploy to AWS S3
run-name: Deploy postmanpatdev to S3
on:
push:
branches: main
jobs:
build-and-deploy:
name: Build and deploy website
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: "ap-southeast-2"
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: Install Project Dependencies
run: npm i --force
- name: Install Gatsby CLI
run: npm install -g gatsby-cli@^5.11
- name: Install Gatsby Plugin S3
run: npm install gatsby-plugin-s3 --force
- name: Configure AWS CLI Credentials
run: aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" && aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" && aws configure set region "$AWS_DEFAULT_REGION" && aws configure set output "json"
- name: Deploy to S3
run: npm run build && npm run deploy
CloudFormation Template
Below is the Cloudformation template used to setup the AWS resources required to host the website. It creates the following resources in AWS:
- S3 Buckets with public access allowed
- IAM User with specific credentaials (IAM Policy) required by Gatsby CLI for deployment to the S3 Bucket
Note: this file does not include setting up of AWS Cloudfront, AWS Route53, AWS ACM (SSL Certificates) resources as they require manual confgiuration depending on the Domain Registrar.
Description: Deploy postmanpat.dev to S3
Resources:
postmanpatS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: "postmanpatdev"
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerPreferred
WebsiteConfiguration:
IndexDocument: "index.html"
ErrorDocument: "error.html"
postmanpatUser:
Type: "AWS::IAM::User"
postmanpatUserPolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: "postmanpatUserPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "s3:GetObject"
- "s3:PutObject"
- "s3:ListBucket"
- "s3:DeleteObject"
- "S3:PutBucketAcl"
- "s3:GetBucketLocation"
- "s3:PutBucketWebsite"
- "S3:PutObjectAcl"
Resource:
- !Sub "arn:aws:s3:::${postmanpatS3Bucket}"
- !Sub "arn:aws:s3:::${postmanpatS3Bucket}/*"
Users:
- !Ref postmanpatUser
postmanpatAccessKey:
Type: "AWS::IAM::AccessKey"
Properties:
UserName: !Ref postmanpatUser
Outputs:
S3BucketName:
Description: "Name of the created S3 bucket"
Value: !Ref postmanpatS3Bucket
S3StaticWebsiteURL:
Description: "URL of the static website hosted in the S3 bucket"
Value: !Sub "http://${postmanpatS3Bucket}.s3-website-${AWS::Region}.amazonaws.com/"
UserAccessKeyId:
Value: !Ref postmanpatAccessKey
Description: "Access Key ID for the IAM user"
UserSecretKey:
Value: !GetAtt postmanpatAccessKey.SecretAccessKey
Description: "Secret Access Key for the IAM user"