Web Architecture on AWS
Introduction
Deploying a web service on AWS requires combining several services: VPC, EC2, Load Balancer, and a good security strategy. This section covers the most common architecture patterns.
Pattern 1: Simple Architecture
A Public EC2 Instance
┌─────────────────────────────────────────────────────────────┐
│ SIMPLE ARCHITECTURE (dev/test) │
├─────────────────────────────────────────────────────────────┤
│ │
│ INTERNET │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ IGW │ │
│ └────┬─────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ VPC │ │ │
│ │ │ │ │
│ │ ┌─────────────────▼───────────────────┐ │ │
│ │ │ PUBLIC SUBNET │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────┐ │ │ │
│ │ │ │ EC2 │ │ │ │
│ │ │ │ Web Server │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ IP: 52.1.2.3 │ │ │ │
│ │ │ │ SG: web-server │ │ │ │
│ │ │ └─────────────────┘ │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ Advantages: │
│ ✅ Simple to deploy │
│ ✅ Minimal cost │
│ ✅ Ideal for dev/test │
│ │
│ Disadvantages: │
│ ❌ No high availability │
│ ❌ Single point of failure │
│ ❌ Not scalable │
│ │
└─────────────────────────────────────────────────────────────┘
Configuration
# 1. Create a Security Group for the web
aws ec2 create-security-group \
--group-name sg-web-simple \
--description "Web server SG" \
--vpc-id vpc-xxx
# 2. Allow HTTP and HTTPS
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol tcp --port 443 --cidr 0.0.0.0/0
# 3. Launch the instance
aws ec2 run-instances \
--image-id ami-xxx \
--instance-type t3.micro \
--subnet-id subnet-public \
--security-group-ids sg-xxx \
--associate-public-ip-address \
--user-data '#!/bin/bash
yum install -y httpd
systemctl start httpd
echo "Hello World" > /var/www/html/index.html'
Pattern 2: Architecture with Load Balancer
ALB + Private Instances
┌─────────────────────────────────────────────────────────────────────────┐
│ ARCHITECTURE WITH ALB (production) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ INTERNET │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ IGW │ │
│ └────┬─────┘ │
│ │ │
│ ┌────────────────────────────┼────────────────────────────────┐ │
│ │ VPC │ (10.0.0.0/16) │ │
│ │ │ │ │
│ │ ┌────────────────────────┴────────────────────────────┐ │ │
│ │ │ PUBLIC SUBNETS │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ Public 1a │ │ Public 1b │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌───────┐ │ │ ┌───────┐ │ │ │ │
│ │ │ │ │ ALB │◄─┼──────────────┼──│ ALB │ │ │ │ │
│ │ │ │ │ node │ │ │ │ node │ │ │ │ │
│ │ │ │ └───┬───┘ │ │ └───┬───┘ │ │ │ │
│ │ │ └──────┼──────┘ └──────┼──────┘ │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────┼────────────────────────────┼───────────────┘ │ │
│ │ │ │ │ │
│ │ ┌─────────┼────────────────────────────┼───────────────┐ │ │
│ │ │ │ PRIVATE SUBNETS │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌──────▼──────┐ ┌──────▼──────┐ │ │ │
│ │ │ │ Private 1a │ │ Private 1b │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ │
│ │ │ │ │ EC2 │ │ │ │ EC2 │ │ │ │ │
│ │ │ │ │ Web 1 │ │ │ │ Web 2 │ │ │ │ │
│ │ │ │ └─────────┘ │ │ └─────────┘ │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Advantages: │
│ ✅ High availability (Multi-AZ) │
│ ✅ Scalable (add instances) │
│ ✅ SSL termination at ALB level │
│ ✅ Protected web servers (private subnet) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
AWS Load Balancer Types
| Type | Usage | OSI Layer | Protocols |
|---|---|---|---|
| ALB | HTTP/HTTPS Applications | Layer 7 | HTTP, HTTPS, gRPC |
| NLB | Ultra performance | Layer 4 | TCP, UDP, TLS |
| CLB | Legacy | Layer 4/7 | TCP, SSL, HTTP, HTTPS |
| GWLB | Network appliances | Layer 3 | IP |
ALB Configuration
# 1. Create the Target Group
aws elbv2 create-target-group \
--name tg-web-servers \
--protocol HTTP \
--port 80 \
--vpc-id vpc-xxx \
--health-check-path /health \
--health-check-interval-seconds 30
# 2. Create the Application Load Balancer
aws elbv2 create-load-balancer \
--name alb-web \
--subnets subnet-public-1a subnet-public-1b \
--security-groups sg-alb \
--scheme internet-facing \
--type application
# 3. Create the Listener
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:...:alb-web \
--protocol HTTP \
--port 80 \
--default-actions Type=forward,TargetGroupArn=arn:aws:...:tg-web-servers
# 4. Register the instances
aws elbv2 register-targets \
--target-group-arn arn:aws:...:tg-web-servers \
--targets Id=i-web1 Id=i-web2
Pattern 3: 3-Tier Architecture
Web + App + Database
┌─────────────────────────────────────────────────────────────────────────┐
│ 3-TIER ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ INTERNET │
│ │ │
│ ┌──────▼──────┐ │
│ │ IGW │ │
│ └──────┬──────┘ │
│ │ │
│ ┌──────────────────────────────┼──────────────────────────────┐ │
│ │ VPC │ │ │
│ │ │ │ │
│ │ ╔══════════════════════════╧════════════════════════════╗ │ │
│ │ ║ TIER 1: PRESENTATION ║ │ │
│ │ ║ (Public Subnet) ║ │ │
│ │ ║ ║ │ │
│ │ ║ ┌─────────────────────────┐ ║ │ │
│ │ ║ │ Application Load │ ║ │ │
│ │ ║ │ Balancer (ALB) │ ║ │ │
│ │ ║ └───────────┬─────────────┘ ║ │ │
│ │ ╚═══════════════════════╪═══════════════════════════════╝ │ │
│ │ │ │ │
│ │ ╔═══════════════════════╪═══════════════════════════════╗ │ │
│ │ ║ TIER 2: APPLICATION ║ │ │
│ │ ║ (Private App Subnet) ║ │ │
│ │ ║ │ ║ │ │
│ │ ║ ┌────────────────────┼────────────────────┐ ║ │ │
│ │ ║ │ │ │ ║ │ │
│ │ ║ ┌───▼───┐ ┌─────▼─────┐ ┌─────▼───┐ ║ │ │
│ │ ║ │ EC2 │ │ EC2 │ │ EC2 │ ║ │ │
│ │ ║ │ App 1 │ │ App 2 │ │ App 3 │ ║ │ │
│ │ ║ └───┬───┘ └─────┬─────┘ └────┬────┘ ║ │ │
│ │ ║ │ │ │ ║ │ │
│ │ ╚══════╪════════════════════╪═══════════════════╪═══════╝ │ │
│ │ │ │ │ │ │
│ │ ╔══════╪════════════════════╪═══════════════════╪═══════╗ │ │
│ │ ║ │ TIER 3: DATA │ │ ║ │ │
│ │ ║ │ (Private DB Subnet) │ ║ │ │
│ │ ║ │ │ │ ║ │ │
│ │ ║ └────────────────────┼───────────────────┘ ║ │ │
│ │ ║ │ ║ │ │
│ │ ║ ┌──────▼──────┐ ║ │ │
│ │ ║ │ RDS │ ║ │ │
│ │ ║ │ MySQL │ ║ │ │
│ │ ║ │ Multi-AZ │ ║ │ │
│ │ ║ └─────────────┘ ║ │ │
│ │ ║ ║ │ │
│ │ ╚════════════════════════════════════════════════════════╝ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Security Groups for 3-Tier
┌─────────────────────────────────────────────────────────────┐
│ SECURITY GROUPS 3-TIER │
├─────────────────────────────────────────────────────────────┤
│ │
│ sg-alb (Load Balancer) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Inbound: HTTP/443 from 0.0.0.0/0 │ │
│ │ Outbound: HTTP/80 to sg-app │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ sg-app (Application Servers) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Inbound: HTTP/80 from sg-alb │ │
│ │ Inbound: SSH/22 from sg-bastion │ │
│ │ Outbound: MySQL/3306 to sg-db │ │
│ │ Outbound: HTTPS/443 to 0.0.0.0/0 (external APIs) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ sg-db (Database) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Inbound: MySQL/3306 from sg-app │ │
│ │ Outbound: None (or minimal) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Principle: Each tier accepts ONLY traffic from the │
│ previous tier │
│ │
└─────────────────────────────────────────────────────────────┘
Health Checks
ALB Health Check Configuration
┌─────────────────────────────────────────────────────────────┐
│ HEALTH CHECKS ALB │
├─────────────────────────────────────────────────────────────┤
│ │
│ Important parameters: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Protocol : HTTP │ │
│ │ Path : /health or /api/health │ │
│ │ Port : traffic-port (80) │ │
│ │ Healthy threshold : 2 (consecutive successes) │ │
│ │ Unhealthy threshold : 3 (consecutive failures) │ │
│ │ Timeout : 5 seconds │ │
│ │ Interval : 30 seconds │ │
│ │ Success codes : 200-299 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Typical /health endpoint: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HTTP 200 OK │ │
│ │ { │ │
│ │ "status": "healthy", │ │
│ │ "database": "connected", │ │
│ │ "cache": "connected" │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
DNS with Route 53
┌─────────────────────────────────────────────────────────────┐
│ ROUTE 53 + ALB │
├─────────────────────────────────────────────────────────────┤
│ │
│ User types: www.mysite.com │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Route 53 │ │
│ │ DNS │ │
│ └──────┬───────┘ │
│ │ │
│ │ Alias Record │
│ │ www.mysite.com │
│ │ → alb-web-xxx.elb.amazonaws.com│
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ ALB │ │
│ └──────────────┘ │
│ │
│ Record types: │
│ • A (Alias): Points to AWS resource (ALB, CF, S3) │
│ • CNAME : Points to another domain name │
│ │
│ Alias Advantage: │
│ ✅ Free for requests to AWS resources │
│ ✅ Responds with IPs directly │
│ │
└─────────────────────────────────────────────────────────────┘
Summary of Patterns
| Pattern | Complexity | Cost | HA | Use Case |
|---|---|---|---|---|
| Simple EC2 | ⭐ | $ | ❌ | Dev/Test |
| ALB + EC2 | ⭐⭐ | $$ | ✅ | Simple production |
| 3-Tier | ⭐⭐⭐ | $$$ | ✅✅ | Production |
| Microservices | ⭐⭐⭐⭐ | $$$$ | ✅✅✅ | Large scale |
Next section: Lab: Web Publishing