π Hey there, tech enthusiasts!
I'm Sarvar, a Cloud Architect with a passion for transforming complex technological challenges into elegant solutions. With extensive experience spanning Cloud Operations (AWS & Azure), Data Operations, Analytics, DevOps, and Generative AI, I've had the privilege of architecting solutions for global enterprises that drive real business impact. Through this article series, I'm excited to share practical insights, best practices, and hands-on experiences from my journey in the tech world. Whether you're a seasoned professional or just starting out, I aim to break down complex concepts into digestible pieces that you can apply in your projects.
π― Welcome Back!
Remember in Article 5 when you learned about variables and outputs? You created flexible, reusable S3 bucket configurations. That's great for storage, but what about networking?
Here's the reality: S3 buckets are public services. But what about:
- EC2 instances that need network isolation?
- Databases that should never be directly accessible from the internet?
- Applications that need both public and private components?
That's where VPC (Virtual Private Cloud) comes in.
By the end of this article, you'll:
- β Understand VPC fundamentals (CIDR, subnets, routing)
- β Create a production-ready VPC with Terraform
- β Configure public and private subnets
- β Set up Internet Gateway and NAT Gateway
- β Master route tables and associations
- β Use data sources to fetch AWS information
- β Build cost-optimized VPC architecture
Time Required: 45 minutes (20 min read + 25 min practice)
Cost: ~$0.05 for testing (destroy immediately!)
Difficulty: Intermediate
β οΈ IMPORTANT: NAT Gateway costs $0.045/hour (~$32/month). We'll create it for learning, but destroy it immediately after testing!
Let's build real infrastructure! π
π The Problem: Networking Confusion
The Manual Nightmare
Imagine this scenario (maybe you've lived it):
Your Task: "Set up a VPC for our new application"
You open AWS Console:
Step 1: Create VPC... wait, what's a CIDR block?
Step 2: Create subnets... public or private? What's the difference?
Step 3: Internet Gateway... where does this go?
Step 4: NAT Gateway... why do I need this?
Step 5: Route tables... which subnet goes where?
Step 6: *2 hours later* ... did I configure this correctly?
Step 7: *Application doesn't work* ... something's wrong with routing
Step 8: *Starts over* π°
Common Problems:
β Forgot route table associations - Subnets can't reach internet
β Wrong CIDR blocks - IP addresses overlap
β NAT Gateway in wrong subnet - Private instances can't update
β Inconsistent configuration - Resources don't work together
β Can't remember configuration - No documentation
β Takes hours to set up - Clicking through endless screens
Sound familiar? Let's fix this with Terraform.
π What is a VPC? (Quick Theory)
Simple Definition
VPC (Virtual Private Cloud) is your own private network in AWS. Think of it like this:
- Traditional Data Center: Physical building with servers, switches, routers
- VPC: Virtual data center with virtual servers, virtual switches, virtual routers
Key Point: Your VPC is isolated from other AWS accounts. It's YOUR private network.
VPC Components (The Building Blocks)
VPC (Your Private Network)
βββ CIDR Block (IP Address Range)
βββ Subnets (Subdivisions of your network)
β βββ Public Subnets (Internet-accessible)
β βββ Private Subnets (Internal only)
βββ Internet Gateway (Door to the internet)
βββ NAT Gateway (Private subnet's internet access)
βββ Route Tables (GPS for network traffic)
Understanding CIDR Blocks
CIDR = Classless Inter-Domain Routing (fancy name for IP address ranges)
Examples:
-
10.0.0.0/16= 65,536 IP addresses (10.0.0.0 to 10.0.255.255) -
10.0.1.0/24= 256 IP addresses (10.0.1.0 to 10.0.1.255) -
10.0.2.0/24= 256 IP addresses (10.0.2.0 to 10.0.2.255)
Simple Rule: Smaller number after / = More IP addresses
-
/16= 65,536 IPs (big network) -
/24= 256 IPs (small network) -
/32= 1 IP (single host)
Don't worry! You don't need to be a networking expert. Just follow the patterns.
Public vs Private Subnets
Public Subnet:
- β Has route to Internet Gateway
- β Resources get public IP addresses
- β Directly accessible from internet
- π Use for: Web servers, load balancers, bastion hosts
Private Subnet:
- β Has route to NAT Gateway (not Internet Gateway)
- β No public IP addresses
- β Not directly accessible from internet
- π Use for: Databases, application servers, internal services
Why both? Security! Keep sensitive resources (databases) in private subnets.
ποΈ What We'll Build Today
Architecture Overview
VPC: 10.0.0.0/16 (65,536 IPs)
β
βββ Public Subnet 1: 10.0.1.0/24 (256 IPs) - us-east-1a
β βββ Internet Gateway attached
β βββ Route: 0.0.0.0/0 β Internet Gateway
β
βββ Private Subnet 1: 10.0.11.0/24 (256 IPs) - us-east-1a
β βββ Route: 0.0.0.0/0 β NAT Gateway
Why this design?
- β Single-AZ
- β Public subnets = For load balancers, web servers
- β Private subnets = For databases, application servers
- β NAT Gateway = Private subnets can download updates
- β Production-ready = This is how real companies do it
π Step-by-Step: Building the VPC
Step 1: Create Project Directory
mkdir -p ~/terraform-vpc-demo
cd ~/terraform-vpc-demo
Step 2: Create variables.tf
Let's start with variables for flexibility:
nano variables.tf
Copy this code:
# AWS Region
variable "aws_region" {
description = "AWS region where resources will be created"
type = string
default = "us-east-1"
}
# Project Name
variable "project_name" {
description = "Project name to be used in resource naming"
type = string
default = "terraform-vpc"
}
# Environment
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
default = "dev"
}
# VPC CIDR Block
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
# Public Subnet CIDR
variable "public_subnet_cidr" {
description = "CIDR block for public subnet"
type = string
default = "10.0.1.0/24"
}
# Private Subnet CIDR
variable "private_subnet_cidr" {
description = "CIDR block for private subnet"
type = string
default = "10.0.11.0/24"
}
What's happening here?
- All CIDR blocks are variables (easy to change)
- Project name and environment for tagging
- Default values provided (but can be overridden)
- Cost-optimized: 1 public + 1 private subnet
Save the file (Ctrl+X, then Y, then Enter)
Step 3: Create terraform.tfvars
nano terraform.tfvars
Copy this code:
# Default configuration for development environment
aws_region = "us-east-1"
project_name = "terraform-vpc"
environment = "dev"
# VPC Configuration
vpc_cidr = "10.0.0.0/16"
# Subnets
public_subnet_cidr = "10.0.1.0/24"
private_subnet_cidr = "10.0.11.0/24"
Save the file
Step 4: Create main.tf (The Main Infrastructure)
This is where the magic happens! We'll build it piece by piece.
nano main.tf
Copy this code:
# Terraform configuration
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# Provider configuration
provider "aws" {
region = var.aws_region
}
# Data source: Get available availability zones
data "aws_availability_zones" "available" {
state = "available"
}
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
ManagedBy = "Terraform"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
Environment = var.environment
ManagedBy = "Terraform"
}
}
# Public Subnet 1
resource "aws_subnet" "public_1" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_1_cidr
availability_zone = data.aws_availability_zones.available.names[0]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-subnet"
Environment = var.environment
Type = "Public"
ManagedBy = "Terraform"
}
}
# Private Subnet
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidr
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "${var.project_name}-private-subnet"
Environment = var.environment
Type = "Private"
ManagedBy = "Terraform"
}
}
# Elastic IP for NAT Gateway
resource "aws_eip" "nat" {
domain = "vpc"
tags = {
Name = "${var.project_name}-nat-eip"
Environment = var.environment
ManagedBy = "Terraform"
}
depends_on = [aws_internet_gateway.main]
}
# NAT Gateway
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public_1.id
tags = {
Name = "${var.project_name}-nat-gateway"
Environment = var.environment
ManagedBy = "Terraform"
}
depends_on = [aws_internet_gateway.main]
}
# Public Route Table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "${var.project_name}-public-rt"
Environment = var.environment
Type = "Public"
ManagedBy = "Terraform"
}
}
# Private Route Table
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main.id
}
tags = {
Name = "${var.project_name}-private-rt"
Environment = var.environment
Type = "Private"
ManagedBy = "Terraform"
}
}
# Public Subnet Route Table Association
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# Private Subnet Route Table Association
resource "aws_route_table_association" "private_1" {
subnet_id = aws_subnet.private_1.id
route_table_id = aws_route_table.private.id
}
# Private Subnet Route Table Association
resource "aws_route_table_association" "private" {
subnet_id = aws_subnet.private.id
route_table_id = aws_route_table.private.id
}
Save the file
That's the complete VPC infrastructure! Let's break it down...
π Understanding the Code
1. Data Source (NEW CONCEPT!)
data "aws_availability_zones" "available" {
state = "available"
}
What's a data source?
- Resources = Things Terraform creates (VPC, subnets, etc.)
- Data Sources = Things Terraform reads from AWS (AZs, AMIs, etc.)
Why use it?
- Don't hardcode availability zones (they differ by region)
- Automatically get available AZs
- Makes code portable across regions
How to use it:
availability_zone = data.aws_availability_zones.available.names[0] # First AZ
availability_zone = data.aws_availability_zones.available.names[1] # Second AZ
2. VPC Resource
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true # Important for EC2 instances
enable_dns_support = true # Important for DNS resolution
}
Key settings:
-
enable_dns_hostnames= EC2 instances get DNS names -
enable_dns_support= DNS resolution works in VPC
Without these: Your instances can't resolve domain names!
3. Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id # Attach to our VPC
}
What it does: Allows public subnets to access the internet
Think of it as: The front door of your VPC
4. Public Subnets
resource "aws_subnet" "public_1" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_1_cidr
availability_zone = data.aws_availability_zones.available.names[0]
map_public_ip_on_launch = true # Auto-assign public IPs
}
Key setting: map_public_ip_on_launch = true
- EC2 instances in this subnet automatically get public IPs
- Makes them accessible from internet
5. Private Subnets
resource "aws_subnet" "private_1" {
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_1_cidr
availability_zone = data.aws_availability_zones.available.names[0]
# NO map_public_ip_on_launch = Private!
}
Notice: No map_public_ip_on_launch
- Instances in private subnets don't get public IPs
- More secure for databases and internal services
6. Elastic IP and NAT Gateway
# Elastic IP (static public IP)
resource "aws_eip" "nat" {
domain = "vpc"
depends_on = [aws_internet_gateway.main]
}
# NAT Gateway (in public subnet!)
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public_1.id # Must be in public subnet
depends_on = [aws_internet_gateway.main]
}
What's NAT Gateway?
- Allows private subnets to access internet (outbound only)
- Private instances can download updates, call APIs
- But internet can't initiate connections to private instances
Why Elastic IP?
- NAT Gateway needs a static public IP
- Elastic IP provides that
β οΈ COST WARNING: NAT Gateway = $0.045/hour (~$32/month)
7. Route Tables (The GPS)
Public Route Table:
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0" # All traffic
gateway_id = aws_internet_gateway.main.id # Goes to Internet Gateway
}
}
Translation: "Send all internet traffic (0.0.0.0/0) to the Internet Gateway"
Private Route Table:
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0" # All traffic
nat_gateway_id = aws_nat_gateway.main.id # Goes to NAT Gateway
}
}
Translation: "Send all internet traffic (0.0.0.0/0) to the NAT Gateway"
8. Route Table Associations
resource "aws_route_table_association" "public_1" {
subnet_id = aws_subnet.public_1.id
route_table_id = aws_route_table.public.id
}
What this does: Links subnet to route table
Think of it as: "Public Subnet 1, use the Public Route Table for routing"
Without this: Subnet doesn't know how to route traffic!
π€ Step 5: Create outputs.tf
nano outputs.tf
Copy this code:
# VPC Outputs
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "vpc_cidr" {
description = "CIDR block of the VPC"
value = aws_vpc.main.cidr_block
}
# Subnet Outputs
output "public_subnet_1_id" {
description = "ID of public subnet 1"
value = aws_subnet.public_1.id
}
output "public_subnet_2_id" {
description = "ID of public subnet 2"
value = aws_subnet.public_2.id
}
output "private_subnet_1_id" {
description = "ID of private subnet 1"
value = aws_subnet.private_1.id
}
output "private_subnet_2_id" {
description = "ID of private subnet 2"
value = aws_subnet.private_2.id
}
# Gateway Outputs
output "internet_gateway_id" {
description = "ID of the Internet Gateway"
value = aws_internet_gateway.main.id
}
output "nat_gateway_id" {
description = "ID of the NAT Gateway"
value = aws_nat_gateway.main.id
}
output "nat_gateway_public_ip" {
description = "Public IP of the NAT Gateway"
value = aws_eip.nat.public_ip
}
# Route Table Outputs
output "public_route_table_id" {
description = "ID of the public route table"
value = aws_route_table.public.id
}
output "private_route_table_id" {
description = "ID of the private route table"
value = aws_route_table.private.id
}
# Availability Zone
output "availability_zone" {
description = "Availability zone used"
value = data.aws_availability_zones.available.names[0]
}
Save the file
Why so many outputs?
- You'll need these IDs in Article 7 (EC2 + Load Balancer)
- Good documentation of what was created
- Easy to reference in other Terraform modules
π Let's Deploy the VPC!
Step 6: Initialize Terraform
terraform init
Expected output:
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.x.x...
Terraform has been successfully initialized!
Step 7: Plan the Infrastructure
terraform plan
What you'll see:
Terraform will perform the following actions:
# aws_eip.nat will be created
# aws_internet_gateway.main will be created
# aws_nat_gateway.main will be created
# aws_route_table.private will be created
# aws_route_table.public will be created
# aws_route_table_association.private_1 will be created
# aws_route_table_association.private_2 will be created
# aws_route_table_association.public_1 will be created
# aws_route_table_association.public_2 will be created
# aws_subnet.private_1 will be created
# aws_subnet.private_2 will be created
# aws_subnet.public_1 will be created
# aws_subnet.public_2 will be created
# aws_vpc.main will be created
Plan: 10 to add, 0 to change, 0 to destroy.
10 resources! That's a complete VPC infrastructure from just one command.
Review the plan carefully:
- β VPC with correct CIDR (10.0.0.0/16)
- β 4 subnets with correct CIDRs
- β Subnets in different availability zones
- β Internet Gateway attached to VPC
- β NAT Gateway in public subnet
- β Route tables with correct routes
Step 8: Apply the Configuration
terraform apply
Type yes when prompted.
Expected output:
aws_vpc.main: Creating...
aws_vpc.main: Creation complete after 2s [id=vpc-xxxxx]
aws_internet_gateway.main: Creating...
aws_subnet.public_1: Creating...
aws_subnet.public_2: Creating...
aws_subnet.private_1: Creating...
aws_subnet.private_2: Creating...
...
aws_nat_gateway.main: Creating...
aws_nat_gateway.main: Still creating... [10s elapsed]
aws_nat_gateway.main: Still creating... [20s elapsed]
...
aws_nat_gateway.main: Creation complete after 1m45s
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
Outputs:
availability_zones = [
"us-east-1a"
internet_gateway_id = "igw-xxxxx"
nat_gateway_id = "nat-xxxxx"
nat_gateway_public_ip = "54.xxx.xxx.xxx"
private_route_table_id = "rtb-xxxxx"
private_subnet_id = "subnet-xxxxx"
public_route_table_id = "rtb-xxxxx"
public_subnet_id = "subnet-xxxxx"
vpc_cidr = "10.0.0.0/16"
vpc_id = "vpc-xxxxx"
β±οΈ Time: Takes about 2-3 minutes (NAT Gateway is slow to create)
π Success! You just created production-grade networking infrastructure!
Step 9: Verify in AWS Console
Option 1: AWS CLI
# Get VPC ID
VPC_ID=$(terraform output -raw vpc_id)
# List all subnets
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone,Tags[?Key==`Name`].Value|[0]]' \
--output table
# Check NAT Gateway
aws ec2 describe-nat-gateways \
--filter "Name=vpc-id,Values=$VPC_ID" \
--query 'NatGateways[*].[NatGatewayId,State,SubnetId]' \
--output table
# Check route tables
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'RouteTables[*].[RouteTableId,Tags[?Key==`Name`].Value|[0]]' \
--output table
Option 2: AWS Console
- Go to AWS Console β VPC
- Find your VPC:
terraform-vpc-vpc - Check:
- β 2 subnets (1 public, 1 private)
- β Internet Gateway attached
- β NAT Gateway in public subnet
- β 2 route tables (public and private)
π§ Understanding Resource Dependencies
Implicit Dependencies
Terraform automatically understands dependencies when you reference resources:
resource "aws_subnet" "public_1" {
vpc_id = aws_vpc.main.id # References VPC
}
Terraform knows: "Create VPC first, then create subnet"
Explicit Dependencies
Sometimes you need to force an order:
resource "aws_eip" "nat" {
domain = "vpc"
depends_on = [aws_internet_gateway.main] # Explicit dependency
}
Why? Elastic IP in VPC requires Internet Gateway to exist first.
Dependency Graph
Terraform builds a graph of dependencies:
VPC
βββ Internet Gateway
β βββ Elastic IP
β β βββ NAT Gateway
β βββ Public Route Table
β βββ Route Table Associations
βββ Subnets
βββ Route Table Associations
Terraform creates resources in the correct order automatically!
π° Cost Breakdown
Let's talk about costs (important!):
| Resource | Cost | Notes |
|---|---|---|
| VPC | FREE | No charge for VPCs |
| Subnets | FREE | No charge for subnets |
| Internet Gateway | FREE | No charge for IGW |
| Elastic IP | FREE* | *When attached to running instance |
| NAT Gateway | $0.045/hour | ~$32/month β οΈ |
| Data Transfer | $0.045/GB | Through NAT Gateway |
Total for this setup: ~$32/month (just for NAT Gateway)
β οΈ IMPORTANT: Always destroy test infrastructure!
terraform destroy
Production Note: In production, you'd have one NAT Gateway per AZ (2 NAT Gateways = $64/month) for high availability.
π― Best Practices
1. CIDR Planning
Do:
- β Plan CIDR blocks before creating VPC
- β Leave room for growth (use /16 for VPC)
- β Use non-overlapping ranges
Don't:
- β Use overlapping CIDR blocks
- β Make VPC too small (/24 = only 256 IPs)
- β Forget about VPC peering requirements
Tool: Use CIDR Calculator for planning
2. Multi-AZ Architecture
Always use multiple availability zones:
- β High availability
- β Fault tolerance
- β Better for production
Our setup: 2 AZs (us-east-1a, us-east-1b)
3. Tagging Strategy
Always tag resources:
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
ManagedBy = "Terraform"
Project = "Learning"
}
Why?
- Easy to identify resources
- Cost allocation
- Automation and filtering
4. Separate Public and Private
Security principle:
- Public subnets: Load balancers, bastion hosts
- Private subnets: Databases, application servers
Never put databases in public subnets!
5. Use Variables
Make everything configurable:
- CIDR blocks
- Project name
- Environment
- Region
Benefit: Same code for dev, staging, prod
π Common Issues & Solutions
Issue 1: NAT Gateway Creation Timeout
Problem:
Error: timeout while waiting for state to become 'available'
Solution:
- NAT Gateway takes 2-3 minutes to create
- This is normal, just wait
- If it fails, run
terraform applyagain
Issue 2: Elastic IP Limit Reached
Problem:
Error: AddressLimitExceeded: The maximum number of addresses has been reached
Solution:
# Check current EIPs
aws ec2 describe-addresses
# Release unused EIPs
aws ec2 release-address --allocation-id eipalloc-xxxxx
# Or request limit increase in AWS Console
Issue 3: Route Table Not Associated
Problem: Subnet can't reach internet
Solution: Check route table associations:
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=$VPC_ID"
Ensure each subnet has a route table association.
Issue 4: CIDR Block Overlap
Problem:
Error: InvalidSubnet.Conflict: The CIDR 'x.x.x.x/x' conflicts with another subnet
Solution:
- Check your CIDR blocks don't overlap
- Public: 10.0.1.0/24, 10.0.2.0/24
- Private: 10.0.11.0/24, 10.0.12.0/24
- No overlap!
Issue 5: Forgot to Destroy NAT Gateway
Problem: Unexpected AWS bill
Solution:
# Check for NAT Gateways
aws ec2 describe-nat-gateways --filter "Name=state,Values=available"
# Destroy with Terraform
terraform destroy
# Or manually delete in AWS Console
π§Ή Cleanup (IMPORTANT!)
β οΈ Don't forget this step! NAT Gateway costs money.
# Destroy all resources
terraform destroy
Type yes when prompted.
Expected output:
aws_route_table_association.private_2: Destroying...
aws_route_table_association.private_1: Destroying...
aws_route_table_association.public_2: Destroying...
aws_route_table_association.public_1: Destroying...
...
aws_nat_gateway.main: Destroying...
aws_nat_gateway.main: Still destroying... [10s elapsed]
aws_nat_gateway.main: Still destroying... [20s elapsed]
...
aws_nat_gateway.main: Destruction complete after 1m30s
...
Destroy complete! Resources: 10 destroyed.
Verify deletion:
# Should return empty
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=terraform-vpc-vpc"
Clean up directory:
cd ~
rm -rf ~/terraform-vpc-demo
π What You Learned
Concepts:
- β VPC fundamentals (CIDR, subnets, routing)
- β Public vs Private subnets
- β Internet Gateway and NAT Gateway
- β Route tables and associations
- β Data sources (aws_availability_zones)
- β Resource dependencies (implicit and explicit)
- β Cost-optimized architecture
Skills:
- β Created production-ready VPC
- β Configured networking components
- β Used data sources
- β Managed complex infrastructure
- β Understood AWS networking costs
Infrastructure:
- β 1 VPC
- β 2 Subnets (1 public, 1 private)
- β 1 Internet Gateway
- β 1 NAT Gateway
- β 2 Route Tables
- β Cost-optimized setup
π Challenge: Extend Your VPC
Try these modifications:
Easy:
- Change CIDR blocks to 172.16.0.0/16
- Add a third availability zone
- Change project name and environment
Medium:
- Add more private subnets (10.0.21.0/24, 10.0.22.0/24)
- Create separate route tables for each private subnet
- Add Network ACLs for additional security
Hard:
- Add VPC Flow Logs
- Create a second NAT Gateway for high availability
- Add VPC endpoints for S3 and DynamoDB
π Useful Resources
- AWS VPC Documentation
- Terraform AWS Provider - VPC
- CIDR Calculator
- AWS VPC Pricing
- GitHub Repo with Code
π What's Next?
In Article 7, we'll deploy EC2 instances and an Application Load Balancer in this VPC!
You'll learn:
- Launch EC2 instances in public and private subnets
- Configure security groups
- Create an Application Load Balancer
- Set up health checks
- Test the complete architecture
Time: 45 minutes
Difficulty: Intermediate
Outcome: Full web application infrastructure
π Wrapping Up
Thank you for reading. I hope this article provided practical insights and a clearer understanding of the topic.
If you found this useful:
- β€οΈ Like if it added value
- π¦ Unicorn if youβre applying it today
- πΎ Save it for your next optimization session
- π Share it with your team
π‘ Whatβs Next
More deep dives are coming soon on:
- Cloud Operations
- GenAI & Agentic AI
- DevOps Automation
- Data & Platform Engineering
Follow along for weekly insights and hands-on guides.
π Portfolio & Work
You can explore my full body of work, certifications, architecture projects, and technical articles here:
π Visit My Website
π οΈ Services I Offer
If you're looking for hands-on guidance or collaboration, I provide:
- Cloud Architecture Consulting (AWS / Azure)
- DevSecOps & Automation Design
- FinOps Optimization Reviews
- Technical Writing (Cloud, DevOps, GenAI)
- Product & Architecture Reviews
- Mentorship & 1:1 Technical Guidance
π€ Letβs Connect
Iβd love to hear your thoughts. Feel free to drop a comment or connect with me on:
π LinkedIn
For collaborations, consulting, or technical discussions, reach out at:
Found this helpful? Share it with your team.
β Star the repo β’ π Follow the series β’ π¬ Ask questions
Made by Sarvar Nadaf
π https://sarvarnadaf.com
















Top comments (0)