# SSH into a Pi behind CGNAT

Behind carrier-grade NAT, port forwarding cannot work: the public IP on your
router belongs to your ISP and is shared with hundreds of other customers.
The fix is to turn the connection around. The Pi opens an outbound tunnel to
a relay, and you SSH to the relay. This page shows how to tell whether you
are behind CGNAT, and then how to get in.

## Check whether you are behind CGNAT

Open your router's status page and note its WAN address. Then, from any
machine on the same network, ask the internet what address it sees:

```sh
curl -4 ifconfig.me
```

You are behind CGNAT if either of these is true:

- The router's WAN address is between `100.64.0.0` and `100.127.255.255`. That range is reserved for carrier-grade NAT.
- The router's WAN address and the `curl` result are different. The router sits behind a second layer of NAT that you do not control.

A WAN address in `10.x.x.x` or `192.168.x.x` means the
same thing. If the two addresses match and are public, you are not behind
CGNAT, and a forwarded port would work — though
[you may still
not want one](https://relayssh.com/docs/ssh-without-port-forwarding/).

## Why port forwarding cannot help

A forwarding rule on your router says "send inbound port 22 to the Pi". But
inbound traffic for that public IP arrives at your ISP's NAT first, and the
ISP has no rule for it. The packet is dropped before your router ever sees
it. Dynamic DNS does not help either: it publishes an address that nobody
can connect to. Some ISPs sell a public IP as an add-on; many will not
offer one at any price. Mobile carriers never do.

Outbound connections are unaffected. Your Pi can reach any server on the
internet, and it can keep that connection open. That is the whole trick.

## Turn the connection around

The agent on your Pi opens an SSH connection out to the relay and holds a
reverse tunnel on it. The relay gives that tunnel a public port. You SSH to
the relay on that port, and the connection is delivered to the Pi's own SSH
server through the tunnel. Nothing inbound ever reaches your network. Your
Pi checks your key or password, not the relay — we never hold your logins.

## Install the agent on the Pi

Sign in, open **Add device**, and run the install command on
the Pi. It needs Linux with systemd, Python 3.11 or newer, and
`ssh-keygen` — Raspberry Pi OS has all three.

```sh
curl -fsSL https://relayssh.com/install/YOUR-INSTALL-KEY/ | sudo sh
```

## Add a tunnel to port 22

The Pi appears in the dashboard within a few seconds. On its page, add a
tunnel to port 22. The relay assigns a public port between 20000 and
29999, and the agent opens the reverse tunnel to it.

## SSH in

Use the assigned port and your usual username. The login is the Pi's own:

```sh
ssh -p 20001 pi@relayssh.com
```

Nothing about your ISP, router, or WAN address is involved. Move the Pi
to another CGNAT network and the same command still works.

## What about IPv6?

Many ISPs that use CGNAT for IPv4 hand out public IPv6 addresses, and an
IPv6 address is reachable from anywhere with IPv6 — no NAT at all. That is
a real option if every network you will ever connect from also has IPv6.
Many do not: hotel Wi-Fi, mobile data in some countries, and most corporate
networks are still IPv4 only. A tunnel works from both. So does a mesh VPN,
if every machine involved is yours to install on —
[RelaySSH vs Tailscale](https://relayssh.com/docs/relayssh-vs-tailscale/)
covers that trade.

## Boundaries

The Pi needs outbound TCP to `relayssh.com` on ports 443 and
2002. CGNAT never blocks outbound traffic, but a strict firewall might block
port 2002; if it does, the tunnel will not connect. A tunnel forwards one
TCP port, so this is SSH access to the Pi, not a VPN into your network — for
a NAS or camera next to the Pi, see
[reaching devices next to your Pi](https://relayssh.com/docs/reach-lan-devices/).
