Capstone: Deploying a Simple Web Application on AWS

AWS Fundamentals

Chapter 10 · Capstone: Deploying a Simple Web Application on AWS

Nine chapters, one piece at a time. This closing chapter combines every one of them into a single, realistic architecture — a small web application handling user photo uploads, with a database, background image processing, and real monitoring — built the way a genuine, small production deployment actually would be.

The Target Architecture

Users upload a photo through a web app; the app stores metadata in a database, saves the original image to object storage, and a background job automatically generates a thumbnail. Every piece of this deliberately gives every prior chapter's own technique a real, concrete place to apply.

Step 1 — Region & Multi-AZ Planning

Chapter 1: the whole deployment lands in one Region, with the web and database tiers deliberately spread across two Availability Zones from the very start — not retrofitted later once something has already failed.

Step 2 — An IAM Role, Not Embedded Keys

Chapter 2: a dedicated IAM role is created for the web servers, scoped to exactly what they need — s3:PutObject/s3:GetObject on the one specific application bucket, and permission to write to CloudWatch Logs. Nothing broader, and no long-term access key ever touches the application's own code.

{ "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject"], "Resource": "arn:aws:s3:::app-photo-bucket/*" }

Step 3 — VPC, Subnets & the Two Gateways

Chapter 5: one VPC, public subnets (route to an Internet Gateway) for the web tier, and private subnets (route to a NAT Gateway) for the database — outbound-only internet access for the database tier, never inbound, exactly as Chapter 5's own asymmetry described.

Step 4 — EC2 Web Servers

Chapter 3: web servers launch from a custom AMI (the application pre-installed), sized as t3.small — general-purpose, matching the workload's own modest, steady traffic. The step 2 IAM role is attached at launch; a security group allows inbound HTTP only from the load balancer (Step 8), never directly from the internet.

Step 5 — S3 for the Photos

Chapter 4: the application bucket stores original uploads in S3 Standard, with versioning enabled (protecting against an accidental overwrite) and Block Public Access left firmly on — exactly the real, account-level safeguard the chapter's own Deep Root Analytics case study made the case for. Nothing in this bucket is ever meant to be directly public.

Step 6 — RDS for Application Data

Chapter 6: a Multi-AZ RDS PostgreSQL instance sits in the private subnets from Step 3, storing photo metadata (uploader, timestamp, S3 key). Its own security group allows inbound traffic only from the web tier's security group — never a public IP, never 0.0.0.0/0.

Step 7 — A Lambda Function for Thumbnails

Chapter 7: an S3 event trigger fires a Lambda function the moment a new photo lands in the bucket, generating a real thumbnail and saving it back to S3 under a separate key prefix — a genuinely well-suited serverless job (short, event-driven, bursty) that would be wasteful to run on a permanently-provisioned EC2 instance instead. Its own IAM role is scoped identically narrowly to Step 2's — read the original, write the thumbnail, nothing more.

Step 8 — Load Balancer & Auto Scaling

Chapter 8: an Application Load Balancer (real content-based routing isn't needed here, but ALB's own container/microservice-friendly health checks are still the right default) sits in front of the web tier, distributing traffic across an Auto Scaling Group spanning both AZs from Step 1. A target tracking policy holds average CPU at 60% — the same worked example from Chapter 8 itself.

Step 9 — Monitoring & a Budget

Chapter 9: a CloudWatch alarm watches RDS free storage space (a metric collected automatically, unlike the memory/disk-space gotcha for EC2) and notifies the team before it runs low; the ASG's own target tracking policy from Step 8 is fed directly by CloudWatch's CPU metric. An AWS Budget is set at a real, planned monthly threshold — understood, per Chapter 9's own warning, as an alert mechanism, not an automatic spending cutoff.

The Full Picture

StepChapter
1Ch.1 — Region & multi-AZ planning
2Ch.2 — Scoped IAM role, no embedded keys
3Ch.5 — VPC, public/private subnets, Internet/NAT Gateways
4Ch.3 — EC2 instances, security groups
5Ch.4 — S3 storage, versioning, Block Public Access
6Ch.6 — Multi-AZ RDS, scoped security group
7Ch.7 — Lambda triggered by an S3 event
8Ch.8 — ALB + Auto Scaling Group, target tracking
9Ch.9 — CloudWatch alarms + AWS Budget

What's Still Out of Scope, Honestly

This capstone deliberately stops short of several real, genuine next steps: no CI/CD deployment pipeline for the application code itself, no CloudFront CDN or WAF in front of the ALB, no Route 53 DNS configuration, no multi-Region disaster recovery, and no containerization (ECS/EKS) as an EC2 alternative. Each is a real, legitimate next step for a production system — named honestly as still outstanding rather than treated as solved here, the same discipline this site applies to every other course's own capstone.

The Through-Line, Restated
Every step in this capstone is a direct, concrete application of a chapter's own material — nothing new was introduced here. Least privilege (Ch.2), private-by-default networking (Ch.5), scoped security groups (Ch.3/Ch.6), and honest monitoring (Ch.9) all show up together, repeatedly, because they're the same small set of real disciplines applied consistently across every AWS service, not a separate lesson for each one.
Security Runs Through Every Chapter, Not Just Chapter 2
Chapter 1's shared responsibility model, Chapter 2's least privilege, Chapter 3's IMDSv2, Chapter 4's Block Public Access, and Chapter 5's NACLs/security groups are all real, separate mechanisms — but they're all answering the same underlying real question: what's the smallest possible blast radius if any single one of them fails. This capstone's own architecture never relies on just one of them holding up alone.

Closing the Course

From Chapter 1's real global infrastructure and shared responsibility model to this chapter's own working, multi-service architecture — every chapter in between covered one specific, genuine piece of what it actually takes to run something real on AWS. Compute, storage, networking, databases, serverless, scaling, and monitoring together are what make a deployment resilient and secure — not any single service used in isolation.

Hands-On Exercises

Exercise 1

Explain, in your own words, why Step 7's thumbnail-generation job was built as a Lambda function rather than as a service running continuously on the Step 4 EC2 web servers, using the chapter's own real cost/execution-model reasoning from Chapter 7.

📄 View solution
Exercise 2

Trace, step by step, every real point in this capstone's own architecture where least privilege (Chapter 2's principle) is specifically applied, and explain what would go wrong at each point if it weren't.

📄 View solution
Exercise 3

A teammate suggests this capstone's own AWS Budget alone is sufficient to prevent unexpected overspending. Using Chapter 9's own real distinction, explain why this claim is incomplete, and name one concrete real scenario from earlier chapters where it would fail to hold.

📄 View solution

Course Complete — AWS Fundamentals

  • 10/10 chapters — from AWS's real 2006 origin and global infrastructure through a full, working multi-service architecture
  • Every chapter's own real service (IAM, EC2, S3, VPC, RDS/DynamoDB, Lambda, ALB/Auto Scaling, CloudWatch) applied together in this capstone, not in isolation
  • A recurring real thread: least privilege, private-by-default networking, and honest monitoring, applied consistently rather than as one-off lessons
  • Real, honest next steps named rather than glossed over: CI/CD, CDN/WAF, DNS, multi-Region DR, containerization
  • Next in the Cloud Platform Specifics arc: Azure Fundamentals (azure1) and GCP Fundamentals (gcp1), deliberately structured chapter-for-chapter in parallel with this course