CGNAT Explained: Why You Can’t Reach Your Home Server From the Internet
Devin Harper
September 27, 2026
The week I moved into my current apartment, I spent two evenings convinced I’d broken my own server. Same mini PC, same Docker stack, same reverse proxy config I’d been running for three years at the old place. New fiber provider, cheaper plan, faster speeds. I recreated the port forward for 443 on the new router, pointed my DNS at the new public IP, and opened the site from my phone on mobile data.
Timeout.
I did everything you do. Checked the forward. Rebooted the router. Disabled the server’s firewall. Tried a different port. Ran a port checker website, which cheerfully told me 443 was “closed.” I started suspecting the new router’s firmware. At about 11 p.m. on the second night I finally opened the router’s status page and looked at the WAN address it had been given.
It started with 100.72. The IP address that the port-check websites saw started with 81. Those two numbers are supposed to be the same. They weren’t, because my shiny new ISP had put me behind carrier-grade NAT, and no amount of port forwarding on my router was ever going to work.
If you’ve landed here after your own two evenings, this is what’s going on, how to confirm it in five minutes, and what your real options are.
What CGNAT actually is
You already live with one layer of NAT. Your router takes one public IPv4 address from your ISP and shares it among every phone, laptop, and TV in your house, each of which gets a private address like 192.168.1.23. When your laptop opens a web page, the router rewrites the packet so it looks like it came from the public address, remembers the mapping, and sends the reply back to the right device.
Inbound connections are the problem NAT creates. When a packet arrives from the internet addressed to your public IP on port 443, the router has no idea which of your devices should get it. A port forward is you telling it: “anything on 443 goes to the server at .50.” That’s the only reason self-hosting from home works at all.
Carrier-grade NAT, or CGNAT, is the same trick done one level up, by your ISP. The world ran out of fresh IPv4 addresses years ago. ISPs signing up new customers can’t give each one a public address anymore, so they put a big NAT box in their network and share one public address among dozens or hundreds of customers. Your router gets an address from a special shared range, usually 100.64.0.0 to 100.127.255.255, and the ISP’s equipment translates that to a real public address on the way out.
Outbound, you’ll never notice. Streaming, browsing, video calls: all fine, because every one of those is a connection you started. Inbound is where it falls apart. A packet arriving at the shared public address has to get through the ISP’s NAT first, and the ISP has no forward for you. Your router never even sees the packet. That’s why port checkers say “closed” no matter what you configure at home: the door you’re opening is behind a second door you don’t have a key to.

How to tell if you’re behind CGNAT
This takes five minutes and saves you two evenings.
- Find your router’s WAN address. Log into the router’s admin page and look for “Internet,” “WAN,” or “Status.” Write down the IPv4 address shown there.
- Find your public address. From any device at home, visit an IP echo site, or run
curl ifconfig.mefrom a terminal. - Compare them. If they’re identical, you have a real public IPv4 address, and your inbound problem is somewhere else. If they’re different, something between your router and the internet is doing NAT.
If the WAN address starts with 100.64 through 100.127, that’s the shared address range reserved specifically for carrier NAT. Case closed. Some ISPs use ordinary private ranges instead, like 10.x.x.x, which makes it look like a double-NAT situation inside your house. Before blaming the ISP, check that your router isn’t plugged into another router, like an ISP combo box you forgot was in router mode. A traceroute to any public host helps: if the first hop is your router and the second hop is also a private or 100.x address that isn’t yours, that second hop is the ISP’s NAT.
One confusing detail if you use Tailscale: Tailscale also hands out addresses from the 100.64.0.0/10 range for devices on your tailnet. So you might see “100.something” in two places and assume they’re related. They aren’t. The Tailscale address lives on a virtual interface on your devices. The CGNAT address is on your router’s WAN port. Check the router, not your laptop.
Why ISPs do this, and who does it most
It isn’t malicious. An ISP that launched in the last decade may have been allocated a fraction of the IPv4 addresses it needs, and buying more on the secondary market costs real money per address. CGNAT lets them serve thousands of customers from a small pool.
In my experience, you’re most likely to hit it on:
- Newer fiber providers and regional ISPs that entered the market after IPv4 ran out.
- Mobile broadband, 4G and 5G home internet, where CGNAT is close to universal.
- Cheaper “basic” tiers from bigger ISPs, where a public address is reserved for pricier plans.
- Apartment buildings with a bulk internet contract, where the building’s provider NATs everybody.
Established cable and DSL providers with large legacy address blocks are least likely to do it, though some are moving new customers onto CGNAT as well. The only reliable way to know is to check.
Your options, from cheapest to most involved
Once you know it’s CGNAT, the question stops being “what’s wrong with my router” and becomes “how do I get traffic in.” Here’s what I tried, roughly in the order I’d recommend.
1. Ask the ISP to take you off it
This is the one people skip because it sounds too simple. Call or message support and ask for a public IPv4 address. Use exactly those words; “I can’t forward ports” may get you a script about UPnP. Some providers will move you to a public address for free, same day, because they only apply CGNAT by default and keep a pool for people who ask. Others charge a monthly fee, often packaged as a “static IP” add-on. A few flatly refuse on residential plans.
My provider charged €5 a month for a public dynamic address. Worth knowing: you usually don’t need the static version to escape CGNAT. A public dynamic address plus dynamic DNS is enough for most home servers. If you’re weighing whether to pay extra for the address to also be fixed, that’s a separate question about whether a home server needs a static IP at all, and the answer is usually no.
2. Check whether IPv6 already solves it
Many CGNAT’d connections come with native IPv6, and IPv6 has no shortage of addresses, so there’s no carrier NAT. Your server may already have a globally reachable IPv6 address. Allow the port in your router’s IPv6 firewall and it’s reachable.
The catch is the other end. Plenty of networks your visitors will be on, like office Wi-Fi, hotels, and some mobile carriers, still don’t route IPv6 properly. An IPv6-only server works beautifully from your phone on one network and times out from your colleague’s laptop on another. It’s a good supplement, not a replacement, unless you control every client.
3. Don’t expose anything: use an overlay network
If the only people using your server are you and a handful of people you trust, you may not need inbound connections from the public internet at all. Tailscale, ZeroTier, or a plain WireGuard setup create a private network between your devices. Each device makes outbound connections, and the overlay stitches them together, often punching straight through both layers of NAT.
CGNAT does make direct connections harder. Some carrier NATs behave in a way that defeats hole punching, and then your traffic goes through a relay instead. With Tailscale you’ll see this as a “relayed” connection in the status output. It still works; it’s just slower and adds latency. For a password manager or Home Assistant, you won’t care. For streaming a 4K movie from Jellyfin to a phone on hotel Wi-Fi, you might.
This is what I use for 90% of my services now, and it’s the option I’d tell most people to try first.

4. Use an outbound tunnel for a public website
Some things genuinely need a public URL: a blog, a shared calendar for people who won’t install an app, a webhook endpoint for a service like GitHub or Stripe. For those, tunnel services turn the problem around. A small agent on your server opens an outbound connection to the provider’s edge, and the provider accepts public traffic for your hostname and sends it back down that connection. Nothing inbound ever touches your router, so CGNAT is irrelevant.
Cloudflare Tunnel is the one most people meet first, and Tailscale Funnel does something similar for devices already on a tailnet. They differ in who terminates TLS, what traffic they’ll carry, and how much they see of it. If you’ve decided a tunnel is the answer and you’re choosing between those two, Cloudflare Tunnel versus Tailscale Funnel for one public URL is the comparison you’ll want next.
The limitation to know about up front: these services are built for HTTP and HTTPS. Game servers, raw TCP, and UDP-heavy protocols are either unsupported, restricted by terms of service, or awkward. And a large media library streamed through a free tunnel may run into fair-use rules.
5. Rent a small VPS and tunnel through it
This is the most flexible option and the one I ended up adding for the leftovers. You rent the cheapest VPS you can find, which comes with a real public IPv4 address. Your home server connects to it over WireGuard, outbound, so CGNAT doesn’t matter. Then the VPS forwards whichever ports you want down the tunnel to your server.
Now you have what you had before CGNAT: a public address, any port, any protocol. A Minecraft server for my nephew, a self-hosted Git remote a friend’s CI pushes to, SSH from a locked-down work machine. All of it goes through a €4-a-month box that does nothing except forward packets.
The cost is that you now run a second machine on the internet. It needs updates, a firewall, and some thought about what it forwards. Your home server’s traffic also takes a detour through the VPS’s data center, which adds latency depending on where it is. Pick a location close to home.
What I’d do in your shoes
If I were starting fresh behind CGNAT, here’s the order I’d go in:
- Ask the ISP first. One message could make the whole problem vanish, and a free public address beats every workaround.
- If that fails, split your services by audience. Things only you and family use go on an overlay. That’s usually most of them.
- For the few things that need to be public over HTTPS, use a tunnel service.
- For anything else, like games, odd protocols, or services where you don’t want a third party terminating TLS, add a small VPS as your front door.
Looking back, the two lost evenings weren’t really about CGNAT. They were about me assuming the problem was inside my house because that’s where all my tools were. The five-minute check, router WAN address against public address, is now the first thing I do on any new connection, before I touch a single port forward. If the numbers don’t match, stop configuring. There’s nothing on your side of the wall to fix.