Sooner or later every DevOps engineer has to pick an address range. You size a VPC, carve subnets for three availability zones, choose a pod CIDR for a Kubernetes cluster, or discover that your VPN range collides with the one your office already uses. Subnetting looks like arcane binary arithmetic, but it comes down to one idea: an address has a part that names the network and a part that names the host, and the prefix length tells you where the boundary sits. This guide builds that idea from the ground up and finishes with practical design patterns.
To check any calculation as you read, use the CIDR and subnet calculator, which shows the network, broadcast, mask and usable range for IPv4 and IPv6.
Addresses are just 32 bits
An IPv4 address is a 32-bit number written as four decimal bytes. 192.168.10.37 is really:
192 168 10 37
11000000.10101000.00001010.00100101
Each byte, or octet, runs from 0 to 255. Nothing about the dots is special; they exist for readability. A subnet is a contiguous block of those 32-bit numbers that share the same leading bits.
Network bits, host bits and the prefix
CIDR notation writes the block as an address, a slash and a number: 192.168.10.0/26. The number is the prefix length, the count of leading bits that are fixed and identify the network. The remaining 32 - 26 = 6 bits are free to vary and identify hosts inside it.
The same boundary can be written as a subnet mask, a 32-bit value with ones for the network bits and zeros for the host bits. For /26 that is 11111111.11111111.11111111.11000000, or 255.255.255.192 in decimal. Combine any address in the block with the mask using a bitwise AND and you get the network address.
The number of addresses in a block is always a power of two: 2^(32 - prefix). Two of those addresses are reserved in ordinary subnets. The first is the network address (all host bits zero) and the last is the broadcast address (all host bits one). That leaves 2^(32 - prefix) - 2 usable hosts.
| Prefix | Subnet mask | Addresses | Usable hosts |
|---|---|---|---|
| /8 | 255.0.0.0 | 16,777,216 | 16,777,214 |
| /16 | 255.255.0.0 | 65,536 | 65,534 |
| /20 | 255.255.240.0 | 4,096 | 4,094 |
| /24 | 255.255.255.0 | 256 | 254 |
| /25 | 255.255.255.128 | 128 | 126 |
| /26 | 255.255.255.192 | 64 | 62 |
| /27 | 255.255.255.224 | 32 | 30 |
| /28 | 255.255.255.240 | 16 | 14 |
| /29 | 255.255.255.248 | 8 | 6 |
| /30 | 255.255.255.252 | 4 | 2 |
| /31 | 255.255.255.254 | 2 | 2 (RFC 3021) |
| /32 | 255.255.255.255 | 1 | 1 |
Two special cases are worth remembering. A /32 is a single host, which is how you write one address in a firewall rule or route. A /31 is designed for point-to-point links, and RFC 3021 makes both addresses usable because a two-device link does not need a broadcast address.
Working an example by hand
Take 192.168.10.37/26. Which network is this host on, and what is the usable range?
- The prefix is 26, so the last octet is partly network and partly host. The mask’s last octet is
192(binary11000000). - The block size is
256 - 192 = 64. Subnets in this octet therefore start at 0, 64, 128 and 192. - The value 37 falls between 0 and 63, so the network address is
192.168.10.0. - The broadcast address is the last in the block:
192.168.10.63. - Usable hosts run from
192.168.10.1to192.168.10.62, which is 62 addresses.
Another: 10.0.0.77/28. The block size is 16, and multiples of 16 are 0, 16, 32, 48, 64, 80. The number 77 sits in the block starting at 64, so the network is 10.0.0.64, the broadcast is 10.0.0.79, and the usable range is 10.0.0.65 to 10.0.0.78, a total of 14 hosts.
The shortcut is always the same: compute the block size as 256 - mask octet, find the multiple of it at or below your value, and the network address is that multiple. You can verify any result in the subnet calculator in a second.
Private ranges you will actually use
Three blocks are reserved for private networks by RFC 1918, and you will draw almost all internal addressing from them:
10.0.0.0/8provides about 16.7 million addresses and is the usual choice for clouds and large organisations.172.16.0.0/12covers172.16.0.0to172.31.255.255. Note that172.32.0.0is public.192.168.0.0/16is typical of home and small-office networks.
Two other ranges often surprise people. 100.64.0.0/10 is carrier-grade NAT space (RFC 6598) and appears in some mobile and ISP networks. 169.254.0.0/16 is link-local; if a machine has one of these addresses it failed to get a DHCP lease.
Designing a VPC
Suppose you choose 10.0.0.0/16 for a VPC, giving 65,536 addresses. You want three availability zones with a private and a public subnet in each. A tidy approach is to split the VPC into equal /20 blocks first. Going from /16 to /20 adds four bits, so you get 2^4 = 16 subnets of 4,096 addresses each:
10.0.0.0/20 10.0.16.0/20 10.0.32.0/20 10.0.48.0/20
10.0.64.0/20 10.0.80.0/20 ...
Use the first three for private workloads, one per zone, and keep others in reserve. Public subnets that only hold load balancers and NAT gateways need far fewer addresses, so subdivide one more /20 into /24 blocks such as 10.0.128.0/24, 10.0.129.0/24 and 10.0.130.0/24.
Remember that cloud providers reserve addresses inside each subnet. AWS, for example, reserves the first four and the last address, so a /20 offers 4,091 usable addresses rather than 4,094. Also plan for growth: Kubernetes nodes, load balancers and managed services all consume addresses quickly, and a subnet cannot be resized in place. It is far cheaper to start generous than to renumber later.
Subnetting in Kubernetes and Docker
Container platforms use CIDR blocks too, and the defaults can collide with your network.
Docker’s default bridge network uses 172.17.0.0/16. If your corporate VPN also hands out addresses in that range, containers and VPN hosts become unreachable from each other. You can define a safe network explicitly, either with docker network create --subnet 172.28.0.0/16 appnet or in a Compose file. If you are turning commands into Compose files, the Docker run to Compose converter handles --network flags for you.
Kubernetes needs a pod CIDR and a service CIDR. Common defaults are 10.244.0.0/16 for pods (the Flannel default) and 10.96.0.0/12 for services (the kubeadm default). Each node typically receives a /24 slice of the pod range, which means about 254 addresses per node and a default cap of 110 pods. If your VPC already uses 10.0.0.0/8, make sure the cluster ranges do not overlap with it or with any peered network.
Summarising and aligning blocks
You can merge adjacent subnets into one larger block, but only if the result is aligned. A block must start at a multiple of its own size. 10.0.0.0/24 and 10.0.1.0/24 combine into 10.0.0.0/23, because 0 is a multiple of 2 in the third octet. 10.0.1.0/24 and 10.0.2.0/24 cannot combine into a /23: the pair starts at 1, which is not a multiple of 2, so a /23 starting there is not valid. Alignment is why careful engineers allocate subnets in size order, largest first.
This matters when writing route tables, firewall rules and peering routes: one summary route is easier to maintain than a dozen individual ones, as long as the underlying ranges are contiguous and aligned.
A short note on IPv6
IPv6 addresses are 128 bits written in hexadecimal, with :: standing for one run of zero groups. The ideas are the same, but the conventions differ. A normal LAN subnet is always a /64, which leaves 64 bits for hosts. Sites commonly receive a /48 or /56, so a /48 contains 65,536 possible /64 subnets. There is no broadcast address in IPv6, so every address in the prefix is assignable. Because the space is so large, nobody counts hosts; you count subnets.
Common mistakes to avoid
- Forgetting reserved addresses. The usable count is two lower than the block size, and cloud providers reserve more.
- Choosing a range that is too small. A
/24for a VPC subnet holds at most about 250 workloads, which a busy cluster exhausts quickly. - Overlapping ranges. Two networks that share addresses cannot be peered or joined by VPN without NAT. Keep a central register of every CIDR in use.
- Typing host bits.
192.168.1.77/24describes the network192.168.1.0/24. Be explicit by writing the network address in configuration. - Misreading
172.16.0.0/12. It spans 16/16blocks, ending at172.31.255.255.
Next steps
Subnetting becomes fast with a handful of anchors: the powers of two up to 256, the block-size shortcut and the prefix table above. Practise on real ranges from your own infrastructure with the CIDR calculator, try splitting a block into smaller subnets, and test whether specific addresses fall inside it. If you are also automating network or backup jobs, the companion guide How Cron Syntax Works covers scheduling.