SSH port forwarding: los 8 escenarios con -L, -R y -D

SSH port forwarding: los 8 escenarios con -L, -R y -D

El Imperio controla la Holonet. Cada mensaje que viaja por los canales oficiales pasa por sus filtros, sus inspectores, sus reglas de firewall.

La Alianza aprendió pronto que la única forma de comunicarse con seguridad era no usar esos canales. Había otra red — más discreta, construida con nodos de confianza conectados por rutas encubiertas. Un paquete que parecía ir de Tatooine a Mos Eisley llevaba en realidad las coordenadas de Echo Base cifradas en su interior. El firewall imperial solo veía una conexión SSH normal. Lo que viajaba dentro era otra cosa.

SSH funciona así. No mueve solo sesiones de terminal — mueve cualquier tráfico TCP dentro de un canal cifrado. Un servicio bloqueado por el firewall puede aparecer en tu localhost. Un servidor interno puede exponerse al exterior con un solo comando. La red privada de otro sistema se convierte en tu red.

Ocho escenarios. Tres flags (-L, -R, -D). Un solo canal SSH. Esta es la guía completa de port forwarding actualizada a 2026: los comandos de hoy, ProxyJump, Sshuttle y lo que los libros no cuentan.

Índice


Aviso de uso responsable

Los túneles SSH son una herramienta legítima de administración de sistemas: acceso a servicios internos, administración remota segura, bypass de restricciones de red propias.

Usar estas técnicas para acceder sin autorización a sistemas ajenos o para evadir controles de seguridad corporativos sin permiso es ilegal. Úsalas en sistemas propios o con autorización escrita del propietario.


Qué es un túnel SSH

SSH cifra la conexión entre dos máquinas. Pero además de ejecutar comandos, puede hacer otra cosa: encapsular tráfico TCP dentro de esa conexión cifrada. Eso es un túnel.

Hay tres tipos:

Tipo Flag Quién inicia Para qué
Local -L El cliente Acceder a servicios del lado remoto
Remoto -R El cliente Exponer servicios del lado local al remoto
Dinámico -D El cliente Proxy SOCKS para cualquier destino

En los ejemplos siguientes usamos esta topología:

Red externa          Frontera SSH              Red interna
──────────────       ──────────────────        ──────────────
Tatooine             Tatooine  Coruscant       Coruscant
Mos Eisley       ←── único canal SSH ───────→  Mandalore

Tatooine puede conectar con Coruscant por SSH. No hay otra ruta entre las dos redes.


Los 8 escenarios

Escenario 1 — Local: Tatooine usa un servicio de Coruscant (localhost)

Escenario 1 — SSH local port forwarding a localhost

Tatooine quiere conectarse al servicio VNC (puerto 5900) de Coruscant, que solo escucha en localhost:

tatooine $ ssh -L 7900:localhost:5900 usuario@coruscant

El puerto 7900 de Tatooine ahora apunta al puerto 5900 de Coruscant. Solo es accesible desde el propio Tatooine:

tatooine $ vncviewer localhost::7900

Escenario 2 — Local: Mos Eisley usa un servicio de Coruscant vía Tatooine

Escenario 2 — SSH local port forwarding 0.0.0.0

Igual que el anterior, pero queremos que sea Mos Eisley quien acceda. Necesitamos que el puerto local se abra en 0.0.0.0 en lugar de en localhost:

tatooine $ ssh -L 0.0.0.0:7900:localhost:5900 usuario@coruscant
# equivalente:
tatooine $ ssh -g -L 7900:localhost:5900 usuario@coruscant

Ahora desde Mos Eisley:

moseisley $ vncviewer tatooine::7900

Escenario 3 — Remoto: Coruscant usa un servicio de Tatooine (localhost)

Escenario 3 — SSH remote port forwarding a localhost

Ahora el flujo es al revés. Tatooine tiene un servicio que Coruscant quiere usar. El túnel se establece desde Tatooine con -R:

tatooine $ ssh -R 7900:localhost:5900 usuario@coruscant

En Coruscant aparece el puerto 7900 apuntando al VNC de Tatooine:

coruscant $ vncviewer localhost::7900

Escenario 4 — Remoto: Mandalore usa un servicio de Tatooine vía Coruscant

Escenario 4 — SSH remote port forwarding GatewayPorts

Como en el escenario 2 pero en dirección contraria. Por defecto, -R solo escucha en localhost de Coruscant. Para que Mandalore también pueda acceder, necesitamos GatewayPorts (ver sección más abajo):

tatooine $ ssh -R 0.0.0.0:7900:localhost:5900 usuario@coruscant

Esto solo funciona si Coruscant tiene GatewayPorts yes en su sshd_config.


Escenario 5 — Local: Tatooine accede a un servicio de Mandalore vía Coruscant

Escenario 5 — SSH local port forwarding multi-hop

Tatooine quiere acceder a un servicio en Mandalore, que solo tiene conectividad con Coruscant. El túnel salta a través de Coruscant:

tatooine $ ssh -L 7902:mandalore:5900 usuario@coruscant
tatooine $ vncviewer localhost::7902

El tráfico viaja: Tatooine:7902 → SSH → Coruscant → TCP → Mandalore:5900.


Escenario 6 — Local 0.0.0.0: Mos Eisley también llega a Mandalore

Escenario 6 — SSH local port forwarding 0.0.0.0 multi-hop

Como el escenario 5, pero exponiendo el puerto a Mos Eisley:

tatooine $ ssh -L 0.0.0.0:7902:mandalore:5900 usuario@coruscant
moseisley $ vncviewer tatooine::7902

Escenario 7 — Remoto: Coruscant accede a un servicio de Mos Eisley

Escenario 7 — SSH remote port forwarding a red externa

Coruscant quiere acceder a un servicio en Mos Eisley, que solo tiene conectividad con Tatooine. De nuevo, -R al rescate:

tatooine $ ssh -R 7902:moseisley:5900 usuario@coruscant
coruscant $ vncviewer localhost::7902

Escenario 8 — Dinámico: proxy SOCKS hacia cualquier destino

Escenario 8 — SSH dynamic port forwarding SOCKS5

El más potente. En lugar de reenviar a un destino fijo, crea un proxy SOCKS en el cliente que puede dirigir tráfico a cualquier destino a través del servidor SSH:

tatooine $ ssh -D 1080 usuario@coruscant

Ahora localhost:1080 es un proxy SOCKS5. Cualquier aplicación que soporte SOCKS puede usarlo:

# Navegar a través del proxy
curl --socks5 localhost:1080 https://example.com

# Abrir Firefox con el proxy SOCKS5
firefox --proxy-server="socks5://localhost:1080"

# Redirigir cualquier herramienta con proxychains
proxychains nmap -sT mandalore

Túneles en background: -f -N

En los escenarios anteriores, el túnel ocupa la terminal. Para uso en producción, lánzalo en background:

# -f: va al background tras autenticarse
# -N: no ejecuta ningún comando remoto (solo el túnel)
ssh -f -N -L 7900:localhost:5900 usuario@coruscant

Verificar que el túnel está activo:

ss -ltn | grep 7900
# o
nmap -p 7900 127.0.0.1

Para cerrarlo:

pkill -f "ssh -f -N -L 7900"

ProxyJump: el salto de 2016 que lo cambió todo

Antes de OpenSSH 7.3 (2016), hacer SSH a través de un bastion host requería ProxyCommand con netcat o -W. Desde entonces existe -J:

# Conectar a Coruscant pasando por Tatooine
ssh -J tatooine usuario@coruscant

# Múltiples saltos
ssh -J tatooine,coruscant usuario@mandalore

Combinado con port forwarding:

# Túnel local a Mandalore pasando por Tatooine → Coruscant
ssh -J tatooine,coruscant -L 7900:localhost:5900 usuario@mandalore

En ~/.ssh/config, la forma canónica:

Host coruscant
    HostName coruscant
    User usuario
    ProxyJump tatooine

Host mandalore
    HostName mandalore
    User usuario
    ProxyJump coruscant

Con esto, ssh mandalore ya hace los saltos automáticamente.


GatewayPorts: el gotcha que nadie te cuenta

Por defecto, cuando haces -R 7900:localhost:5900, el puerto 7900 se abre solo en localhost de Coruscant. Aunque pongas 0.0.0.0, por defecto el servidor SSH lo ignora.

Para que funcione el escenario 4 — o cualquier remote forward accesible desde la red interna — necesitas en sshd_config de Coruscant:

GatewayPorts yes

O una opción intermedia:

GatewayPorts clientspecified

Con clientspecified, el cliente controla si el puerto se expone a 0.0.0.0 o no. Con yes, todos los forwards remotos se exponen siempre.

Tras el cambio, reiniciar SSH:

systemctl restart ssh

Sshuttle: la VPN del sysadmin

Los túneles SSH manuales sirven para puertos concretos. Cuando quieres acceder a toda la red remota sin configurar cada puerto a mano, existe sshuttle.

Sshuttle redirige transparentemente todo el tráfico TCP hacia una red remota a través de SSH. No necesita root en el servidor remoto — solo Python.

# Instalar en Debian/Ubuntu
apt install sshuttle

# Enrutar todo el tráfico de 192.168.10.0/24 a través de Coruscant
sshuttle -r usuario@coruscant 192.168.10.0/24

# Con salto intermedio (ProxyJump)
sshuttle -r usuario@coruscant 192.168.10.0/24 --ssh-cmd "ssh -J tatooine"

# Todo el tráfico (VPN completa)
sshuttle -r usuario@coruscant 0/0

Mientras sshuttle está activo, accedes a 192.168.10.x directamente desde tu máquina, sin configurar proxychains ni puertos individuales.


Integración con ~/.ssh/config

Las opciones de tunnel también van en ~/.ssh/config. Así evitas escribir el comando completo cada vez:

Host mi-tunel-vnc
    HostName coruscant
    User usuario
    LocalForward 7900 localhost:5900
    ServerAliveInterval 60
    ExitOnForwardFailure yes

Host mi-socks
    HostName coruscant
    User usuario
    DynamicForward 1080
    ServerAliveInterval 60

Con esto, ssh mi-tunel-vnc -N activa el túnel. Añade -f para enviarlo al background.

ServerAliveInterval 60 envía un keep-alive cada 60 segundos para que el túnel no caiga si no hay tráfico. ExitOnForwardFailure yes hace que SSH salga con error si el puerto local ya está en uso — útil en scripts.


Cheat sheet

Objetivo Comando
Acceder a puerto remoto desde localhost ssh -L LPORT:localhost:RPORT user@host
Acceder a puerto remoto desde la red local ssh -L 0.0.0.0:LPORT:localhost:RPORT user@host
Exponer tu servicio al servidor remoto ssh -R RPORT:localhost:LPORT user@host
Acceder a tercera máquina de la red remota ssh -L LPORT:host3:RPORT user@host
Proxy SOCKS dinámico ssh -D 1080 user@host
Túnel en background ssh -f -N -L LPORT:localhost:RPORT user@host
Salto por bastion ssh -J bastion user@destino
VPN transparente a subred sshuttle -r user@host 192.168.1.0/24
VPN total sshuttle -r user@host 0/0

Recursos