AWS Static Resume Website

AWS Logo
Project Overview:

Overview

This project documents how I built and deployed my personal resume site on AWS. The goal was to create a lightweight portfolio that is easy to maintain, globally available, and backed by a simple serverless component for a real visitor counter.

The result is a static website architecture that is inexpensive to run, straightforward to update, and a practical example of combining core AWS services into a small production-style deployment.

Architecture Overview

AWS Static Site Diagram

Step 1: Prepare the Static Site

The frontend was built with HTML, CSS, and a small amount of JavaScript. At a minimum, the deployment requires an index.html entry point and any supporting assets such as images, icons, or additional pages.

Because the site is static, updates are simple: modify the files locally and upload the latest version to the hosting bucket.

Step 2: Configure the S3 Bucket

I created an S3 bucket aligned with the site domain and uploaded the static assets to it. S3 acts as the origin for the website content and provides a simple deployment target for future updates.

For a basic static hosting setup, the bucket can expose public read access to the site objects. An example policy is shown below:

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

Step 3: Set Up CloudFront

I placed CloudFront in front of the S3 origin to improve global performance, enable HTTPS, and provide a cleaner public entry point for the website.

In this setup, the S3 website endpoint is used as the origin rather than the REST endpoint.

Step 4: Connect the Domain with Route53

Route53 was used to manage DNS for the custom domain. The public record is an A alias record pointing to the CloudFront distribution, which keeps the URL clean and avoids exposing the distribution domain to visitors.

Type: A (Alias)
Name: mycoolwebsite.com
Alias Target: dxxxxxxxxxxxx.cloudfront.net

Step 5: Add a Shared Visitor Counter

To make the site slightly more dynamic, I added a visitor counter backed by DynamoDB and Lambda. Unlike a browser-only solution, this approach keeps a shared count that is visible to every visitor.

  1. Create a DynamoDB table such as VisitorCount with a primary key like id.
  2. Create a Lambda function that increments the stored count and returns the updated value.
  3. Expose the function through API Gateway so the static site can request the current count from JavaScript.

Example Lambda function (Node.js):

const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
    const params = {
        TableName: 'VisitorCount',
        Key: { id: 'main' },
        UpdateExpression: 'ADD #c :inc',
        ExpressionAttributeNames: { '#c': 'count' },
        ExpressionAttributeValues: { ':inc': 1 },
        ReturnValues: 'UPDATED_NEW'
    };
    const result = await dynamo.update(params).promise();
    return {
        statusCode: 200,
        headers: { 'Access-Control-Allow-Origin': '*' },
        body: JSON.stringify({ count: result.Attributes.count })
    };
};

Example client-side request:

<script>
fetch('https://your-api-id.execute-api.ap-southeast-1.amazonaws.com/default/VisitorCounter')
  .then(res => res.json())
  .then(data => {
    document.getElementById('visitors').textContent = data.count;
  });
</script>

With this in place, each page load can retrieve and display a shared visitor count from the backend service.

Deployment and Validation

After the infrastructure was configured, I validated the deployment by checking content delivery through the custom domain, confirming HTTPS redirection, and verifying that the visitor counter updated successfully through the API.

For troubleshooting, the main checkpoints were S3 object access, CloudFront origin settings, and Lambda or API Gateway logs.

Outcome and Key Takeaways

This project was a useful exercise in building a small but complete cloud-hosted application. It combines static hosting, CDN delivery, DNS management, and serverless components in a way that is practical, low-cost, and easy to reason about.

Beyond serving as my personal website, it also works as a compact case study for deploying frontend assets on AWS and extending a static site with lightweight backend functionality.