9. CICD Pipeline - GitHub to S3

How to use AWS infrastructure to create a git push CI/CD pipeline for a Nuxt 3 Static website built and deployed to a AWS S3 bucket with a fully qualified custom domain name
Why Use a CICD pipeline?
A Continuous Integration and Continuous Delivery (CICD) system creates stress-free and consistent deployments. The pros and cons of using CICD vs. manual are:
Why Use a CICD Pipeline?
The main reasons to use a CICD pipeline are:
- Automation
- once set up, the pipeline will automatically build and deploy your site with no manual intervention. This is especially useful for frequent updates or multiple contributors.
- Consistency
- the pipeline ensures that the build and deployment process is consistent and repeatable, reducing the risk of human error.
- The Build Machine is fresh, dedicated to building and always on-demand. No chance of update, installation issues, or viruses.
- Your source code is pulled fresh from GitHub. No chance of uploading code that hasn't been checked-in.
- Your NPM dependencies are always installed anew on each build.
- Speed
- the pipeline can significantly speed up the build and deployment process, allowing for faster updates and releases.
- Downtime for your web-site is minimal
- You can roll-back to previous versions
- Version Control Integration
- the pipeline can be integrated with version control systems like GitHub, allowing for automatic builds and deployments triggered by code changes.
- Testing and Validation
- the pipeline can include automated testing and validation steps, ensuring that code changes do not introduce bugs or issues.
- the CICD can put insert 'approval' checkpoints or stages
- Solo Scalability
- the pipeline can easily scale to handle multiple projects deployments. As a solo developer as I scale by creating more than one site, I can use the same pipeline with minor configuration changes.
CICD Cons
- It costs money. This can be mitigated by using small build machines and unnecessary build times (the main driver of money is how many minutes of build machine time is used.)
- CICD errors require 'operational' skill set to locate and fix. On the other hand, you can have similar problems and skill set issues with the manual method as well, so it is usually easier with a CICD than finding out what manual steps you took.
Prod Infrastructure
Prod (Production) Infrastructure consists of cloud resources that host your web site for public viewing. For JAMStart, the prod infrastructure recommendations are:
- Custom Domain
- HTTPS Site Certificate
- AWS Route53 Hosted zone, subdomain redirect
- AWS CloudFront Distribution with WAF (web application firewall)
- AWS S3 Bucket
- CodePipeline, CodeBuild, CodeDeploy
Here are my monthly costs for hosting my blog with this infrastructure:
| Service | Monthly Cost | Notes |
|---|---|---|
| Custom Domain | $1.25 | $15/year registration renewal amortized |
| AWS Certificate Manager | $0.00 | Free for public certificates |
| AWS Route53 | $0.55 | 1 hosted zone, 0.40 per 1,000,000 queries for the first 1 Billion queries |
| AWS CloudFront with WAF | $8.50 | 1TB data transfer out, 10 million requests |
| AWS S3 | $0.05 | Requests per 10,000, first 50 TB / month of storage used, varies on demand |
| AWS CodePipeline/Build/Deploy | $0.00 | Free tier 100 build minutes/month, 1GB storage |
| Total | $10.35 | Approximate monthly cost |
Custom Domain
You need a registered custom domain first. Yes, really. Create, transfer, and/or attach custom domain nameservers in AWS Route 53. Web registration at Amazon is $12-$15/year depending on the domain name. You can also transfer your domain from another registrar to AWS Route 53 for $12-$15/year. If you have a domain registered with another registrar, you can change the nameservers to point to AWS Route 53 and manage the DNS records in Route 53.
Simplicity is best, so I recommend registering or transferring your domain to AWS Route 53.
Site Certificate
To validate your site so that your site displays without warning or sketchiness, create a site certificate.
Request Certificate
To request a new certificate 🎫 use the AWS certificate manager.
- AWS Certificate Manager → Certificates → Request
Certificate properties
| Field | State |
|---|---|
| Certificate type | 'Request a public certificate' |
| Domain names : Fully qualified domain names | {custom domain name} |
| Optional Recommend - Domain names : Add another name to this certificate | www.{custom domain name} |
| Validation method | DNS validation |
CNAME cert records
In order to DNS validate your certificate you need to add one or two CNAME records to your hosted zone. Conveniently from the certificate request details you can automatically create the records. Choose the 'create CNAME records' button.
🛑 Important - DNS validation requires these CNAME records to be created.
AWS Route53 hosted zone
To use your S3 static site bucket with a custom domain name, you need an AWS Route53 hosted zone. If you acquired your custom domain through Route53, the hosted zone will be automatically setup. If you transferred your custom domain names into Route53, you may need to create one.
Creating Public hosted zone
Creating a hosted zone is simple, double-check that it is 'Public hosted zone'.
Default hosted zone
A new hosted zone in Route53, should have two records in it.
| Record | Type | Value |
|---|---|---|
| {custom domain name} | NS | {set of AWS name servers} |
| {custom domain name} | SOA | {single AWS name server} |
You can create a hosted zone without certification or with certification (recommended)
With Certification (recommended)
In order to create a certificate for your site, you need a CloudFront distribution and a certificate issued for that distribution. You will also create a CNAME record that will point your domain name to your CloudFront Distribution.

Chart showing how users interact with Route53, CloudFront, Certificate Manager and S3 for your site
Wait until it the certificate is issued.
Without Certification

Chart showing how users interact with Route53 and S3 for your site
No cert ANAME record
In your hosted zone choose 'Create record' for your root
| Field | State |
|---|---|
| Record name | (leave blank for root) |
| Record type | A - Routes traffic to AWS resource |
| Route traffic to endpoint | Alias to S3 website endpoint |
| Route traffic to region | (choose your region) |
| Enter S3 endpoint | (pick your endpoint, should be in dropdown list) (only if your S3 bucket name matches domain name) |
Verify
Your hosted zone should now have at least three records in the record set.
- NS record
- SOA record
- ANAME record - Domain to S3
AWS CloudFront Distribution
In AWS CloudFront choose 'Create CloudFront Distribution' and change the following
| Field | State |
|---|---|
| Origin : Origin domain | {insert your S3 Bucket website endpoint (no 'http://')} |
| Default cache behavior : Viewer protocol policy | Redirect HTTP to HTTPS |
| Settings: Alternate domain name (CNAME) - optional | {custom domain name} |
| Optional - Settings: Alternate domain name (CNAME) - optional | www.{custom domain name} |
| Settings: Custom SSL certificate - optional | {pick your certificate from dropdown} |
| Settings: Price class | Use only North America and Europe (Recommended) |
Verify
Your hosted zone should now have at least four or maximum five records in the hosted zone record set.
- NS record
- SOA record
- CNAME record(s) for certificate - 1 or 2 depending on if you included 'www' or not
- ANAME record - Domain to CloudFront
Subdomain redirect
Optionally, if you've created your certificate and CloudFront distribution with 'www', you need to create an ANAME 'www' redirect. In your hosted zone choose 'Create record' for your root
| Field | State |
|---|---|
| Record name | 'www' |
| Record type | A - Routes traffic to AWS resource |
| Route traffic to endpoint | Alias to another record in this hosted zone |
| Route traffic to Choose record | (pick your ANAME domain without the 'www') |
Verify
After your certificate is issued and the CloudFront distribution is deployed, you can validate that your custom domain opens your static site hosted from S3 after you deploy it.
AWS S3 Bucket
Create an AWS S3 bucket that will host your static site. You can use the AWS Console ('Create bucket' in the Console S3 General purpose bucket) or AWS CLI (aws s3 mb). The bucket must be in the same region as your CICD pipelines.
S3 Bucket Name
You must name the S3 Bucket exactly the same name as your custom Domain name, i.e. for 'pennockprojects.com' custom domain, create a bucket named pennockprojects.com. Otherwise, your endpoint will not be visible as an alias for the Route 53 record
Allow public access
S3 Bucket Permissions Block all public access should be set to Off
Bucket Policy
Add a bucket policy for object access, replace {{BucketName}} with your bucket name.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::{{BucketName}}/*"
}
]
}
S3 Bucket Properties
Set the following S3 bucket properties as appropriate.
| Property | State |
|---|---|
| Static website hosting | Enable |
| Hosting type | Host a static website |
| Index document | index.html |
| Error document - optional | 404.html (or whatever you have) |
Production Pipeline
The Prod Pipeline will gather your source from git, build it, and deploy it to production infrastructure.
Source Build Deploy
The base Build and Deploy pipeline consists of three Stages
- Source
- Build
- Deploy
Source
The source stage will trigger on a 'git push' to the main branch (or whatever git branch you designate). It will copy all the code from GitHub to the AWS CodeBuild Machine. The package from GitHub to AWS Codebuild is called SourceArti and is stored in CodePipeline S3.
Build
A CodeBuild EC2 machine is spun up on-demand. It is a Linux:g1.small machine with Free Tier 100 build minutes a month. For my blog I typically use about 1 1/2 minutes - 2 minutes a build.
The SourceArti from Source is copied and uncompressed onto the file-system of the CodeBuild EC2 machine.
The CodeBuild machine then follows the phases in the buildspec.yml file in the root of the repo. It will do the npm install reading the repo package.json file and installing packages directly. It will run the npm run generate command to layout your Nuxt SSG site.
If successful, the built files from dist will be compressed and stored in the CodePipeline S3 bucket as BuildArti.
Deploy
The CodeDeploy phase will grab the BuildArti compressed files, decompress and copy the files to your live website S3 bucket.
New CodePipeline Steps
Important, you should have created a custom domain, prepared an S3 bucket and received a site certificate prior to creating the AWS CodePipeline.
- Requisition a S3 bucket configured for Static Site Hosting
- Requisition a CodePipeline - Git Sync, AWS CodeBuild, Deploy to S3 Bucket
- Requisition a Route 53 hosted zone
- Non-certificate (http warning)
- CloudFront with certificate (https)
- Requisition a CloudFront Distribution
- Requisition a https Certificate
Create an AWS CodePipeline that will perform three tasks.
- Attach and watch a GitHub repo branch for changes
- Initiate AWS Codebuild and generate your Nuxt 3 Static Site
- Copy the built Nuxt Static Site into your S3 site bucket
Create a CodePipeline
From AWS Console find CodePipeline and choose 'Create'
- Create a unique name for the pipeline
- Choose Queued
- Leave the pipeline role
Next
Pipeline Git sync
Choose a stage source
| Field | State |
|---|---|
| Source Provider | 'GitHub (version 2)' |
| Connection | Use existing or choose 'Connect to GitHub' |
| Repository name | (pick your repo) |
| Default branch | (pick your branch) |
| Output artifact format | CodePipeline default |
| Trigger - Trigger type | No filter (launches on push) |
Next
Pipeline CodeBuild
Build - Optional
Build provider → AWS codeBuild
| Field | State |
|---|---|
| Build Provider | 'AWS CodeBuild' |
| Region | (pick your region) |
| Input artifacts | SourceArtifact (from the GitHub sync above) |
| Project Name | (pick your project name or choose 'Create Project') |
| Environment variables | (leave blank or add) |
| Build type | Single build |
Create Build Projects
| Field | State |
|---|---|
| Project name | (pick a project name) |
| Source 1 - Primary | Source provider - AWS CodePipeline |
| Environment Provisioning model | On-demand |
| Environment image | Managed image |
| Environment Compute | EC2 |
| Operating system | Amazon Linux |
| Runtime | Standard |
| Image | aws/codebuild/amazonlinux2-x86_64-standard:5.0 |
| Image Version | Always use the latest image for this runtime version |
| Buildspec Build specifications | Use a Buildspec file |
| Buildspec name | (leave blank or buildspec.yml) |
Pipeline buildspec.yml
Add the following buildspec.yml file to your repo. These are the instructions that will be used to build the Nuxt static site as well as indicating where the built files will exist after build.
version: 0.2
phases:
install:
commands:
- npm install
build:
commands:
- npm run generate
artifacts:
files:
- '**/*'
base-directory: 'dist'
AWS CodeDeploy
The third stage of the pipeline, deploy, copies the built files to the S3 website bucket
| Field | State |
|---|---|
| Deploy provider | 'Amazon S3' |
| Region | (pick your Region, same as build) |
| Input artifacts | 'BuildArtifact' |
| Bucket | (pick your bucket) |
| Extract file before deploy | enabled |
Verify
If all your steps are correct, your code pipeline should run. You should validate by opening the website at the S3 bucket website endpoint.
S3 → {static site bucket} → properties → Static website hosting | Bucket website endpoint
Dev Infrastructure (optional)
The Dev (Development) Infrastructure consists of cloud resources that host your development web site - for testing and validation before deployment. A dev infrastructure and pipeline are optional and may or may not be implemented for your site needs. A content heavy site with multiple proofreaders, editors, or authors, might want a dev infrastructure to view the web site before deployment to production. A solo author might be fine will validating the site locally and skip the dev infrastructure.
Recommended Resources
- AWS Route53 Hosted zone
- AWS S3 Bucket
Dev Pipeline (optional)
A Developer Pipeline is used to host your site for testing before deploying to prod
Resources
The following videos illustrate many of the steps used here: