System designCore9 min
Private networks: NAT, VPCs & firewalls
Most machines in a system have addresses nobody on the internet can reach, and that is on purpose. Private address ranges, NAT, virtual private clouds, subnets and firewall rules decide which machines face the world, which talk only to each other, and how anything gets out.
1 · The idea
Most machines have an address the internet cannot reach
A bookkeeping service for small businesses runs a load balancer, a dozen app servers and a PostgreSQL database holding every customer's accounts. Only one of those needs to be reachable from the internet: the load balancer. The database, especially, should be impossible to even try to connect to from outside.
The tool is private addresses: ranges reserved for internal networks, which internet routers are expected to filter out. Traffic addressed to them never crosses the public internet. Three ranges were reserved in 1996 and are still used everywhere, from home Wi-Fi to cloud networks:
Range | Written as | Addresses |
|---|---|---|
10.0.0.0 – 10.255.255.255 | 10.0.0.0/8 | About 16.8 million |
172.16.0.0 – 172.31.255.255 | 172.16.0.0/12 | About 1 million |
192.168.0.0 – 192.168.255.255 | 192.168.0.0/16 | 65,536 |
Private addresses were also an answer to scarcity: IPv4 has only about 4.3 billion addresses in total, far fewer than the devices that want one. Any number of private networks can reuse the same ranges, as long as something translates at the edge.
2 · NAT
NAT lets many private machines share one public address
When an app server at 10.0.2.15 calls the bank's API to import a customer's transactions, the bank must be able to reply. NAT (network address translation) rewrites the outgoing packet's source to a public address and a port it picks, remembers the mapping, and translates the reply back:
Replies match a mapping and are let in. A connection that nobody inside started has no mapping, so it goes nowhere.
Three consequences matter in design:
Consequence | Why it matters |
|---|---|
Inbound is blocked by default | A side effect, not a security policy: it shouldn't be the only thing between the database and the internet |
Ports are finite | AWS's NAT gateway allows 55,000 simultaneous connections per public address to each unique destination; more addresses raise the limit |
It can fail | It lives in one zone; if that zone fails, every zone using it loses outbound access. Use one per zone |
NAT is also why peer-to-peer calls are hard (WebRTC & peer-to-peer) and why servers that must accept connections need a public address or a load balancer in front. With IPv6 there are enough addresses for every device, and clouds offer an egress-only gateway that allows outbound connections without NAT while still refusing unsolicited inbound ones.
3 · VPCs
A VPC is your own private network inside someone else's data center
In the cloud, the bookkeeping service gets a virtual private cloud (VPC): a network logically isolated from every other customer's, with an address range it chooses, such as 10.0.0.0/16 (65,536 addresses). Inside it:
- Subnets are smaller ranges, such as
10.0.1.0/24(256 addresses). In AWS each subnet lives in one availability zone; in Google Cloud the VPC is global and subnets are regional. - Route tables decide where traffic for each destination range goes: stay inside the VPC, go to the internet gateway, go to a NAT gateway, or go to a connected network.
- An internet gateway connects the VPC to the internet for the subnets whose routes point to it.
Whether a subnet is public or private is decided by one route. A public subnet has a route for all internet traffic (0.0.0.0/0) to the internet gateway, and its machines can have public addresses. A private subnet has no such route; its machines can reach the internet only through a NAT gateway sitting in a public subnet, and nothing on the internet can start a connection to them.
Route table of | Traffic for | Goes to |
|---|---|---|
Public subnet | 10.0.0.0/16, inside the VPC | Stays local |
Public subnet | 0.0.0.0/0, anywhere else | The internet gateway |
Private subnet | 10.0.0.0/16, inside the VPC | Stays local |
Private subnet | 0.0.0.0/0, anywhere else | The NAT gateway, outbound only |
4 · Layout
Public subnets face the internet; private subnets only face each other
The bookkeeping service splits its tiers by subnet, repeated in each availability zone for redundancy (Redundancy & failure domains):
Only the load balancer and the NAT gateway have public addresses. App servers can call out through NAT but can't be called from outside; the database can't reach the internet at all.
Each tier can only be reached from the one in front of it. An attacker who finds a bug in the load balancer's configuration still can't connect to the database directly, because there is no route from the internet to its subnet and no rule that would admit them. That layering is defense in depth: several independent barriers, any one of which might fail on its own.
5 · Firewall rules
A firewall rule says who may talk to whom, on which port
Routes decide where traffic can go; firewall rules decide whether it is allowed. Clouds provide two kinds, and AWS's are typical:
Aspect | Security group | Network ACL |
|---|---|---|
Applies to | Each instance (network interface) | A whole subnet |
Rules | Allow only; everything else is denied | Allow and deny, checked in numbered order |
Replies | Allowed automatically (stateful) | Must be allowed explicitly (stateless) |
Best used as | The main control, rule by rule | A coarse guard rail, such as blocking a range |
Security groups can name other security groups instead of addresses, which matters when addresses change with every deploy (Service discovery & registration). The bookkeeping service's rules read like the architecture itself:
Group | Allows in | From |
|---|---|---|
Load balancer | TCP 443 | Anywhere |
App servers | TCP 8080 | The load balancer group only |
Database | TCP 5432 | The app server group only |
Keep rules as narrow as the architecture allows: specific ports, specific source groups, no "allow all from 0.0.0.0/0" on anything but the front door. Google Cloud's firewall works the same way: stateful, with ingress denied unless a rule allows it and egress allowed by default.
6 · In and out
A forward proxy speaks for clients; a reverse proxy speaks for servers
Two kinds of middleman sit at the edges of a private network, facing opposite directions:
A reverse proxy accepts requests for your servers (Reverse proxies & API gateways). A forward proxy makes requests on behalf of your servers, so outbound traffic can be checked against an allow-list and logged.
Controlling egress is easy to forget and valuable: it limits where stolen data can be sent and stops a server from being tricked into calling internal addresses (Webhooks covers this for user-supplied URLs). Cloud services can be reached without the internet at all: private endpoints, such as AWS PrivateLink, make a cloud service appear at a private address inside the VPC, so traffic to object storage or a queue never needs the NAT gateway.
Private networks also connect to each other. VPC peering joins two VPCs; a transit gateway joins many; a site-to-site VPN or a dedicated line connects a VPC to an office or data center. Each connection is another path an attacker could use, so give it the same narrow rules as anything else.
7 · In practice
Put only the front door in public, and everything else behind it
Administrators still need to reach private servers. The old answer is a bastion host, one hardened machine in a public subnet that admins log in to first; managed tools such as AWS Systems Manager Session Manager open sessions through the provider's own service, with no inbound port, bastion or SSH key to manage, and log every session. Either way, admin access should be logged, short-lived and tied to a person (Network segmentation & zero trust goes further).
- Plan the address ranges
Choose VPC ranges that won't overlap with offices or other VPCs you may connect later; renumbering a live network is painful.
- Public only at the edge
Load balancers and NAT gateways in public subnets; app servers and data stores in private ones.
- Narrow rules
Security groups that reference each other, specific ports, nothing open to the world but the front door.
- Control the way out
NAT per availability zone, private endpoints for cloud services, and a forward proxy where outbound calls must be restricted.
- Watch it
Flow logs of what connects to what, and alerts on rules that open anything to 0.0.0.0/0.
Check yourself
4 questions
Takeaways
Remember this
- Private address ranges are filtered from the internet, so machines on them can only be reached from inside or through a translator.
- NAT lets private machines make outbound connections and drops unsolicited inbound ones; it has port and availability limits of its own.
- A VPC divides into subnets whose route tables make them public or private; only the front door belongs in a public subnet.
- Stateful security groups that reference each other express "who may talk to whom on which port"; stateless network ACLs add coarse guard rails.
- Control the way out as well as the way in: NAT per zone, private endpoints for cloud services, and a forward proxy for restricted egress.