
NAT: Private IP to Public IP
How whole family surfs with one Public IP. The magic of Network Address Translation concealing Private IPs.

How whole family surfs with one Public IP. The magic of Network Address Translation concealing Private IPs.
Why does my server crash? OS's desperate struggle to manage limited memory. War against Fragmentation.

Two ways to escape a maze. Spread out wide (BFS) or dig deep (DFS)? Who finds the shortest path?

Fast by name. Partitioning around a Pivot. Why is it the standard library choice despite O(N²) worst case?

Establishing TCP connection is expensive. Reuse it for multiple requests.

While running a startup, I spun up AWS EC2 instances and suddenly wondered: we have 10 laptops and 15 phones all sharing the same router, but how are IP addresses managed? From the outside, our company only has one IP address. So when a packet arrives, how does the router know "oh, this goes to Kim's laptop"?
What was even stranger: when I ran ifconfig on my MacBook at the office, I saw 192.168.0.15. When I went home and ran it again, same thing—192.168.0.15. Isn't IP address duplication a disaster? So why is the world still functioning?
This question led me to NAT (Network Address Translation). That was it. The core job of a router is "address translation."
At first, I thought "doesn't the router just forward packets like a switch?" But switches work at L2 (data link layer) using MAC addresses, while routers work at L3 (network layer) messing with IP addresses. Completely different levels.
My next confusion: "Does the router assign different public IPs to each internal device?" Nope. The ISP gives our home exactly one public IP. So how do we share it?
That's when the insight hit: "Ah, the router uses port numbers to distinguish connections!" Even with the same IP address, different port numbers mean different connections. The router creates a mapping table using port numbers like "this port is Kim's laptop", "that port is Lee's phone."
The apartment building analogy completely clicked.
Apartment Building = Public IP Each Unit Number = Private IP + Port NumberWhen mail arrives at "123 Teheran-ro, Gangnam-gu, Seoul," that's the address for the whole building. But the mail has "Unit 305" as the detailed address. The front desk (router) sees this and delivers to Unit 305.
From outside, the entire apartment appears as one address "123 Teheran-ro," but inside there are hundreds of units from 101 to 1505. That's the essence of NAT.
IPv4 addresses are 32-bit. 2^32 = about 4.3 billion. Sounds like a lot, but with 8 billion people globally, and each person having a smartphone, laptop, tablet, smartwatch, and IoT fridge, it's nowhere near enough.
In the mid-1990s, warnings came: "At this rate, we'll run out of IP addresses within 10 years." Two solutions emerged:
IPv6 is the right answer, but changing global infrastructure takes forever. So NAT appeared as a temporary fix and has been in production for 30 years. NAT ended up being an "IPv4 lifespan extension patch."
IANA (Internet Assigned Numbers Authority) designated three private IP ranges:
10.0.0.0 ~ 10.255.255.255 (10.0.0.0/8) - Class A, for large enterprises
172.16.0.0 ~ 172.31.255.255 (172.16.0.0/12) - Class B, for SMBs
192.168.0.0 ~ 192.168.255.255 (192.168.0.0/16) - Class C, for homes
These addresses can be freely used by anyone globally, under the premise they "don't go directly onto the internet." My home router uses 192.168.0.1, the neighbor's uses 192.168.0.1 too. But each router has a different public IP, so no collision.
I understood it this way: Private IP is a "home nickname," public IP is the "address on your ID card." Whether you call dad "honey" at home, or the neighbor calls their husband "honey" doesn't matter. But tax notices come to the ID card address.
Maps one private IP to one fixed public IP. Mainly used for servers like web servers that "must be accessible from outside."
192.168.0.10 (web server) <-> 211.45.123.100 (fixed public IP)
AWS Elastic IP works this way. Attach a fixed public IP to an EC2 instance so the IP doesn't change on reboot.
Create a pool of public IPs and assign one whenever needed. If you have 100 internal devices but only 10 public IPs, only 10 can communicate externally at once.
Pool: 211.45.123.100 ~ 211.45.123.110 (11 total)
100 internal devices compete for them
Rarely used nowadays. It was a temporary method when IPs were scarce.
This is the real core. The method your home router and office router use. One public IP is sliced by port numbers for multiple devices to share.
Private IP:Port Public IP:Port
192.168.0.10:54321 <-> 211.45.123.100:10001
192.168.0.15:49152 <-> 211.45.123.100:10002
192.168.0.20:33000 <-> 211.45.123.100:10003
One public IP (211.45.123.100) handles tens of thousands of connections by changing ports. Theoretically, ports range 0-65535, so one public IP can handle 60,000 simultaneous connections.
I accepted this with the "telephone operator analogy." Old companies had one main number (02-1234-5678), and the operator asked "which department?" and connected via extension numbers (ports). NAT does the exact same thing.
Routers keep a NAT table (mapping table) in memory. When you enable NAT on a Linux server, the kernel manages this table.
# Check NAT table on Linux
sudo iptables -t nat -L -v -n
Example table:
| Internal IP:Port | External IP:Port | Destination IP | State | Timeout |
|---|---|---|---|---|
| 192.168.0.10:54321 | 211.45.123.100:10001 | 8.8.8.8:80 | Active | 120s |
| 192.168.0.15:49152 | 211.45.123.100:10002 | 142.250.1.1:443 | Active | 120s |
| 192.168.0.20:33000 | 211.45.123.100:10003 | 13.124.199.1:443 | Closing | 10s |
My laptop (192.168.0.10:54321) -> Router
"I'm sending an HTTP request to Google (8.8.8.8:80)"
Router:
192.168.0.10:54321211.45.123.100:10001 (auto-assign available port)211.45.123.100:10001Google (8.8.8.8:80) -> Router
"This is a response to the request sent to 211.45.123.100:10001"
Router:
10001192.168.0.10:54321192.168.0.10:54321That was it. The router actively rewrites the IP address and port number in packets in real time. Like using correction fluid to erase and rewrite the "recipient" address on an envelope.
To use a Linux server like a router, configure NAT with iptables.
# Enable IP forwarding (allow packet forwarding)
sudo sysctl -w net.ipv4.ip_forward=1
# Add NAT rule (SNAT: Source NAT)
# eth0 is the interface with public IP, eth1 is the private network interface
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Verify
sudo iptables -t nat -L -v -n
MASQUERADE means "my public IP might change dynamically, so automatically translate to the current interface IP." Used in environments where ISP assigns IP via DHCP, like home routers.
If your public IP is static:
sudo iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 211.45.123.100
Say you have a web server at the office (192.168.0.50:8080) and want external access via 211.45.123.100:80 to reach the internal server.
# DNAT (Destination NAT): Translate destination address
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.0.50:8080
# Also translate response packets (SNAT)
sudo iptables -t nat -A POSTROUTING -j MASQUERADE
This is "port forwarding." Adding a rule in router settings like "external port 80 -> internal 192.168.0.50:8080" works on this principle.
Docker works the same way. docker run -p 8080:80 NATs packets arriving at host port 8080 to container's internal port 80.
NAT perfectly handles "requests going from internal to external," but "requests coming from external to internal" are blocked by default. Without mapping info in the NAT table, the router doesn't know "who should receive this packet?"
This becomes a problem in:
If the router supports UPnP, internal devices can request "please automatically add a port forwarding rule for me."
# Python miniupnpc library example
import miniupnpc
u = miniupnpc.UPnP()
u.discover()
u.selectigd()
# Add mapping: external port 12345 -> internal port 12345
u.addportmapping(12345, 'TCP', u.lanaddr, 12345, 'My Game', '')
print(f"External IP: {u.externalipaddress()}")
But UPnP is a huge security hole. Malware can open ports via UPnP, so nowadays it's recommended to disable it.
Ask a STUN server "what's my current public IP:Port?" The STUN server responds "you're 211.45.123.100:10001," then you send that info to the other party for P2P connection.
WebRTC uses this method. Video conferencing services like Zoom use STUN for initial connection.
// WebRTC STUN configuration example
const configuration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
};
const peerConnection = new RTCPeerConnection(configuration);
In extreme NAT environments (Symmetric NAT) where STUN fails, relay through a TURN server. Not P2P but via server, so slower but reliable.
Try STUN, TURN, direct connection, everything, and automatically pick the fastest route. Core WebRTC technology.
I summarize it this way: NAT Traversal = "punching holes through the NAT wall." UPnP is the front door key, STUN is finding the back door, TURN is climbing over the fence.
In IPv6, every device gets a unique public IP. No private IPs needed. No NAT needed.
# IPv6 address example
2001:0db8:85a3:0000:0000:8a2e:0370:7334
IPv6 addresses are 128-bit, so even if you assigned an IP to every grain of sand on Earth, there'd be leftovers. The concept of "IP shortage" itself disappears.
But reality? As of 2025, 60% of global traffic is still IPv4. Over half the internet still depends on NAT. Why?
NAT started as a "temporary fix" but worked so well it became a permanent solution. This is a textbook case of technical debt.
Docker containers also use NAT. The host server acts as the "router," and containers receive private IPs (172.17.0.0/16).
# Check container internal IP
docker run -it --rm alpine ip addr show
# Example output:
# eth0: 172.17.0.2/16
# Check Docker NAT rules on host
sudo iptables -t nat -L -n | grep DOCKER
Docker creates a virtual bridge called docker0, applies NAT to it, and lets containers communicate externally. The -p 8080:80 option is "port forward host 8080 to container 80."
Kubernetes is similar. Each Pod gets a private IP, and NodePort services use NAT to forward external traffic to Pods.
I opened the office router settings and found a "port forwarding" menu. I added a rule myself: external port 22 → my MacBook 192.168.0.15:22 for SSH access. I SSH'd into my office MacBook from home. Now I viscerally understood what NAT does. That was it. The router isn't just a signal relay; it's an address translator actively rewriting packets.