Skip to content

shaunniee/AWS-PORTFOLIO-WEBSITE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

☁️ AWS Static Portfolio Website

Production-grade static site on AWS with fully automated CI/CD

Live Site AWS CI/CD

S3 CloudFront Route 53 ACM CodeBuild CloudWatch HTML5 CSS3


πŸ“‹ Table of Contents


πŸ”Ž Overview

A personal cloud engineering portfolio hosted on AWS using a production-style architecture β€” private S3 origin, global CDN delivery via CloudFront, custom domain with TLS, fully automated deployments on every git push, and operational monitoring with alerting.

🎯 Goals

Goal Implementation
⚑ Global performance CloudFront CDN with edge caching
πŸ”’ HTTPS everywhere ACM TLS certificate, HTTP β†’ HTTPS redirect
🚫 No public S3 Private bucket, Origin Access Control (OAC)
πŸ”„ Zero-touch deploys git push β†’ CodePipeline β†’ CodeBuild β†’ live
πŸ“Š Operational visibility CloudWatch alarms, CloudFront access logs

πŸ›  Tech Stack

Layer Service Purpose
πŸ—„οΈ Origin Amazon S3 Private static file storage
🌐 CDN Amazon CloudFront Global edge delivery + HTTPS termination
πŸ“ DNS Amazon Route 53 Custom domain resolution
πŸ” TLS AWS Certificate Manager Free public TLS certificate
πŸ”„ CI/CD CodePipeline + CodeBuild Automated build and deploy
πŸ“Š Monitoring CloudWatch + SNS 5xx alerting and metrics
πŸ“ Logging CloudFront Access Logs Traffic analysis and debugging

πŸ— Architecture

Architecture Diagram β€” S3 + CloudFront + CodePipeline

πŸ“ Request Flow

flowchart LR
    subgraph DEV["<b>πŸ§‘β€πŸ’» Developer</b>"]
        A["<b>git push</b><br>main branch"]
    end

    subgraph CICD["<b>πŸ”„ CI / CD</b>"]
        B["<b>πŸ“₯ GitHub</b><br>Webhook Trigger"]
        C["<b>βš™οΈ CodePipeline</b><br>Orchestration"]
        D["<b>πŸ”¨ CodeBuild</b><br>buildspec.yml"]
    end

    subgraph INFRA["<b>☁️ AWS Infrastructure</b>"]
        E["<b>πŸ—„οΈ S3</b><br>Private Origin"]
        F["<b>🌐 CloudFront</b><br>Edge CDN + TLS"]
        G["<b>πŸ“ Route 53</b><br>DNS Resolution"]
        H["<b>πŸ” ACM</b><br>TLS Certificate"]
    end

    subgraph CLIENT["<b>πŸ‘€ End User</b>"]
        I["<b>🌍 Browser</b><br>HTTPS Request"]
    end

    A -- "push event" --> B
    B --> C
    C --> D
    D -- "aws s3 sync" --> E
    D -- "cache invalidation" --> F

    I -- "shaunvividszportfolio.com" --> G
    G -- "A Record (Alias)" --> F
    H -. "TLS termination" .-> F
    F -- "OAC fetch" --> E
    F -- "cached response" --> I

    style DEV fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
    style CICD fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
    style INFRA fill:#fef9c3,stroke:#ca8a04,stroke-width:2px,color:#713f12
    style CLIENT fill:#f3e8ff,stroke:#7c3aed,stroke-width:2px,color:#581c87
    style A fill:#bfdbfe,stroke:#3b82f6,stroke-width:1px,color:#1e3a5f
    style B fill:#bbf7d0,stroke:#22c55e,stroke-width:1px,color:#14532d
    style C fill:#bbf7d0,stroke:#22c55e,stroke-width:1px,color:#14532d
    style D fill:#bbf7d0,stroke:#22c55e,stroke-width:1px,color:#14532d
    style E fill:#fef08a,stroke:#eab308,stroke-width:1px,color:#713f12
    style F fill:#fef08a,stroke:#eab308,stroke-width:1px,color:#713f12
    style G fill:#fef08a,stroke:#eab308,stroke-width:1px,color:#713f12
    style H fill:#fef08a,stroke:#eab308,stroke-width:1px,color:#713f12
    style I fill:#e9d5ff,stroke:#a855f7,stroke-width:1px,color:#581c87
Loading

πŸ“ AWS Resources

πŸ—„οΈ Amazon S3

BucketRegionPurposeConfiguration
shaun-portfolio-content eu-west-1 Static site files βœ… Block all public access
βœ… OAC-only bucket policy
βœ… Default encryption (SSE-S3)
βœ… Versioning enabled
shaun-portfolio-cf-logs eu-west-1 CloudFront access logs βœ… Block all public access
βœ… ACL for CloudFront logging

Bucket Policy (content bucket):

{
  "Effect": "Allow",
  "Principal": { "Service": "cloudfront.amazonaws.com" },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::shaun-portfolio-content/*",
  "Condition": {
    "StringEquals": {
      "AWS:SourceArn": "arn:aws:cloudfront::<ACCOUNT>:distribution/<DIST_ID>"
    }
  }
}

🌐 Amazon CloudFront

Setting Value
Origin S3 via Origin Access Control (OAC)
Default root object index.html
Custom domain www.shaunvividszportfolio.com
TLS certificate ACM public cert (us-east-1)
Viewer protocol Redirect HTTP β†’ HTTPS
Cache policy Managed CachingOptimized
Access logging Enabled β†’ shaun-portfolio-cf-logs

πŸ“ Amazon Route 53

Record Type Target
www.shaunvividszportfolio.com A (Alias) CloudFront distribution

πŸ” AWS Certificate Manager

  • Certificate type: Public
  • Region: us-east-1 (required for CloudFront)
  • Domain: *.shaunvividszportfolio.com
  • Validation: DNS (CNAME record in Route 53)
  • Auto-renewal: βœ… Enabled

πŸ”„ CI/CD Pipeline

Pipeline Architecture

flowchart LR
    subgraph PIPE["<b>βš™οΈ CodePipeline</b>"]
        direction LR
        S["<b>πŸ“₯ Source</b><br>GitHub<br>main branch"]
        B["<b>πŸ”¨ Build</b><br>CodeBuild<br>buildspec.yml"]
        D["<b>πŸ“€ Deploy</b><br>S3 sync +<br>CloudFront invalidate"]
    end

    S --> B --> D

    style PIPE fill:#f0fdf4,stroke:#16a34a,stroke-width:2px,color:#14532d
    style S fill:#dbeafe,stroke:#3b82f6,stroke-width:1px,color:#1e3a5f
    style B fill:#fef9c3,stroke:#ca8a04,stroke-width:1px,color:#713f12
    style D fill:#dcfce7,stroke:#22c55e,stroke-width:1px,color:#14532d
Loading

πŸ”¨ buildspec.yml

version: 0.2

env:
  parameter-store:
    S3_BUCKET: "/portfolio/static-site/s3-bucket"
    CLOUDFRONT_DISTRIBUTION_ID: "/portfolio/static-site/cf-distribution-id"

phases:
  install:
    commands:
      - echo "Install phase - nothing to install for basic static site"
  build:
    commands:
      - echo "Build phase - no framework build step for plain HTML"
  post_build:
    commands:
      - echo "Deploying to S3..."
      - aws s3 sync . s3://$S3_BUCKET --delete --exclude ".git/*" --exclude "buildspec.yml"
      - echo "Creating CloudFront invalidation..."
      - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths "/*"

artifacts:
  files:
    - '**/*'

πŸ’‘ Note: Sensitive values (S3_BUCKET, CLOUDFRONT_DISTRIBUTION_ID) are pulled from AWS Systems Manager Parameter Store β€” no secrets hardcoded in the repo.

βš™οΈ CodeBuild IAM Permissions

The CodeBuild service role follows least-privilege principles:

Permission Resource Purpose
s3:ListBucket Content bucket List existing objects
s3:GetObject Content bucket /* Read files during sync
s3:PutObject Content bucket /* Upload new/changed files
s3:DeleteObject Content bucket /* Remove deleted files (--delete)
cloudfront:CreateInvalidation Distribution ARN Purge CDN cache
logs:* CodeBuild log group Write build logs
ssm:GetParameters Parameter Store paths Read deploy config

πŸ” Security

Control Implementation
🚫 No public S3 Block all public access enabled; bucket policy only allows CloudFront OAC
πŸ”’ HTTPS enforced CloudFront viewer protocol redirects HTTP β†’ HTTPS; ACM TLS on custom domain
πŸ”‘ Least-privilege IAM CodeBuild role scoped to specific bucket + distribution only
πŸ—„οΈ Encryption S3 default encryption (SSE-S3); TLS in transit
πŸ“ Audit trail CloudFront access logs + CodeBuild logs in CloudWatch
πŸ”— Origin isolation OAC replaces legacy OAI β€” S3 is never directly accessible

πŸ“Š Observability & Monitoring

🚨 CloudWatch Alarm β€” 5xx Error Rate

Setting Value
Region us-east-1 (CloudFront metrics)
Metric 5xxErrorRate
Period 5 minutes
Threshold > 1% for 1 consecutive period
Action SNS β†’ email notification

πŸ“ CloudFront Access Logs

  • Destination: shaun-portfolio-cf-logs (private S3 bucket)
  • Use cases:
    • πŸ” Debug 4xx/5xx errors
    • πŸ“ˆ Analyse traffic patterns
    • πŸ“Š Future: feed into Athena/Glue for dashboards

πŸ”¨ CodeBuild Logs

  • Log group: /aws/codebuild/shaunvividsz-portfolio-build
  • Region: eu-west-1
  • Contents: Full output of s3 sync and cloudfront create-invalidation

πŸ’° Cost Monitoring

  • AWS Budgets monthly limit with email alerts on actual + forecasted spend
  • CloudWatch billing alarm on EstimatedCharges in us-east-1

πŸ’° Cost Profile

This architecture is designed for near-zero cost for a personal site:

Service Cost Driver Expected
πŸ—„οΈ S3 Storage + GET requests ~ $0.01/mo
🌐 CloudFront Data transfer + requests ~ $0.00 (free tier)
πŸ“ Route 53 1 hosted zone + queries ~ $0.50/mo
πŸ” ACM Public certificate Free
πŸ”„ CodePipeline 1 pipeline Free (1 free)
πŸ”¨ CodeBuild Build minutes ~ $0.00 (100 min/mo free)
πŸ“Š CloudWatch 1 alarm + logs ~ $0.10/mo
Total < $1/mo

βœ… No EC2 instances, no RDS databases, no continuously running compute.


πŸš€ Deployment

Quick Deploy

# 1. Make your changes
vim index.html

# 2. Commit and push
git add .
git commit -m "Update portfolio"
git push origin main

# 3. CodePipeline automatically:
#    πŸ“₯ Pulls code from GitHub
#    πŸ”¨ Runs CodeBuild (buildspec.yml)
#    πŸ“€ Syncs to S3 + invalidates CloudFront cache
#
# 4. βœ… Live at https://www.shaunvividszportfolio.com

Pipeline Stages

Stage Action Duration
πŸ“₯ Source Pull from GitHub main ~10s
πŸ”¨ Build CodeBuild runs buildspec.yml ~30s
πŸ“€ Deploy s3 sync + CloudFront invalidation ~20s
βœ… Live Changes propagated to edge locations ~60s

πŸ“‚ Repository Structure

AWS-PORTFOLIO-WEBSITE/
β”œβ”€β”€ πŸ“„ index.html          # Main portfolio page (HTML + CSS + Lucide icons)
β”œβ”€β”€ πŸ“‹ buildspec.yml       # CodeBuild deploy specification
β”œβ”€β”€ πŸ“– README.md           # This documentation
└── πŸ“ projects/           # Individual project READMEs
    β”œβ”€β”€ readme (2).md      # Serverless Blog Platform
    β”œβ”€β”€ README (3).md      # Three-Tier Blog App
    β”œβ”€β”€ README (4).md      # Serverless Ordering System
    └── README (5).md      # Static Portfolio Site (this project)

πŸ“ Lessons Learned

Challenge Resolution
🌍 ACM cert must be in us-east-1 for CloudFront Created cert in us-east-1 with DNS validation via Route 53
πŸ”— OAI vs OAC for S3 origin Used modern OAC β€” simpler bucket policy, supports SSE-KMS
πŸ”„ Cache stale after deploy Added cloudfront create-invalidation --paths "/*" in buildspec
πŸ” CodeBuild IAM too broad initially Scoped down to specific bucket ARN + distribution ARN only
πŸ“Š No visibility into errors Added CloudWatch 5xx alarm + SNS email notification

πŸ— Related Projects

# Project Architecture Key Services
01 Portfolio Site (this) Static + Edge S3, CloudFront, CodePipeline
02 Three-Tier Blog App VPC + 3-Tier VPC, ALB, EC2 ASG, RDS
03 Serverless Blog Platform Serverless Full-Stack Lambda, API GW, DynamoDB
04 Serverless Ordering System Event-Driven Saga Step Functions, SQS, DynamoDB

Built by Shaun Β· Deployed on AWS Β· Automated with CodePipeline

AWS Solutions Architect AWS Developer Terraform

About

Static portfolio website hosted on AWS with a production-style setup

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages