Subnets & CIDR — dividing the network into zones
You could throw every server onto one flat network — and plenty of people do, right up until the day it bites them. Subnets are how you carve that one network into separate zones, so a problem in one corner doesn't spill into the rest.
What a subnet actually is
A subnet is just a block of IP addresses you treat as one group. If two devices sit in the same subnet, they talk to each other directly. If they're in different subnets, the traffic has to pass through a router first — and usually a firewall along the way.
Here's why that's worth the effort: if someone breaks into your website (the frontend), they still can't touch the database. To get there they'd have to hop into the app layer first, then into the DB — and every one of those hops is guarded by its own firewall rules. You've made the attacker work for it.
CIDR notation, quickly
CIDR (Classless Inter-Domain Routing) is a compact way to write down a range of IPs. You write it as network/prefix, where the prefix tells you how many bits are locked in as the "network part". The rest is free for hosts.
| CIDR | Range | Usable hosts | Typical use |
|---|---|---|---|
10.0.0.0/8 | 10.0.0.0 – 10.255.255.255 | ~16.7M | Entire private space |
10.0.0.0/16 | 10.0.0.0 – 10.0.255.255 | 65,534 | A whole VPC |
10.0.1.0/24 | 10.0.1.0 – 10.0.1.255 | 254 | One subnet |
10.0.1.0/28 | 10.0.1.0 – 10.0.1.15 | 14 | Tiny subnet — small services |
10.0.1.5/32 | single IP | 1 | A specific host |
Rule of thumb: the bigger the number after the slash, the smaller the network. It feels backwards at first, but it clicks fast. A /24 is the size you'll reach for most often — 256 addresses, of which 254 are usable (2 are reserved for the network and broadcast).
Usable hosts = 2(32 − prefix) − 2. So a /24 = 28 − 2 = 254. A /28 = 24 − 2 = 14.
Network and broadcast addresses
Every subnet quietly loses two addresses off the top — you never get to hand these out:
- Network address — the first address, which names the subnet itself (
10.0.1.0for10.0.1.0/24). - Broadcast address — the last address, meaning "everyone on this subnet at once" (
10.0.1.255).
Clouds take a bit more. In AWS and friends, a few extra addresses are set aside for the gateway, the DNS resolver, and future use — usually the first four and the last one. Worth knowing when you're counting how many hosts a subnet really fits.
Public vs private subnets in the cloud
Public subnet
Has a route to the internet through an Internet Gateway. Servers here can reach out and be reached directly. This is where you park load balancers and jump boxes.
Private subnet
No direct route out. Outbound traffic sneaks through a NAT Gateway, and nothing on the internet can dial in. This is where your app servers and databases belong.
If a box lives in a private subnet, it has no public IP, so you can't SSH straight to it from your laptop — and that's on purpose. The usual way in is a jump box (bastion) sitting in the public subnet: you SSH to the jump box, then hop from there to the private server. So before you go hunting for a broken firewall rule, check which subnet the server is actually in. "No public IP" isn't a bug here; it's the design.
Sizing your subnets
Here's a layout you'll see over and over in small cloud setups — steal it as a starting point:
VPC: 10.0.0.0/16 (65,536 IPs)
Public subnet A: 10.0.1.0/24 (256 IPs)
Public subnet B: 10.0.2.0/24 (256 IPs) — different AZ for HA
Private subnet A: 10.0.10.0/24
Private subnet B: 10.0.11.0/24
DB subnet A: 10.0.20.0/24
DB subnet B: 10.0.21.0/24
Pick VPC ranges that won't collide with anything you might one day connect to — a partner's VPC, your on-prem network, a VPN. The day two networks with the same range need to talk, someone has to renumber, and it's never fun. You've got all of 10.0.0.0/8 to play with, so spread things out and give yourself room.
Try it yourself
A couple of quick ways to sanity-check a CIDR:
# Is 10.0.1.42 inside 10.0.1.0/24? → yes
# Is 10.0.1.42 inside 10.0.2.0/24? → no
# On Linux
ipcalc 10.0.1.0/24
# Or in Python
python -c "import ipaddress; net = ipaddress.ip_network('10.0.1.0/24'); \
print(len(list(net.hosts())))"
Key takeaways
- Subnets carve a network into separate zones — that separation is what keeps you secure.
- CIDR
a.b.c.d/ntells you the range, and a biggernmeans a smaller subnet. - Public subnets reach the internet directly; private ones only get out through a NAT.
- The first and last address of every subnet are always spoken for.
- Plan your CIDR ranges up front — untangling an overlap later is a real headache.