NAT (Network Address Translation)
NAT lets devices with private IPs talk to the public Internet by rewriting addresses (and ports) at the boundary. It exists because IPv4 ran out of addresses around 2011 and we needed a way to share one public IP across many devices.
Your home router does NAT. Cloud NAT gateways do NAT. Docker does NAT. Kubernetes services often do NAT. It’s everywhere.
The basic flow
Laptop 192.168.1.42:54000 ──▶ Home router
NAT table:
192.168.1.42:54000 ↔ 203.0.113.5:62000
──▶ Internet ──▶ example.com:443
Response to 203.0.113.5:62000 ──▶ Home router
lookup table → 192.168.1.42:54000
──▶ Laptop
The router maintains a translation table. Inbound packets only get forwarded if there’s a matching outbound entry — which is why your laptop is unreachable from the Internet by default. (This accidental firewall behavior is one reason home networks aren’t constantly compromised.)
Three flavors
| Type | What it rewrites | Use case |
|---|---|---|
| SNAT (Source NAT) | source IP/port on outbound packets | “let private subnet reach the Internet” — AWS NAT Gateway, home router |
| DNAT (Destination NAT) | destination IP/port on inbound packets | “expose this server” — port forwarding, load balancer VIPs |
| PAT / NAPT (Port Address Translation) | source IP and port | “many devices share one public IP” — what your home router actually does |
In casual usage “NAT” usually means PAT — the many-to-one variant.
iptables syntax (Linux), to make this concrete:
# SNAT — rewrite source to a specific public IP
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to 203.0.113.5
# MASQUERADE — like SNAT but uses whatever the egress interface IP currently is
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
# DNAT — port forward inbound 80 to internal server
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 10.0.0.50:8080
Why NAT exists at all
- IPv4 exhaustion. ~4.3 billion addresses, way more devices.
- Accidental security. Inbound packets without a state entry get dropped.
- Network independence. Renumber the inside without telling the outside.
IPv6 was supposed to kill NAT (enough addresses for everything). It hasn’t — partly because operators got used to NAT’s isolation properties.
Cloud NAT — AWS NAT Gateway
In a VPC (09_vpc_cloud_networking.md), private subnets can’t reach the Internet directly because they don’t have public IPs. The NAT Gateway sits in a public subnet and SNATs outbound traffic from private subnets:
Private subnet 10.0.10.0/24
↓ (default route 0.0.0.0/0 → NAT Gateway)
NAT Gateway in public subnet (has Elastic IP 203.0.113.5)
↓
Internet Gateway
↓
Internet
Practical notes:
- NAT Gateway is per-AZ (deploy one in each AZ for HA, otherwise an AZ failure isolates that AZ’s private subnet).
- It’s not free — ~$0.045/hour + $0.045/GB processed. Big egress = big bill. VPC endpoints for S3 / DynamoDB sidestep NAT GW entirely.
- It’s stateful: outbound creates a state entry, returning packets are allowed back; nothing else gets in.
NAT and connection limits
Each NAT translation entry consumes a port on the public IP side. One public IP × 65k ephemeral ports = ~65k concurrent outbound connections per (dest_IP, dest_port) pair. AWS NAT Gateway limit: ~55k connections per destination per minute. If your service makes many connections to the same destination (e.g. an S3 bucket via public endpoint), you can hit this and see weird intermittent timeouts.
Fix: use a VPC endpoint (no NAT involved), or multiple NAT gateways, or reuse connections (HTTP keep-alive).
NAT and protocols that embed IPs in the payload
NAT only rewrites L3 (IP) and L4 (port) headers. Protocols that put IPs in their payload (FTP active mode, SIP, some game protocols) break under NAT unless there’s an “ALG” (Application Layer Gateway) that knows how to rewrite the payload too.
For modern HTTP/gRPC apps, NAT is invisible. For legacy SIP/FTP setups it’s misery.
NAT vs proxy
Both let internal hosts reach the outside via an intermediary. The difference:
| NAT | Proxy | |
|---|---|---|
| Layer | L3/L4 | L7 (usually) |
| Sees the payload? | no, just packet headers | yes, application content |
| Client config | none (transparent) | client must know proxy address |
| Can cache / inspect / authenticate? | no | yes |
A reverse proxy (nginx in front of your Django app) is doing what looks like DNAT but at L7. See 11_proxies_forward_reverse.md.
Docker NAT
Docker’s default bridge network creates docker0 (a virtual L2 bridge), assigns containers IPs in 172.17.0.0/16, and uses iptables MASQUERADE to NAT outbound traffic. Container-to-container on the same bridge is direct (no NAT). Container-to-Internet goes through the host as a NAT. See ../16_docker/07_networks_bridge_vs_nat_vs_host.md.
Common interview confusions
- “NAT is a firewall.” — it’s an address translator. The firewall behavior is a side effect of state tracking, not the goal.
- “Static NAT and DNAT are different.” — same thing under different names. “Static NAT” usually means a fixed 1:1 mapping (one public IP ↔ one private IP), often used for “expose this internal server.”
- “NAT breaks end-to-end.” — true and intentional. The original IP architecture assumed every host was directly addressable; NAT broke that assumption, which is why VPN/peer-to-peer/VoIP needed NAT-traversal hacks (STUN, TURN, ICE).
Interview angle
- “Why does NAT exist?” — IPv4 address exhaustion; lets many private hosts share one public IP. Side effect: incoming-by-default firewall behavior.
- “SNAT vs DNAT vs PAT?” — SNAT rewrites source (outbound), DNAT rewrites destination (inbound port-forward), PAT/NAPT rewrites source IP + port (the “many-to-one” type your home router does).
- “How does AWS NAT Gateway work, and why is it per-AZ?” — sits in a public subnet, SNATs outbound traffic from private subnets via its Elastic IP. Per-AZ because cross-AZ traffic costs money and an AZ failure shouldn’t take down all egress.
- “Why might your service intermittently fail to reach S3 through a NAT?” — port exhaustion / per-destination connection limit on the NAT Gateway. Fix with VPC endpoints or connection reuse.
- “Does NAT work for IPv6?” — IPv6 was designed to not need it; addresses are abundant. NAT66 exists but is uncommon.