¿Cuál necesitas?
| Opción | El puerto se abre en | Úsalo para |
|---|---|---|
-L local | Tu máquina | Llegar a un servicio que solo el servidor puede alcanzar, como una base de datos. |
-R remoto | El servidor | Dejar que el servidor llegue a algo de tu máquina, como un sitio de desarrollo. |
-D dinámico | Tu máquina | Navegar o conectarte a muchos hosts como si estuvieras en el servidor. |
Una forma fácil de recordarlo: -L escucha en tu máquina local, -R escucha en el servidor remoto, y -D es dinámico porque la aplicación elige el destino cada vez.
Reenvío local: -L
ssh -N -L 8080:localhost:80 user@server
your app -> your machine, port 8080 -> SSH -> server -> localhost:80 as seen by the server
El formato es puerto_local:destino:puerto_destino. Ahora http://127.0.0.1:8080 en tu máquina muestra el servidor web que escucha solo en la dirección de loopback del propio servidor.
Lo importante es que el servidor resuelve el destino. localhost significa el propio servidor, no tu máquina. El destino también puede ser otro host al que llegue el servidor, y ese último salto no lo cifra SSH:
ssh -N -L 8080:intranet.example.com:80 user@server
Reenvío remoto: -R
ssh -N -R 9000:localhost:3000 user@server
a program on the server -> server, port 9000 -> SSH -> your machine -> localhost:3000 as seen by your machine
Ahora un programa del servidor puede abrir http://127.0.0.1:9000 y llegar a la aplicación que corre en tu máquina. Funciona incluso cuando tu máquina está detrás de un NAT, porque tu lado inició la conexión.
Reenvío dinámico: -D
ssh -N -D 1080 user@server
your app -> SOCKS proxy on your machine, port 1080 -> SSH -> server -> any host:port the app asks for
Apunta una aplicación compatible con SOCKS a 127.0.0.1:1080. Para probarlo con curl:
curl --socks5-hostname 127.0.0.1:1080 http://intranet.example.com/
--socks5-hostname hace que la consulta DNS la haga el servidor, así que los nombres internos funcionan y la consulta no se filtra desde tu propia red. Con --socks5 a secas el nombre se resuelve en tu máquina.
La configuración del navegador y las fugas de DNS están en cómo usar SSH como proxy SOCKS.
Varios puertos, o a través de un jump host
Repite la opción para abrir varios reenvíos sobre una misma conexión:
ssh -N -L 127.0.0.1:8080:localhost:80 -L 127.0.0.1:5433:localhost:5432 user@server
Cuando el servidor está detrás de un bastión, añade -J. El reenvío sale del último servidor de la cadena, así que es ese servidor el que resuelve el destino:
ssh -N -J user@bastion -L 127.0.0.1:5433:localhost:5432 user@db-server
Las cadenas de servidores se explican en cómo usar ProxyJump y un jump host.
Ejecutar un túnel sin shell
-Nno ejecuta ningún comando remoto. La sesión solo lleva el túnel.-fpasa a segundo plano después de autenticarse, de modo que todavía puedes escribir antes una frase de contraseña.-o ExitOnForwardFailure=yestermina con un error si no se puede establecer el reenvío.
ssh -f -N -o ExitOnForwardFailure=yes -L 127.0.0.1:8080:localhost:80 user@server
Sin ExitOnForwardFailure, ssh muestra un aviso y sigue conectado sin un túnel que funcione, algo que desconcierta dentro de un script. Con esa opción, un puerto local ya en uso termina con código de salida 255 y Could not request local forwarding, y un puerto remoto en uso termina con remote port forwarding failed for listen port.
Una trampa que vimos en las pruebas: con un -L 8080:... sin dirección, ssh escucha tanto en 127.0.0.1 como en ::1. Si solo una de ellas está ocupada, por ejemplo por otro programa en IPv4, ssh muestra bind [127.0.0.1]:8080: Address already in use y sigue funcionando incluso con ExitOnForwardFailure=yes. Tu aplicación podría entonces llegar a ese otro programa. Escribir la dirección, como en -L 127.0.0.1:8080:..., hace que sea un fallo de verdad, así que usa esa forma en los scripts.
Para detener un túnel en segundo plano, busca su proceso y termínalo:
pgrep -f 'L 127.0.0.1:8080'
kill PID
Para los túneles que abres a menudo, un socket de control te deja detenerlos por su nombre con ssh -O exit. Consulta cómo guardar, iniciar y detener túneles SSH.
Para dejar un túnel en tu configuración, usa LocalForward, RemoteForward y DynamicForward:
Host dbtunnel
HostName 203.0.113.10
User user
LocalForward 127.0.0.1:8080 localhost:80
ExitOnForwardFailure yes
Enlazar solo a localhost
Un puerto reenviado está abierto para quien pueda llegar a él, y el servicio que hay detrás puede fiarse de las conexiones procedentes del servidor. Por defecto, ssh enlaza solo al loopback, así que déjalo así salvo que tengas un motivo.
Estos comandos abren el puerto local a toda tu red. Confirmamos que ambos escuchan en todas las interfaces:
ssh -N -L 0.0.0.0:8080:localhost:80 user@server
ssh -N -g -L 8080:localhost:80 user@server
Con -R, decide el servidor, mediante GatewayPorts en su configuración de sshd:
| GatewayPorts | -R 9000:... | -R 0.0.0.0:9000:... |
|---|---|---|
no (por defecto) | Solo loopback | Solo loopback, sin ningún error |
clientspecified | Solo loopback | Todas las interfaces |
yes | Todas las interfaces | Todas las interfaces, y 127.0.0.1:9000 también se abre en todas las interfaces |
Así que si no se puede llegar desde fuera a tu puerto -R, el motivo habitual es GatewayPorts. Exponer a internet un servicio de tu portátil de esta forma rara vez es lo que quieres. Si lo necesitas, prefiere clientspecified y añade una regla de firewall.
Cuando el servidor lo rechaza
AllowTcpForwarding en la configuración de sshd del servidor controla esto. Los valores son yes (el valor por defecto), no, local (permite -L y -D) y remote (permite -R).
- Un
-Lo-Dbloqueado se conecta sin problema. El error aparece solo cuando algo usa el puerto:channel 2: open failed: administratively prohibited: open failed. - Un
-Rbloqueado diceremote port forwarding failed for listen port.
La página del manual señala que desactivar el reenvío aporta poco si los usuarios también tienen un shell, ya que pueden ejecutar su propio reenviador. Para limitar de verdad a alguien, quítale también el shell, como en un usuario solo de túnel para una base de datos.
Otros dos errores salen a menudo. Cuando el puerto local o remoto está ocupado, consulta Address already in use y remote port forwarding failed. Cuando se rechazan las conexiones a través del túnel, consulta administratively prohibited: open failed.
Preguntas
¿Qué diferencia hay entre ssh -L y ssh -R?
-L abre un puerto en tu equipo que lleva a algo que alcanza el servidor. -R abre un puerto en el servidor que lleva de vuelta a algo de tu equipo.
¿Cómo reenvío varios puertos con un solo comando ssh?
Repite la opción: ssh -N -L 127.0.0.1:8080:localhost:80 -L 127.0.0.1:5433:localhost:5432 user@server. Una sola conexión los lleva todos. En ~/.ssh/config, añade una línea LocalForward por puerto.
¿Cómo mantengo activo un túnel SSH?
Arráncalo con -N y -o ExitOnForwardFailure=yes, y deja que autossh o un servicio de systemd lo reinicie tras un corte. Consulta autossh y systemd.
¿Por qué el túnel conecta pero no funciona nada?
El servidor puede prohibir el reenvío con AllowTcpForwarding. Un -L o -D bloqueado conecta igual y solo falla al usar el puerto, con administratively prohibited: open failed.
¿Es seguro el reenvío de puertos SSH?
El tráfico va cifrado entre tu equipo y el servidor SSH. El tramo del servidor al destino no, y un puerto que escucha en 0.0.0.0 lo puede usar cualquiera en tu red, así que deja la dirección de escucha en 127.0.0.1.