iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Subnets & Routes

A subnet is a CIDR block inside a VPC, tied to one Availability Zone. Public subnets route to an Internet Gateway; private subnets don’t. The boundary between the two is the security backbone of every AWS account.

Public + private subnet pair, with route tables

EXAMPLE
# 1) Plan the addressing — RFC-1918, generous, multi-AZ
# VPC:                10.0.0.0/16
#   AZ a:  public  10.0.0.0/24   private 10.0.16.0/20
#   AZ b:  public  10.0.1.0/24   private 10.0.32.0/20
#   AZ c:  public  10.0.2.0/24   private 10.0.48.0/20

# 2) Create VPC + subnets
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=app}]'
# returns vpc-abc123

aws ec2 create-subnet --vpc-id vpc-abc123 --cidr-block 10.0.0.0/24  --availability-zone us-east-1a
aws ec2 create-subnet --vpc-id vpc-abc123 --cidr-block 10.0.16.0/20 --availability-zone us-east-1a
aws ec2 create-subnet --vpc-id vpc-abc123 --cidr-block 10.0.1.0/24  --availability-zone us-east-1b
# …

# 3) Internet gateway (only for PUBLIC subnets)
aws ec2 create-internet-gateway
aws ec2 attach-internet-gateway --vpc-id vpc-abc123 --internet-gateway-id igw-abc

# 4) Route tables
# Public — 0.0.0.0/0 → IGW
aws ec2 create-route-table --vpc-id vpc-abc123     # → rtb-pub
aws ec2 create-route --route-table-id rtb-pub --destination-cidr-block 0.0.0.0/0 --gateway-id igw-abc
aws ec2 associate-route-table --route-table-id rtb-pub --subnet-id subnet-pub-a

# Private — 0.0.0.0/0 → NAT gateway (lives in a public subnet)
aws ec2 allocate-address --domain vpc                                       # eip
aws ec2 create-nat-gateway --subnet-id subnet-pub-a --allocation-id eipalloc-…
aws ec2 create-route-table --vpc-id vpc-abc123                              # → rtb-priv
aws ec2 create-route --route-table-id rtb-priv --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-…

# 5) Sanity check — what gets where
aws ec2 describe-subnets --filters Name=vpc-id,Values=vpc-abc123 \
    --query 'Subnets[*].[SubnetId,AvailabilityZone,CidrBlock,MapPublicIpOnLaunch]' --output table

# 6) Equivalent in Terraform — shape that everyone copies
# resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" }
# resource "aws_subnet" "public" {
#     for_each                = toset(["a","b","c"])
#     vpc_id                  = aws_vpc.main.id
#     availability_zone       = "us-east-1${each.key}"
#     cidr_block              = "10.0.${index(["a","b","c"], each.key)}.0/24"
#     map_public_ip_on_launch = true
# }

# 7) Best practices
#   • App + DB in private subnets — never public IPs on databases
#   • One NAT GW per AZ (HA) — or use NAT instances + autoscaling for cost
#   • Use VPC endpoints for S3 / DynamoDB to skip NAT egress charges entirely
#   • Tag subnets `kubernetes.io/role/elb` and `…/internal-elb` for EKS

Why it matters

A public subnet is just “has a route to an IGW”; a private subnet is “doesn’t.” The hardest AWS bills come from misrouted private subnets accidentally egressing through a NAT gateway you forgot about.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# Public subnets have route to internet gateway.
# Private subnets reach internet via NAT.
Try it Yourself »

Discussion

Loading…