Jeff Sherard

Built with AI

How Claude Code built jsherard.net from scratch

Infrastructure, code, DNS, SSL — all from a terminal conversation

The Premise

This entire site — the infrastructure, the code, the DNS configuration, the SSL certificates, even the page you're reading right now — was built in a single sitting through a conversation with Claude Code, Anthropic's AI coding assistant running in a terminal. No clicking through AWS consoles. No copying from Stack Overflow. Just a senior engineer directing an AI pair-programmer through natural language.

What Got Built

AWS Infrastructure

S3 static hosting, CloudFront CDN with edge caching, ACM SSL certificates covering 6 domains, and Route 53 DNS zones — all defined as Terraform modules.

Three-Domain Setup

jsherard.net, jsherard.com, and jsherard.org all serve the same site. GoDaddy nameservers were programmatically updated via API to point to Route 53.

CI/CD Pipeline

GitHub Actions workflows that auto-deploy site content on push to main and run Terraform plan/apply for infrastructure changes.

Static Site

Clean, responsive HTML/CSS — no frameworks, no build step, no JavaScript dependencies. Fast, accessible, and maintainable.

Movie Showtimes API

An old Flask app from a defunct Lambda/Zappa deployment was recovered, modernized into a JSON API, and deployed on Lambda + API Gateway. CloudFront routes /api/* requests to the backend, and the static frontend fetches showtimes via JavaScript.

This Page

Meta? Sure. But this writeup, the architecture diagrams below, and the CSS styling it uses were all generated in the same conversation.

Architecture

Request Flow

How a browser request reaches the site content.

flowchart LR
    Browser(("User\nBrowser"))
    GD["GoDaddy\n(3 domains)"]
    R53["Route 53\n(3 hosted zones)"]
    CF["CloudFront\n(CDN + SSL)"]
    ACM["ACM\n(SAN cert)"]
    S3["S3 Bucket\n(static files)"]
    APIGW["API Gateway\n(HTTP API)"]
    Lambda["Lambda\n(Flask API)"]

    Browser -->|"jsherard.net\n.com / .org"| GD
    GD -->|"NS delegation"| R53
    R53 -->|"A / AAAA alias"| CF
    ACM -.->|"TLS termination"| CF
    CF -->|"OAC\n(static)"| S3
    CF -->|"/api/*"| APIGW
    APIGW --> Lambda

    style GD fill:#e0f2fe,stroke:#0ea5e9,color:#075985
    style R53 fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style CF fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style ACM fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style S3 fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style APIGW fill:#dbeafe,stroke:#3b82f6,color:#1e40af
    style Lambda fill:#dbeafe,stroke:#3b82f6,color:#1e40af
                            

Deployment Pipeline

How code changes reach production.

flowchart LR
    Dev(("Developer\n+ Claude Code"))
    GH["GitHub\n(private repo)"]
    GA["GitHub Actions"]
    TF["Terraform"]
    S3["S3 Bucket"]
    CF["CloudFront"]

    Dev -->|"git push"| GH
    GH -->|"on: push"| GA
    GA -->|"aws s3 sync"| S3
    GA -->|"create-invalidation"| CF
    GA -->|"lambda update"| LM["Lambda"]
    GH -->|"on: PR"| TF
    TF -->|"plan / apply"| AWS["AWS Resources"]

    style GH fill:#ede9fe,stroke:#8b5cf6,color:#5b21b6
    style GA fill:#ede9fe,stroke:#8b5cf6,color:#5b21b6
    style TF fill:#ede9fe,stroke:#8b5cf6,color:#5b21b6
    style S3 fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style CF fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style AWS fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style LM fill:#dbeafe,stroke:#3b82f6,color:#1e40af
                            

Terraform Module Structure

Infrastructure as code layout.

flowchart TD
    Root["terraform/main.tf"]
    Mod["modules/static-site"]
    MovMod["modules/movie-app"]
    S3R["aws_s3_bucket"]
    CFR["aws_cloudfront_distribution"]
    ACMR["aws_acm_certificate"]
    R53P["aws_route53_zone\n(primary)"]
    R53A["aws_route53_zone\n(aliases: .com, .org)"]
    VAL["aws_acm_certificate_validation"]
    REC["aws_route53_record\n(A, AAAA, CNAME)"]
    LFN["aws_lambda_function"]
    APIGW["aws_apigatewayv2_api"]
    IAM["aws_iam_role"]

    Root -->|"module call"| Mod
    Root -->|"module call"| MovMod
    Mod --> S3R
    Mod --> CFR
    Mod --> ACMR
    Mod --> R53P
    Mod --> R53A
    ACMR --> VAL
    VAL --> REC
    R53P --> REC
    R53A --> REC
    MovMod --> LFN
    MovMod --> APIGW
    MovMod --> IAM
    MovMod -.->|"function_url_domain"| CFR

    style Root fill:#f0fdf4,stroke:#22c55e,color:#166534
    style Mod fill:#f0fdf4,stroke:#22c55e,color:#166534
    style MovMod fill:#f0fdf4,stroke:#22c55e,color:#166534
    style S3R fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style CFR fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style ACMR fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style R53P fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style R53A fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style VAL fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style REC fill:#fef3c7,stroke:#f59e0b,color:#92400e
    style LFN fill:#dbeafe,stroke:#3b82f6,color:#1e40af
    style APIGW fill:#dbeafe,stroke:#3b82f6,color:#1e40af
    style IAM fill:#dbeafe,stroke:#3b82f6,color:#1e40af
                            
The Process
1

Scaffold

Set up the repo structure, Terraform configuration with reusable modules, and GitHub Actions workflows. Configured AWS CLI profile and IAM credentials.

2

Deploy Infrastructure

Ran terraform apply to provision the S3 bucket, CloudFront distribution, ACM certificate, and Route 53 zone. Updated GoDaddy nameservers via their API.

3

Build the Site

Created the resume page with real professional content, a landing page with navigation cards, and styled everything with vanilla CSS. No frameworks needed.

4

Deploy Movie API

Recovered an old Flask showtimes app from a defunct Zappa/Lambda deployment, converted it to a JSON API with apig-wsgi, and deployed it on Lambda + API Gateway. CloudFront proxies /api/* to the backend. GitHub Actions auto-deploys on push.

5

Multi-Domain SSL

Extended the infrastructure to serve all three domains (jsherard.net, .com, .org) from a single CloudFront distribution with a SAN certificate covering all six endpoints.

6

Document It

Built this page to show the work. Because if an AI helps you build production infrastructure in an afternoon and you don't tell anyone, did it really happen?

7

Harden State Management

Migrated Terraform state from a local file committed to git to an S3 backend with DynamoDB locking. Versioned bucket for state history, encrypted at rest, and no more secrets in the repo.

Tech Stack
AI Assistant Claude Code (Claude Opus) — Anthropic
Cloud AWS — S3, CloudFront, ACM, Route 53, Lambda, API Gateway, DynamoDB, IAM
IaC Terraform 1.14 with custom modules — S3 backend + DynamoDB locking
CI/CD GitHub Actions — deploy on push, infra on PR
DNS Route 53 (3 zones) + GoDaddy API for NS delegation
Frontend Vanilla HTML + CSS + Mermaid.js for diagrams
Backend Flask + apig-wsgi — Lambda + API Gateway HTTP API

The Takeaway

This wasn't a toy demo. It's production infrastructure — SSL, CDN, DNS, CI/CD, modular IaC — the same patterns you'd use at a company. The difference is that instead of context-switching between AWS docs, Terraform registry, and Stack Overflow, the entire build happened through a conversation. The engineer provides judgment, context, and decisions. The AI handles the boilerplate, remembers the syntax, and executes at speed.

30 years of engineering experience directing an AI that never gets tired, never loses context, and types really, really fast. That's the multiplier.