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
- Qué es un túnel SSH
- Los 8 escenarios
- Túneles en background
- ProxyJump: el salto de 2016 que lo cambió todo
- GatewayPorts: el gotcha que nadie te cuenta
- Sshuttle: la VPN del sysadmin
- Integración con ~/.ssh/config
- [Cheat sheet](#c
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)
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
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)
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
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
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
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
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
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
- Los 8 escenarios de port forwarding con SSH — artículo original (copia en CRySoL)
- man ssh — documentación oficial de OpenSSH
- Sshuttle — VPN transparente sobre SSH
- VPS gratuito en Oracle Cloud — para tener un nodo SSH siempre disponible