Inside users cannot reach an internal server by its public address, but internet users can. Why, and how do you fix it?
Show the answer
Say this first
That is NAT hairpinning, also called NAT loopback or reflection. The user's packet to 203.0.113.5 enters R1 on an inside interface, and IOS only translates a global destination back to the local one for packets that arrive on an outside interface, so nothing rewrites it. Even on devices that do rewrite it, a server on the same subnet as the user replies straight to the user from its private address, and the user drops that reply. The clean fix is split DNS. If you must hairpin, the device has to translate both destination and source.
Go deeper
Why it fails
- PC1 (192.168.10.10) resolves app.example.com to 203.0.113.5 and sends a SYN to it.
- The SYN enters R1 on
Gi0/0/1, an inside interface. Outside-to-inside translation only applies to packets arriving on an outside interface, so the destination stays 203.0.113.5 and the packet never reaches SRV1 at 192.168.20.10.
The same-subnet trap
Suppose a device does rewrite the destination (Linux DNAT applies on any interface). If the client sits on the server's own subnet, the server replies directly from 192.168.20.10. The client sent its SYN to 203.0.113.5, so it discards the reply. The device has to rewrite the source as well, so the reply comes back through it.
Fixes, best first
- Split DNS: the internal view of app.example.com returns 192.168.20.10. No hairpin at all.
- A DMZ on its own interface: clients and servers on different interfaces, so replies always return through the edge device.
- Hairpin NAT on the edge device. On Linux:
iptables -t nat -A PREROUTING -d 203.0.113.5 -p tcp --dport 443 -j DNAT --to-destination 192.168.20.10
iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -d 192.168.20.10 -p tcp --dport 443 -j MASQUERADEThe first rule has no -i, so it applies to inside traffic too. The second source-NATs clients on
the server's own subnet so their replies return through the router.
On classic IOS the NAT Virtual Interface (ip nat enable on interfaces, ip nat source ... rules
without inside or outside) supports hairpinning, but NVI is not supported on IOS-XE.
They will ask next
Why is split DNS better than hairpin NAT?
Traffic stays local instead of going through the edge device, the server logs the real client address, and nothing depends on a NAT feature some platforms lack.
After hairpin NAT is enabled, the server logs show every internal user as the router. Why?
The source translation that makes hairpinning work hides the real client address. That is expected, and one more reason to prefer split DNS.
Traps
- Testing a new port forward from inside the LAN and declaring it broken.