You have seen 192.168.1.0/24 in every tutorial. You have typed 255.255.255.0 into a network config without thinking twice. Nobody told you these two mean the exact same thing, just written differently. And that is where most networking confusion starts.
IP addressing is not complicated. It just gets taught badly - tools first, concepts never. By the end of this, you will know exactly what that /24 means, why NAT exists, how subnets are carved out of an address block, and what actually happens when a packet leaves your machine and lands somewhere else.
This is not theory for an exam. Every VPC you configure, every Kubernetes cluster you deploy, every firewall rule you write, all of it sits on top of what we are covering here.
Table of Content

IP Addresses
An IPv4 address is a 32-bit number. That is it. The dots, the octets, the notation is just a human-readable way to look at those 32 bits.
When you see 192.168.1.10, what you are actually looking at is four groups of 8 bits each, separated by dots. Each group is called an octet. Each octet can hold a value from 0 to 255, because 8 bits can represent 2⁸ = 256 values. Four octets, 32 bits total.
In binary, 192.168.1.10 looks like this:
11000000.10101000.00000001.00001010You do not need to memorise binary conversions. But you need to understand that the address is a number, not a label. There is structure inside it.
Network vs Host
Every IP address is split into two parts, the network part and the host part. The network part identifies which network the device belongs to. The host part identifies the specific device inside that network.
Think of it like a postal address. The city and PIN code is the network part. The house number is the host part. Two devices can have the same house number as long as they are in different cities.
Where exactly the network part ends and the host part begins, that is what the subnet mask tells you.
The IPv4 Problem
32 bits gives you 2³² possible addresses. That is roughly 4.3 billion addresses. In 1981 when IPv4 was designed, that seemed like more than enough. The internet was a research network with a few thousand machines.
By the early 1990s it was clear this would not last. The internet was growing fast. Organisations were getting allocated large blocks of addresses and wasting most of them. A company that needed 300 addresses would get a block of 65,536 because that was how allocation worked at the time, fixed class sizes, no flexibility.
Two things came out of this problem. First, CIDR - a smarter way to allocate and write address blocks that stopped the waste. Second, NAT - a way to let thousands of devices share a single public IP address. Both exist because 4.3 billion addresses were never going to be enough once the internet went mainstream.
IPv6 is the real long-term fix - 128-bit addresses, effectively unlimited. But IPv4 is still dominant in most infrastructure you will work with, and NAT is everywhere because of it.
Subnetting
A subnet is a smaller network carved out of a larger one. You take a block of IP addresses and divide it into chunks. Each chunk is a subnet.
Why would you do this? A few reasons. You want to isolate different parts of your infrastructure - your web servers should not be on the same network as your databases. You want to control traffic flow between groups of machines. You want to limit broadcast traffic, because broadcasts go to every device on a network and at scale that becomes noise. Subnetting gives you boundaries.
The Subnet Mask
The subnet mask is what tells you where the network part of an address ends and the host part begins.
Take 255.255.255.0. In binary:
11111111.11111111.11111111.00000000The 1s mark the network part. The 0s mark the host part. So for the address 192.168.1.10 with subnet mask 255.255.255.0 - the first three octets (192.168.1) are the network, and the last octet (.10) is the host.
Every device in this network shares the same 192.168.1 prefix. They are in the same subnet.
Reading the Mask
You do not always see 255.255.255.0 written out. More commonly you will see /24. That just means 24 bits are set to 1 in the mask which is exactly what 255.255.255.0 represents. Same thing, two different notations.
/24 gives you 8 bits for hosts. 2⁸ = 256 addresses. But two are reserved - the network address (first) and the broadcast address (last). So you get 254 usable host addresses.
/16 gives you 16 bits for hosts. 2¹⁶ = 65,536 addresses. Minus 2, you get 65,534 usable.
/30 gives you 2 bits for hosts. 4 addresses total, 2 usable. Common for point-to-point links between routers.
Calculating Your Range
Given 192.168.1.0/24, here is how you read it:
Network address: 192.168.1.0 - this identifies the subnet itself, not assigned to any device.
Broadcast address: 192.168.1.255 - packets sent here go to every device on the subnet.
Usable range: 192.168.1.1 to 192.168.1.254 - these are the addresses you assign to devices.
The formula is simple. Take the network address, add 1 for your first usable host. Take the broadcast address, subtract 1 for your last usable host.
Why Subnet
Isolation is the main reason. In AWS, your public subnets hold load balancers and bastion hosts - things that need internet access. Your private subnets hold application servers and databases - things that should not be directly reachable from outside. The subnet boundary, combined with route tables and security groups, is what enforces that separation.
Security is the second reason. Traffic between subnets can be inspected and filtered. Traffic within a subnet flows freely. Putting your database in a separate subnet means you can explicitly block everything except your application servers from reaching it.
Scale is the third. Broadcast traffic stays within a subnet. On a flat network with thousands of devices, broadcasts become a real problem. Subnetting contains that.
CIDR
Before CIDR, IP address allocation worked in fixed classes. Class A gave you 16 million addresses. Class B gave you 65,536. Class C gave you 256. That was it, no in-between. A company that needed 2,000 addresses had to take a Class B block of 65,536 and waste 63,000 of them. This burned through the IPv4 space fast.
CIDR - Classless Inter-Domain Routing - was introduced in 1993 to fix this. It dropped the fixed class system and let you define the network boundary anywhere in the 32 bits, not just at the 8, 16, or 24 bit mark. That /24 notation you see everywhere is CIDR notation. The number after the slash tells you how many bits are the network part. The rest are for hosts.
Reading CIDR Blocks
10.0.0.0/8 - 8 bits for network, 24 bits for hosts. 2²⁴ = 16,777,216 addresses.
10.0.0.0/16 - 16 bits for network, 16 bits for hosts. 2¹⁶ = 65,536 addresses.
10.0.0.0/24 - 24 bits for network, 8 bits for hosts. 2⁸ = 256 addresses, 254 usable.
10.0.0.0/32 - all 32 bits are network. Exactly one address. Used when you want to refer to a single specific host in a route or firewall rule.
The larger the prefix number, the smaller the block. /8 is huge. /32 is a single IP.
Splitting Blocks
This is where CIDR gets useful in practice. You get a block and you split it into smaller subnets. This is called subnetting a CIDR block.
Take 10.0.0.0/16. You want to split it into smaller /24 subnets. How many do you get? The difference is 24 - 16 = 8 bits. 2⁸ = 256 subnets, each with 254 usable hosts.
Your first subnet: 10.0.0.0/24 - hosts from 10.0.0.1 to 10.0.0.254
Your second subnet: 10.0.1.0/24 - hosts from 10.0.1.1 to 10.0.1.254
Your third subnet: 10.0.2.0/24 - and so on, up to 10.0.255.0/24
The third octet is incrementing because that is the bit range you carved out for subnets. This is the mechanical part of subnetting - you are just moving the boundary between network bits and host bits.
Going the other direction is called supernetting - combining smaller blocks into a larger one. Less common in day to day work but you will see it in routing tables where ISPs aggregate routes.
CIDR in Real Infrastructure
In AWS, when you create a VPC you pick a CIDR block - typically something like 10.0.0.0/16. That gives you 65,536 addresses to work with inside that VPC. You then carve it into subnets - /24 blocks for each availability zone, split further into public and private. Plan this wrong at the start and you will run out of IP space or end up with overlapping blocks that break VPC peering.
Kubernetes adds another layer. A cluster has three CIDR ranges you need to know. The node CIDR - IP addresses assigned to the actual EC2 or VM nodes. The pod CIDR, a separate range assigned to pods running on those nodes, each pod gets its own IP. The service CIDR, a virtual range used for Kubernetes services, these IPs never appear on the wire, they exist only inside the cluster's networking layer. All three must be non-overlapping, and none of them should overlap with your VPC CIDR if you want node-to-pod routing to work cleanly.
This is exactly why CIDR planning matters before you create anything. Changing a VPC CIDR after the fact is painful. Changing pod CIDRs on a running cluster is worse.
NAT
Every device on your home network has a private IP - something like 192.168.1.x. But when you open a website, the request goes out to the internet with a single public IP - the one your ISP assigned to your router. Your laptop's 192.168.1.5 never appears on the public internet. Something in the middle swapped it.
That something is NAT - Network Address Translation. It rewrites the source IP on outgoing packets and keeps a table to reverse that translation when the response comes back.
This exists for one reason. Private IP ranges 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 are not routable on the public internet. Every home, every office, every cloud VPC can reuse these ranges internally without conflict. NAT is what bridges that private space to the public internet.
How It Works
When a packet leaves your machine headed for the internet, it hits the NAT device - your router, your cloud NAT gateway, whatever sits at the boundary. The NAT device replaces the source IP in the packet header with its own public IP, then records the mapping in a translation table.
That table entry looks roughly like this:
Private IP:Port Public IP:Port Destination
192.168.1.5:52341 to 203.0.113.1:52341 to 142.250.80.46:443When the response comes back to 203.0.113.1:52341, the NAT device looks up that port in its table, rewrites the destination IP back to 192.168.1.5, and forwards the packet to your machine. Your laptop never knew any of this happened.
This specific type where port numbers are used to track individual connections is called PAT, Port Address Translation. Most people just call it NAT because it is what NAT almost always means in practice. One public IP, thousands of simultaneous private connections, each tracked by port.
NAT Types
Static NAT maps one private IP to one public IP, permanently. Useful when a server inside your network needs to be reachable from outside at a consistent address. One-to-one mapping, no port tricks.
Dynamic NAT pulls from a pool of public IPs and assigns them temporarily as devices make outbound connections. Less common today. You need enough public IPs in the pool to cover concurrent users, which defeats part of the purpose.
PAT - what your home router and AWS NAT gateway both use maps many private IPs to a single public IP using port numbers to track each session. This is why one household with ten devices needs only one public IP.
Source NAT and Destination NAT
Source NAT rewrites the source IP on outgoing packets. This is what your router does when your traffic leaves for the internet. The packet goes out with a different source than it started with.
Destination NAT rewrites the destination IP on incoming packets. This is what happens with port forwarding, a packet arrives at your public IP on port 8080, DNAT rewrites the destination to 192.168.1.20:8080 and sends it to the right internal machine. Load balancers use DNAT at the packet level for the same reason.
In practice: outbound traffic from private to public uses SNAT. Inbound traffic being directed to a specific internal server uses DNAT.
NAT in Cloud Infrastructure
In AWS, private subnets have no route to the internet by default. That is the point, your databases and application servers should not be directly reachable. But they still need to make outbound calls, to pull packages, talk to APIs, send logs.
That is what the NAT gateway is for. It sits in a public subnet, has a public IP, and handles outbound traffic on behalf of instances in private subnets. The private instance sends a packet, the NAT gateway rewrites the source IP to its own Elastic IP, the response comes back, and the NAT gateway forwards it to the right private instance.
The internet gateway is different. It allows two-way traffic - instances with public IPs can receive inbound connections through it. A NAT gateway only allows outbound-initiated traffic. Private instances behind a NAT gateway cannot receive unsolicited inbound connections. That distinction matters when you are debugging why something is unreachable.
How They Work Together
How They Connect
You have seen each piece separately. Now look at what actually happens when a packet moves from one place to another. This is where subnetting, CIDR, and NAT stop being three separate topics and become one system.
A Packet's Journey
You are on your laptop at 192.168.1.5. You open a terminal and run curl https://api.github.com. Here is what happens, step by step.
Your laptop knows its own IP and its subnet mask - say 192.168.1.0/24. The first thing it does is check whether the destination is on the same subnet. It takes the destination IP, applies the subnet mask, and compares the result to its own network address. api.github.com resolves to something like 140.82.121.6. That is not in 192.168.1.0/24. So your laptop knows this packet needs to go to the default gateway, your router.
The packet leaves your machine with source IP 192.168.1.5 and destination 140.82.121.6. It hits your router. The router has a routing table - a list of network prefixes and where to send traffic for each. It looks up 140.82.121.6, finds no specific match, falls back to the default route, and sends it upstream toward your ISP.
But before it goes out, NAT kicks in. Your router rewrites the source IP from 192.168.1.5 to your public IP - say 203.0.113.1 - and records the mapping with the source port. The packet now looks like it came from 203.0.113.1.
It travels across the internet, hits GitHub's servers. GitHub sees a request from 203.0.113.1. It sends the response back to 203.0.113.1. Your router receives it, looks up the port in its NAT table, rewrites the destination back to 192.168.1.5, and delivers it to your laptop.
Your laptop never knew it had a private IP from the internet's perspective. GitHub never knew your laptop existed. NAT handled the translation silently.
Where Each Piece Fits
Subnetting decided that 192.168.1.0/24 is your local network and anything outside that range needs to go through the gateway. Without that boundary, your laptop would not know when to route locally versus send to the gateway.
CIDR is how every network in that path is described - your home subnet, your ISP's block, GitHub's address space. Every routing table entry is a CIDR prefix. The router's job is to match the destination IP against the most specific prefix in its table and forward accordingly. This is called longest prefix matching - a packet destined for 10.0.1.5 matches both 10.0.0.0/8 and 10.0.1.0/24, but the router picks /24 because it is more specific.
NAT is what allows your private 192.168.1.x address to reach the public internet at all. Without it, your packet would leave your router with a source IP that is not routable on the internet. The response would have nowhere to go.
Where Routing Fits
Routing is the mechanism that actually moves packets between networks. Every device that forwards packets - your router, a cloud NAT gateway, an internet gateway has a routing table. Subnetting defines the network boundaries. CIDR describes them. Routing decides which boundary to cross and how.
In AWS, this is explicit. Each subnet has a route table attached to it. A private subnet's route table has a route for local VPC traffic and a route pointing 0.0.0.0/0 - all internet-bound traffic - at the NAT gateway. A public subnet's route table points 0.0.0.0/0 at the internet gateway instead. That single difference in the route table is what makes a subnet public or private. Not the name, not a flag, just where the default route points.
Thanks for supporting this newsletter. Y’all are the best!
Until next time!
Join 1,000+ engineers learning DevOps the hard way
Every week, I share:
How I'd approach problems differently (real projects, real mistakes)
Career moves that actually work (not LinkedIn motivational posts)
Technical deep-dives that change how you think about infrastructure
No fluff. No roadmaps. Just what works when you're building real systems.

👋 Find me on Twitter | Linkedin | Connect 1:1
Thank you for supporting this newsletter.
Y’all are the best.
