Cómo conectarse por SSH a un servidor sin IP pública o detrás de CGNAT

Algo tiene que traer la conexión desde fuera. Puedes usar una VPN o red superpuesta como WireGuard o Tailscale, un túnel SSH inverso hacia un servidor con dirección pública, o IPv6 si los dos extremos lo tienen. Reenviar un puerto en tu router también funciona, pero no detrás de CGNAT, porque tu router no tiene una dirección pública desde la que reenviar.

Actualizada el . Los dos archivos de WireGuard se ejecutaron entre dos contenedores Debian 13 con wireguard-tools, y un inicio de sesión SSH sobre 10.0.0.2 funcionó.

Primero comprueba lo que tienes

Ejecuta esto en la máquina a la que quieres llegar, o mira la página de estado de tu router:

curl -4 https://ifconfig.me   # the public IPv4 others see
curl -6 https://ifconfig.me   # the public IPv6, if you have one
ip -6 addr show scope global  # IPv6 addresses on this machine

Después busca la dirección WAN en la página de estado de tu router. Si es distinta de la que muestra el primer comando, tu proveedor tiene otro NAT delante de ti. Una dirección de 100.64.0.0 a 100.127.255.255 en el lado WAN es una señal clara de CGNAT, porque la RFC 6598 reserva ese rango para ello.

Las opciones

NecesitaFunciona detrás de CGNATLímites
VPN o red superpuestaSoftware en ambos extremos. Un peer accesible o un servicio de coordinaciónSíHay que instalar el software en cada dispositivo desde el que te conectes
Túnel SSH inversoUn servidor con dirección públicaSíEl servidor extra transporta el tráfico
IPv6IPv6 global en la máquina y en la red desde la que te conectasSí, si el proveedor da IPv6Falla desde redes solo IPv4. El firewall debe permitirlo
Reenvío de puertos del routerUna IPv4 pública en el router y acceso a sus ajustesNoEl puerto queda abierto a internet. La dirección puede cambiar

VPN o red superpuesta

WireGuard

WireGuard es una VPN que ejecutas tú mismo. Detrás de CGNAT, la máquina oculta se conecta hacia fuera a un peer que tiene dirección pública, y el keepalive mantiene abierta la entrada del NAT. La guía rápida de WireGuard sugiere 25 segundos. En la máquina oculta, /etc/wireguard/wg0.conf:

[Interface]
Address = 10.0.0.2/24
PrivateKey = HIDDEN_MACHINE_PRIVATE_KEY

[Peer]
PublicKey = PUBLIC_PEER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.0.0.1/32
PersistentKeepalive = 25

En el peer con la dirección pública:

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = PUBLIC_PEER_PRIVATE_KEY

[Peer]
PublicKey = HIDDEN_MACHINE_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

Crea las claves con wg genkey | tee priv | wg pubkey > pub, inicia cada lado con sudo wg-quick up wg0 y conéctate con ssh user@10.0.0.2 desde el peer. El UDP 51820 debe estar abierto en él. Ejecutamos estos dos archivos entre contenedores y el acceso SSH por 10.0.0.2 funcionó. Solo el peer necesita una dirección pública.

Tailscale

Tailscale es una red superpuesta construida sobre WireGuard, con un servicio de coordinación alojado y una cuenta. En Linux, según su documentación:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Haz lo mismo en tu propio dispositivo y después conéctate por SSH a la dirección que te asigne, que tailscale ip -4 muestra en la máquina oculta. Tailscale intenta primero una conexión directa entre dispositivos, y su artículo sobre el NAT traversal dice que esto es más difícil detrás de CGNAT. Cuando las rutas directas fallan, el tráfico pasa por sus relés DERP, cifrado de extremo a extremo.

Túnel SSH inverso

Esto solo necesita SSH y un servidor con dirección pública, como 203.0.113.10. En la máquina oculta:

ssh -N -o ExitOnForwardFailure=yes -R 2222:localhost:22 user@203.0.113.10

Desde tu portátil:

ssh -J user@203.0.113.10 -p 2222 hiddenuser@localhost

Los detalles están en los túneles SSH inversos. Para reiniciarlo automáticamente tras una caída y restringir la clave que usa, mira autossh y systemd.

La opción -J se explica en ProxyJump y servidores de salto.

IPv6

El CGNAT se aplica a IPv4, y algunos proveedores que lo usan también reparten direcciones IPv6 globales. Si ip -6 addr show scope global muestra una, prueba desde una red que tenga IPv6:

ssh user@2001:db8::10

El router o el proveedor pueden bloquear el IPv6 entrante, así que un timeout puede significar que el firewall necesita una regla para el puerto 22. Mira Connection timed out. La red desde la que te conectas también tiene que tener IPv6, y algunas redes de oficinas y hoteles no lo tienen. Si tu dirección cambia, ayuda un nombre de DNS dinámico.

Reenvío de puertos del router

Esto funciona cuando el router tiene una dirección IPv4 pública real. En sus ajustes, reenvía un puerto TCP exterior al puerto 22 de la máquina y después conéctate a la dirección pública del router:

ssh -p 2222 user@203.0.113.10

Detrás de CGNAT esto no sirve de nada, porque la dirección pública pertenece a tu proveedor. Algunos proveedores te dan una IPv4 pública si la pides, a veces de pago, así que puede valer la pena preguntar. Un puerto abierto también recibe intentos de acceso constantes desde internet, así que usa solo claves. Mira cómo desactivar el acceso con contraseña y fail2ban.

Preguntas

¿Cómo sé si estoy detrás de CGNAT?

Compara la dirección WAN del router con la que ven sitios como ifconfig.me. Si no coinciden, o la dirección WAN está entre 100.64.0.0 y 100.127.255.255, tu proveedor usa CGNAT.

¿Puedo entrar por SSH a una máquina detrás de CGNAT sin VPN?

Sí, con un túnel SSH inverso hacia un servidor con dirección pública. La máquina oculta se conecta hacia fuera y tú llegas a ella a través de ese servidor.

¿Funciona la redirección de puertos del router detrás de CGNAT?

No. La dirección pública es del proveedor, no de tu router, así que no hay nada que redirigir. Pide al proveedor una IPv4 pública o usa otra de las opciones.

Fuentes

Más en Túneles y jump hosts

Todas las guías