CIDR blocks, subnets, and Availability Zones
The VPC from the previous lesson is one range of addresses, 10.0.0.0/16. A subnet is a slice of that range placed in a single Availability Zone. This lesson splits the range, shows why one subnet cannot cover two zones, and why the numbers you pick now are hard to change after another network is connected.
Reading the CIDR
10.0.0.0/16 means “addresses that start with 10.0.” The /16 is how many leading bits are fixed. The remaining 16 bits can vary, so the range runs from 10.0.0.0 through 10.0.255.255: 65,536 addresses. A /24 fixes 24 bits, so 10.0.1.0/24 is only 10.0.1.0 through 10.0.1.255: 256 addresses.
A smaller prefix number is a larger network. /16 holds many /24s. The subnet’s CIDR has to sit entirely inside the VPC CIDR, and two subnets in the same VPC cannot overlap.
Five addresses you cannot use
AWS reserves the first four and the last address of every subnet. In 10.0.1.0/24 those are:
10.0.1.0— the network address10.0.1.1— the VPC router10.0.1.2— the DNS resolver10.0.1.3— reserved for future use10.0.1.255— the broadcast address, which AWS does not use, but still will not give you
A /24 therefore has 251 addresses you can assign. A /28 (16 addresses, 11 usable) is plenty for a load balancer and painful for a subnet you later want to fill with tasks. Carve smaller than the VPC, and leave room. Do not carve so small that the subnet is full the first time you add a zone.
One subnet, one zone
An Availability Zone is a separate data center (or group of them) inside the region. A subnet belongs to exactly one zone. There is no setting that stretches 10.0.1.0/24 across eu-west-2a and eu-west-2b.
To keep running when one zone fails, you create a second subnet from a different slice of the VPC, in the other zone. Instances in 10.0.1.0/24 and 10.0.2.0/24 still reach each other: both ranges are inside 10.0.0.0/16, and the VPC router delivers that traffic. The route that does it is the next lesson. The address plan has to allow it first.
| Name | CIDR | Zone | Role later in the course |
|---|---|---|---|
public-a |
10.0.1.0/24 |
eu-west-2a |
Load balancer and anything that must accept internet routes |
public-b |
10.0.2.0/24 |
eu-west-2b |
The same tier, in the other zone |
private-a |
10.0.11.0/24 |
eu-west-2a |
Databases and tasks with no inbound internet route |
private-b |
10.0.12.0/24 |
eu-west-2b |
The same tier, in the other zone |
The names say “public” and “private” early so the later lessons have a stable layout. Nothing in this table makes a subnet public. A subnet becomes public when its route table sends internet traffic to an internet gateway and the instance has a public address. Both are still absent. The gap between 10.0.2.0/24 and 10.0.11.0/24 is spare space, not waste: you can add 10.0.3.0/24 in a third zone without renumbering.
Overlapping ranges come back later
Two networks can be connected only when their addresses do not overlap. If this VPC is 10.0.0.0/16 and the office, or a second VPC, is also 10.0.0.0/16, a packet for 10.0.1.20 has two homes. Routing cannot prefer one of them cleanly, and VPC peering will refuse the connection.
Pick the VPC CIDR before you launch anything you mean to keep. Changing it means creating a new VPC and moving the workloads. Adding a secondary CIDR later is possible and is how teams dig themselves out. It is not a plan.
Check three places before you lock the number: the default VPC in that account (172.31.0.0/16), any other VPC you already have, and the LAN range of any office you might connect with a VPN. 10.0.0.0/16 is fine in a lab. It is a frequent collision in companies that use 10.0.0.0/8 internally. A less common slice, such as 10.42.0.0/16, is the same kind of network with fewer surprises.
Subnets in Terraform
Each subnet names the VPC, the slice, and the zone. map_public_ip_on_launch stays off. A subnet you create does not assign public addresses unless you set this. The default VPC’s subnets are the ones that turn it on. Leaving it off here keeps that choice for a later lesson.
resource "aws_subnet" "app" {
for_each = {
a = { cidr = "10.0.1.0/24", az = "eu-west-2a" }
b = { cidr = "10.0.2.0/24", az = "eu-west-2b" }
}
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.az
map_public_ip_on_launch = false
tags = { Name = "app-${each.key}" }
}
When one subnet is the wrong default
- The whole
/16is a single subnet in one zone. You cannot add a second zone without a new subnet, and you have no spare range left inside the VPC. - Both application tiers share a subnet. A database and a load balancer then have the same route table. You will want different routes for them, and a route table is attached per subnet, not per instance.
- The CIDR matches a network you will connect. Peering and VPN fail, or traffic black-holes, months after the instances are running.
Leave the lesson with four
/24s inside one/16, two zones, and no internet route. The next lesson is the table that decides where packets to those addresses actually go.