Reach a Raspberry Pi Behind CGNAT
If your ISP has you behind carrier-grade NAT, no amount of port forwarding on your own router will make the Pi reachable, because the address your router holds is not a public one. Four things do work: IPv6 if your carrier gives you a real prefix, a mesh VPN if the only audience is you, a tunnelled HTTP relay if you only serve web traffic, or a routable public address attached to the Pi itself. Below is the thirty-second check that tells you which situation you are in, then each option with the commands as they run on Raspberry Pi OS.
First: confirm it really is CGNAT
Run this on the Pi. It takes one command and settles the question.
curl -s https://api.ipify.org; echo
ip -4 addr show | grep -oP 'inet \K[\d.]+'
The first line is the address the internet sees you at. The second lists the addresses your Pi actually holds. Now look at what your router reports as its WAN address, in its admin page.
- Router WAN address is the same as the first line: you have a normal public address. Port forwarding will work and you do not need this guide.
- Router WAN address is different, and sits in
100.64.0.0to100.127.255.255: that is the shared address range reserved for carrier-grade NAT. You are behind CGNAT. - Router WAN address is different and private (
10.x,192.168.x): also CGNAT, or a second router doing NAT of its own. Check for a modem in router mode before blaming the carrier.
Starlink, T-Mobile Home Internet, most 5G home broadband and a growing number of cable providers default to this. It is not a fault and support usually cannot turn it off.
What you are probably trying to reach
It matters, because it decides which options are even candidates.
| What is on the Pi | Who needs to reach it | What that rules in |
|---|---|---|
| Pi-hole, Home Assistant, Octoprint | Usually just you and your household | A mesh VPN is the right answer |
| A web app or dashboard for others | Anyone with the link | An HTTP tunnel, or a public address |
| A game server, Minecraft especially | Friends, on a non-HTTP port | A public address |
| A camera or NVR feed | You, remotely | Mesh VPN first; public address if the app demands it |
| SSH from anywhere | Just you | A mesh VPN, every time |
Option 1: IPv6, if you have it
Many carriers that put you behind CGNAT for IPv4 give you a genuine, routable IPv6 prefix at the same time. If so, this is free and already paid for.
ip -6 addr show scope global
curl -s -6 https://api64.ipify.org; echo
An address starting 2 or 3 is a global one. If the second command returns something, your Pi can already talk IPv6 to the world. You will still need to allow the port through any firewall on the Pi and on the router, since IPv6 has no NAT to hide behind — which is the point, and also the risk.
The catch, and it is a real one: whoever connects to you needs IPv6 too. Plenty of mobile networks have it; plenty of offices and older home connections do not. For something only you use, that is often fine. For a game server your friends join, assume at least one of them cannot reach it.
Option 2: a mesh VPN, if the audience is you
If the honest answer to “who needs to reach this” is you and perhaps your household, stop here and install Tailscale. It is free at this scale, it works through CGNAT without any of this, and it is better at the job than anything else on this page.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Your Pi joins a private network. Your phone and laptop join the same one. They reach each other wherever they are, and nothing is exposed to the public internet at all. For Pi-hole, Home Assistant, Octoprint and remote SSH, this is the correct tool and I am not going to pretend otherwise.
The limit is the word private: a stranger's browser is not on your network. Their Funnel feature bridges that for HTTP, with the address belonging to them rather than to you.
Option 3: an HTTP tunnel, if you only serve web traffic
Cloudflare Tunnel is free and genuinely good if everything you serve is HTTP or HTTPS. A daemon on the Pi dials out, so CGNAT is irrelevant, and you get a hostname with TLS handled for you.
It is the wrong tool the moment you need a port that is not 80 or 443. Minecraft on 25565, a mail daemon, a game server, plain SSH — none of those fit through an HTTP tunnel.
Option 4: give the Pi a public address
When the audience is the public and the port is not HTTP — the Minecraft case, mostly — what you need is a routable address that belongs to the Pi, not to your ISP.
This is what we sell, so weigh it accordingly. A small daemon on the Pi holds a link to our network, we route a public IPv4 address to it, and the Pi answers on that address on any port. Your home connection stays exactly as it is; the address is not your house's and does not change when your ISP reshuffles its pool.
curl -fsSL https://tunnelnet.io/install.sh | sudo bash
sudo tnet status
Then open the port you actually serve on. This is a separate step from the Pi's own firewall and it is the one people miss — ufw governs what the Pi accepts, this governs what reaches it in the first place. There is deliberately no default protocol, because a UDP service with a TCP rule fails silently:
sudo tnet ports allow tcp 25565 # Minecraft Java
sudo tnet ports allow udp 19132 # Minecraft Bedrock
sudo tnet ports mode # check what is open
That is the $10/month ingress plan. It runs on a Pi 3 or newer on 64-bit Raspberry Pi OS.
If you go public, harden the Pi first
This section is not optional and it is the part most guides leave out. A Raspberry Pi reachable from the internet gets scanned within minutes. I can see it in our own logs — requests for /.env and /wp-login.php arrive on anything with an address, continuously, from the moment it is routable.
# 1. keys only, no passwords
ssh-copy-id pi@raspberrypi.local # from your laptop, first
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart ssh
# 2. default-deny, then open only what you meant to
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 25565/tcp # only the ports you actually serve
sudo ufw enable
# 3. security updates without you remembering
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Three more things worth doing: change the default user if you still have one called pi, install fail2ban if you keep SSH open to the world, and check sudo ufw status after a reboot rather than assuming.
One honest caveat about SD cards
A Pi serving real traffic writes logs constantly, and SD cards wear out. If this is something you will be annoyed to lose, move the root filesystem to a USB SSD, or at minimum move logging to RAM with log2ram and keep a backup image. Reachability is the easy problem; the card failing at month fourteen is the one that actually bites.
Choosing, honestly
- Only you need in? Tailscale. Free, better, done.
- Public, and it is all HTTP? Cloudflare Tunnel. Free.
- You have working IPv6 and your visitors do too? Use it. You already paid for it.
- Public, on a port that is not 80 or 443? That is the case a routable address solves, and the case the free options do not cover.
Get a public IP — $10/mo See all plans
Related
- Synology NAS remote access behind CGNAT
- Home Assistant remote access behind CGNAT
- Access an IP camera or NVR without port forwarding
- How to reach a home server behind CGNAT
- Hosting a game server from home
- Hosting a server on Starlink, T-Mobile or 5G home internet
- Cloudflare Tunnel vs a dedicated IP
- Tailscale Funnel vs a public IP
- Why can't I host a server through my VPN?