Double-NAT and How to Escape It

Two routers in series, or an ISP that never gave you a real address — how to spot double-NAT and get out from under it

Contents

You forwarded the port. You checked it three times. The service works perfectly from inside the house and is stone dead from the outside, and you’re starting to doubt your own competence. Before you rewrite the firewall rule for the fourth time, check one thing: how many times your traffic gets NATed on the way out. Because if the answer is “twice”, the port forward you configured on your router never had a chance — the packet gets translated again upstream by a device you don’t control, and your forward is pointing at the wrong layer of the onion. This is double-NAT, and it’s one of the most common reasons a home self-hoster’s inbound access mysteriously refuses to work.

What double-NAT is and why it hurts

Advertisement

Network address translation is what lets a whole household of devices share one public IP. Your router rewrites the private source addresses of outgoing packets to its single public address, remembers the mapping, and rewrites the replies back on the way in. One layer of this is normal and invisible. The trouble starts when there are two layers in series.

That happens in two everyday ways. Either you’ve plugged your own router into the LAN port of the ISP’s router — very common, because people want their own kit but leave the ISP box running — so packets get NATed by your router and then again by the ISP’s. Or your ISP has put you behind carrier-grade NAT (CGNAT), where the “public” address on your router’s WAN interface is itself a private-range address shared among many customers, and the real translation to a genuine public IP happens deep in the ISP’s network on hardware you’ll never touch.

Either way, the consequence is the same and it’s specific. A port forward only works on the outermost NAT — the one holding the real public IP. When you configure a forward on your inner router, inbound traffic arrives at the outer device first, which has no forwarding rule for it and drops it on the floor. UPnP, which normally lets applications punch their own forwards, only talks to the nearest router and can’t reach through the second layer either. Outbound traffic and normal browsing are unaffected, which is exactly why double-NAT is so confusing: everything works except the one thing you’re trying to do, and there’s no error message anywhere.

Port forwarding is the headline casualty, and there are quieter ones. Games and voice apps report a “strict” or “moderate” NAT type and struggle to connect players directly, because they rely on the same inbound reachability. Some VPN protocols that expect a stable public endpoint get flaky. Running your own mail or any service that peers expect to initiate a connection to becomes impractical. Mesh overlays that punch through NAT — Tailscale, WireGuard-based tools, the Nebula overlay — usually survive double-NAT because both ends dial outward and meet in the middle, though two strict/symmetric NATs at once can defeat the hole-punch and force a relay. The pattern to notice is that anything depending on the outside world reaching in is what breaks, while anything your side reaches out to keeps working.

CGNAT deserves its own note because it’s the harder case. With two routers you own, you can fix the topology. With CGNAT you don’t control the outer NAT at all — it belongs to the ISP, is shared with strangers, and no configuration on your side can create a forward through it. That constraint shapes every escape route below.

Diagnosing it in two minutes

You need two numbers: the address on your router’s WAN interface, and your actual public address as the internet sees it. If they differ, and especially if the WAN address is in a private or CGNAT range, you’ve found your culprit.

1
2
3
4
5
6
7
8
9
# 1) What does the outside world think my address is?
curl -s https://api.ipify.org ; echo
# -> e.g. 203.0.113.45  (a real, routable public IP)

# 2) What address is on my router's WAN interface?
#    (read it from the router's status page, or if a Linux box
#     is your router, check the WAN NIC directly)
ip -4 addr show dev eth0 | awk '/inet /{print $2}'
# -> e.g. 100.72.14.9/22   (uh-oh)

Now compare against the reserved ranges. If your WAN address falls in any of these, it isn’t a real public address and something upstream is NATing you again:

RangeMeaning
10.0.0.0/8Private (RFC 1918) — a router in front of you
172.16.0.0/12Private (RFC 1918) — a router in front of you
192.168.0.0/16Private (RFC 1918) — a router in front of you
100.64.0.0/10Carrier-grade NAT (RFC 6598) — your ISP

That 100.72.14.9 in the example sits inside 100.64.0.0/10, so this connection is behind CGNAT. If instead your WAN showed 192.168.x.x, you’d be looking at a router-behind-a-router you can rearrange yourself. And if the WAN address exactly matches what ipify reported, congratulations — you have a real public IP and your inbound problem is a plain firewall or forwarding mistake and has nothing to do with double-NAT.

Escaping it

Advertisement

The route out depends on which flavour you have.

Two routers you own — collapse to one NAT. The cleanest fix is to stop the inner device from NATing. Put your own router in bridge mode (or, on the ISP box, enable bridge / IP-passthrough / modem mode) so only one device performs NAT and holds the public IP. Which one you bridge depends on whose features you want — usually you bridge the ISP box and let your own router do the routing, firewalling and Wi-Fi, so your kit holds the real public address and your port forwards finally land. If the ISP box can’t be bridged, the fallback is to put your router’s WAN IP in the ISP box’s DMZ, which forwards all unsolicited inbound to your router — cruder, and it means your router is the only thing protecting you, but it defeats the double-NAT for inbound.

Just want the second router to stop translating. If you don’t need a routed boundary between the two, set the inner router to access-point mode — it becomes a dumb switch-plus-Wi-Fi and everything sits on one flat network with a single NAT. You lose the ability to firewall between the two segments, so it’s the right move only when you didn’t want that boundary anyway.

CGNAT — you can’t forward, so route around it. Since no forward can pass the ISP’s NAT, escape means either getting a real address or not needing inbound forwards at all:

  • Ask the ISP for a public IP. Many will move you off CGNAT on request, sometimes free, sometimes for a small monthly fee or a static-IP add-on. This is the simplest fix when it’s offered — always ask first.
  • Use IPv6. CGNAT is a scarcity hack for IPv4. If your ISP provides IPv6 — increasingly common — your devices get real, globally routable v6 addresses with no NAT in the path at all. You firewall them properly (a routable address is reachable by anyone, so default-deny inbound and open only what you mean to), and inbound over v6 works even while v4 is trapped behind CGNAT.
  • Terminate elsewhere with an overlay or tunnel. Rent a small VPS with a public IP and bring your services to it over an outbound connection your router is happy to make. A mesh overlay is the tidy version of this — put the reachable endpoint on the VPS and let your home host dial out to join. I’ve written up exactly this pattern in Nebula as a self-owned mesh overlay, where a VPS lighthouse sidesteps CGNAT entirely because your home host only ever makes outbound connections.

Troubleshooting the aftermath

Bridged the ISP box and now nothing has internet. Bridge mode usually means the ISP box stops handing out DHCP and expects your router to authenticate the line (PPPoE) or simply pick up the public IP via DHCP on its WAN. Check whether your connection type needs PPPoE credentials from the ISP entered on your router now, and that your router’s WAN is set to the right mode.

DMZ set but inbound still fails. Confirm the DMZ points at your router’s current WAN IP, which may be dynamic and may have changed. Pin your router’s WAN to a DHCP reservation on the ISP box so the DMZ target stays valid.

Inbound works over IPv6 but half the internet can’t reach it. Plenty of clients are still IPv4-only, so a v6-only service is invisible to them. Treat v6 inbound as a supplement while you’re stuck on v4 CGNAT, and expose anything that must be universally reachable through a v4 path such as a VPS or tunnel.

Everything’s fixed but internal name resolution went weird. Rearranging routers changes which device answers DNS and hands out leases. If indoor access to your services now behaves oddly, it’s worth revisiting split-horizon DNS so internal names still resolve to LAN addresses after the topology change.

Segmentation disappeared after going to AP mode. Access-point mode flattens the network deliberately. If you relied on the inner router to isolate untrusted devices, you’ll want to rebuild that with proper VLAN segmentation on the remaining router rather than depending on a second NAT for separation.

The verdict

If you self-host and want anything reachable from outside, double-NAT is worth understanding before it costs you an evening. The two-router variety is a five-minute fix once you spot it: bridge one device, collapse to a single NAT, and your port forwards start working. Do the two-minute diagnosis before you touch anything, because there’s no point rearranging routers if the real problem is CGNAT.

CGNAT is the genuinely limiting case, and honesty demands admitting there’s no clever config that conjures a forward through an ISP’s shared NAT. Ask for a public IP first, lean on IPv6 where you have it, and reach for a VPS-terminated overlay when neither is on offer. None of those is as tidy as a single public IPv4 address, but any of them gets your services reachable — and once you know which situation you’re actually in, you stop wasting time on fixes that were never going to work.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.