DEV Community

Cover image for πŸš€ The Cloud Resume Challenge My Journey to Cloud Mastery
Devin
Devin

Posted on

πŸš€ The Cloud Resume Challenge My Journey to Cloud Mastery

As a technologist looking to build real world cloud skills, I took on the Cloud Resume Challenge: a project that tests and demonstrates core cloud knowledge through hands-on implementation. This challenge wasn't just about deploying a website; it was a full-spectrum journey through modern cloud infrastructure, tools, development practices, and operational procedures.


🌩️ What is the Cloud Resume Challenge

Created by Forrest Brazeal, the Cloud Resume Challenge is a real project that guides you through building and deploying a cloud-native resume website. It covers many core principles of cloud computing and DevOps workflows including:

  • πŸ— Infrastructure as Code
  • βš™οΈ Serverless architecture
  • 🎨 Frontend development
  • πŸš€ CI/CD pipelines
  • 🌐 DNS setup
  • πŸ” Cloud security

The goal is to not just build a site, but to treat your resume like a real-world cloud application where security, automation, and scalability matter.


πŸ›  My Stack and Architecture

To complete this challenge I leveraged several AWS services as well as modern development tools. The architecture includes:

  • πŸ–₯ Frontend: Static resume website built with HTML, Tailwind CSS, and JavaScript
  • πŸ“¦ Hosting and Delivery: Private S3 bucket with content served via CloudFront with HTTPS
  • 🧠 Backend: AWS Lambda functions triggered via API Gateway to serve a dynamic visitor counter
  • πŸ—ƒ Database: DynamoDB table to store and increment visitor count
  • πŸ“œ Infrastructure: Defined and provisioned using Terraform for repeatability and version control
  • πŸ€– CI/CD Pipeline: GitHub Actions to automate builds, testing, deployment, and cache invalidation
  • 🌍 DNS Management: Custom domain from PorkBun managed in Route 53 with alias records to CloudFront

Cloud Architecture Diagram


🧭 The Build Step by Step

1️⃣ Resume with HTML and Tailwind

I started with a simple static resume coded in HTML and styled using Tailwind CSS. Tailwind was chosen for its utility-first approach, which let me quickly build responsive layouts without writing much custom CSS. I implemented dark mode media query support and ensured the design worked well on mobile and desktop devices.

Live Website Screenshot

2️⃣ Hosting with S3 and CloudFront

To securely host the static site, I created a private S3 bucket and blocked all public access. Using an Origin Access Identity (OAI), I configured CloudFront to act as the only trusted source that could pull content from the bucket. This ensures your content remains secure and only served through the CDN.

S3 Bucket Settings

3️⃣ DNS Setup with Route 53 and PorkBun

After registering my domain through PorkBun, I delegated DNS authority to AWS Route 53. I set up a hosted zone, created A records with alias targets pointing to the CloudFront distribution, and updated name servers in PorkBun.

Route53 Hosted Zone

4️⃣ Visitor Counter with Lambda and DynamoDB

The visitor counter feature required backend logic. I wrote a Lambda function in Python which incremented a counter in DynamoDB and returned the updated count via API Gateway.

import json
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('cloudresume-counter')

def lambda_handler(event, context):
    try:
        response = table.update_item(
            Key={'id': '1'},
            UpdateExpression='ADD views :incr',
            ExpressionAttributeValues={':incr': 1},
            ReturnValues='UPDATED_NEW'
        )
        return {
            'statusCode': 200,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET'
            },
            'body': json.dumps({'views': int(response['Attributes']['views'])})
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({'error': str(e)})
        }
Enter fullscreen mode Exit fullscreen mode

Lambda Function Dashboard

5️⃣ Lightweight Infrastructure Automation with Terraform

While much of the infrastructure setup was done manually via the AWS Console to gain hands-on familiarity, I used Terraform selectively to automate key backend services and streamline CI/CD integration.

βš™οΈ What I Managed with Terraform:

  • 🧠 DynamoDB Table to store the visitor count with on-demand billing
  • 🧬 Lambda Function deployment, environment variables, and IAM execution role
  • 🌐 API Gateway setup with correct CORS configuration and route integration
  • πŸ” IAM Policies for secure resource access
  • πŸ€– CI/CD Support via IAM credentials for GitHub Actions

This approach let me avoid repetitive manual setups for serverless and security components, while keeping the frontend (S3, CloudFront, Route 53) more visual and hands-on for learning.

🧩 Why Partial Terraform?

  • I wanted to focus Terraform on areas where automation made the biggest impact, such as API deployment and IAM security.
  • This hybrid approach gave me better control during debugging while still benefiting from repeatable deployments for Lambda and CI/CD.

terraform/
β”œβ”€β”€ main.tf # Root module
β”œβ”€β”€ lambda.tf # Lambda + IAM
β”œβ”€β”€ dynamodb.tf # DynamoDB setup
β”œβ”€β”€ apigateway.tf # API Gateway resources
β”œβ”€β”€ variables.tf # Inputs
β”œβ”€β”€ outputs.tf # Useful outputs like API endpoint
β”œβ”€β”€ lambda/

6️⃣ Deployment Pipeline with GitHub Actions

CI/CD was automated using GitHub Actions. The pipeline triggers on push to the main branch and includes:

  • Installing dependencies
  • Building Tailwind CSS output
  • Uploading files to S3 with AWS CLI
  • Invalidating CloudFront cache
  • Basic HTML linting checks

GitHub Actions Run


🧩 Challenges

πŸ”’ Private S3 Access

Configuring the correct permissions for private S3 access was tricky. I used the principle of least privilege and created an Origin Access Identity (OAI), then applied a bucket policy allowing only that OAI to read content.

🌐 CORS Errors

The Lambda API required correct CORS settings to work with the frontend JavaScript. I had to carefully set headers both in the AWS Console and in Terraform.

🧼 Cache Invalidation

Updates weren’t showing up due to CloudFront’s cache. I added an invalidation step to my GitHub Actions workflow to automatically purge the cache.

πŸ“¦ Terraform State

I used an S3 backend and DynamoDB table for locking to manage Terraform state securely and avoid corruption.


πŸ“š What I Learned

This challenge helped me grow in many areas of cloud engineering:

  • ⚑ Build clean, fast UIs with Tailwind CSS
  • πŸ” Secure S3 buckets using OAI
  • 🌍 Use multiple DNS providers
  • πŸ›  Modularize infrastructure with Terraform
  • πŸ€– Automate deployments with GitHub Actions
  • 🧠 Build serverless functions
  • πŸ“ˆ Debug cloud deployments using logs and state

πŸ”­ Improvements Ahead

Plans for future improvement include:

  • πŸ›‘ Add AWS WAF for security
  • πŸ“ˆ Monitor with CloudWatch Alarms
  • 🌐 Use multi-region CloudFront
  • ☁️ Use Terraform Cloud for state management
  • πŸ“Š Add real-time user analytics

🏁 Final Thoughts

The Cloud Resume Challenge turned a simple website into a full-scale cloud project. It pushed me to adopt industry standards, automation, and good security practices.

πŸ”— Live site: godevtech.cloud
πŸ“‚ GitHub repo: GitHub

Top comments (0)