What is CGNAT?
CGNAT (also called CGN or large-scale NAT) is a technique ISPs use to stretch their limited supply of IPv4 addresses. Your router doesn’t get its own public IP address. Instead, it gets a private address from your ISP, and the ISP translates traffic for many customers through a shared public IP. This works fine for outbound traffic like browsing and streaming. It breaks anything that needs inbound connections, such as:- Hosting a website, API, or app from home
- SSH or remote desktop into a home machine
- Self-hosted services like Home Assistant, Plex, or a network-attached storage (NAS) device
- Game servers
- Receiving webhooks on a local machine
How to tell if you’re behind CGNAT
- Find your router’s WAN (internet-facing) IP address in its admin page.
- Compare it to your public IP address, as reported by any “what is my IP” website.
100.64.0.0 to 100.127.255.255 range, which RFC 6598 reserves as shared address space for CGNAT.
Why port forwarding doesn’t work behind CGNAT
Port forwarding tells your router to send inbound traffic on a port to a device on your network. Behind CGNAT, inbound traffic first hits your ISP’s NAT, which doesn’t know which customer it belongs to, so it drops the traffic before it ever reaches your router. You can’t configure your ISP’s NAT, so no router setting can fix it. The usual workarounds are paying your ISP for a public or static IP (when they offer one), running your own virtual private server (VPS) as a relay, or using a tunnel that connects outbound, which is how ngrok works.Expose a local service through CGNAT with ngrok
What you’ll need
- ngrok installed.
- Your ngrok authtoken.
1. Install and configure ngrok
Install ngrok using the method that works best for your system, then add your authtoken:2. Expose a web app or API over HTTP
For anything that speaks HTTP, such as a web app, API, Home Assistant, or a dev server, start an HTTP endpoint pointed at its local port:localhost:8080.
You don’t need to change your network or router.
On the free plan, your account’s dev domain stays the same across restarts, so the URL doesn’t change.
3. Expose SSH, RDP, or other TCP services
For non-HTTP services such as SSH, remote desktop (RDP), databases, or game servers, use a TCP endpoint:tcp://1.tcp.ngrok.io:12345.
Connect to it the same way you’d connect to the service directly, for example:
On the free plan, you can use TCP endpoints only after you add a valid payment method to your account.
4. Restrict who can reach it
Anyone with your public URL can reach it. Before you expose anything sensitive, add authentication or an IP allowlist with a Traffic Policy, so your service isn’t open to the whole internet.Frequently asked questions
Does ngrok work behind CGNAT?
Yes. The ngrok agent only makes outbound connections, which CGNAT allows, so it works without a public IP, port forwarding, or router access.Does ngrok work on Starlink?
Yes. Starlink residential plans use CGNAT, which blocks port forwarding. ngrok’s outbound connection works on Starlink without any configuration.Can I port forward without router access?
Not with traditional port forwarding, which requires you to configure the router. ngrok gives you the same result, a public address that reaches a local port, without touching the router.Do I need a static or public IP address?
No. ngrok gives your service a public URL or TCP address, so your own IP address doesn’t matter and can change.Can I use this for OpenVPN?
Yes. See Using ngrok with OpenVPN to tunnel an OpenVPN server through CGNAT.Learn more
- Share localhost: Put any local app on a public URL.
- Using ngrok with OpenVPN: Run an OpenVPN server from behind CGNAT.
- Don Simpson’s blog post on working around CGNAT with ngrok.