Reenvío local (-L): el puerto está ocupado en tu máquina
Con ssh -L 8080:localhost:80 user@server puede aparecer:
bind [127.0.0.1]:8080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 8080
Could not request local forwarding.
Averigua quién ocupa el puerto. Esto funciona en macOS y Linux:
lsof -nP -iTCP:8080 -sTCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ssh 4242 user 4u IPv4 ... 0t0 TCP 127.0.0.1:8080 (LISTEN)
En Windows usa netstat -ano | findstr :8080.
ssh: un túnel anterior sigue en marcha, a menudo iniciado con-fy olvidado. Ejecutakill 4242con el PID que aparece, o mira la sección sobre conexiones compartidas más abajo.- Un servidor de desarrollo, Docker o una base de datos: elige otro puerto local. Solo hay que cambiar el número de la izquierda:
ssh -L 18080:localhost:80 user@server. - En macOS,
ControlCeen el puerto 5000 o 7000 es el receptor de AirPlay. Elige otro puerto, o desactiva el receptor de AirPlay en Ajustes del Sistema.
¿No sabes qué opción necesitas? Túneles SSH: redirección local, remota y dinámica compara los tres.
Solo apareció la primera línea
Si ves únicamente bind [127.0.0.1]:8080: Address already in use y la sesión se abre, SSH enlazó el lado IPv6 pero no el IPv4. -L 8080:... intenta ambos. El puerto queda a medias: los clientes que usan 127.0.0.1 llegan al otro programa, no a tu túnel. Indica la dirección y SSH informará del fallo como es debido:
ssh -o ExitOnForwardFailure=yes -L 127.0.0.1:8080:localhost:80 user@server
Reenvío remoto (-R): el puerto está ocupado en el servidor
Con ssh -R 8080:localhost:80 user@server:
Warning: remote port forwarding failed for listen port 8080
La sesión se abre igualmente y el aviso es fácil de pasar por alto. La causa está en el servidor, y su log contiene la misma línea bind. Mira allí quién ocupa el puerto:
ssh user@server "ss -ltnp | grep ':8080'"
El nombre del proceso solo aparece para tus propios procesos, salvo que lo ejecutes con sudo. A veces el dueño es sshd o sshd-session: la conexión anterior desde tu portátil o tu script de túnel murió sin que el servidor se enterara, y sigue sujetando el puerto. Busca y termina esa sesión en el servidor:
sudo ss -ltnp | grep ':8080'
sudo kill PID
Para que el servidor las limpie por sí solo, añade esto a sshd_config y recarga el servicio. Desconecta a un cliente que lleve unos 90 segundos en silencio:
ClientAliveInterval 30
ClientAliveCountMax 3
Un puerto ocupado no es el único motivo de este aviso. Si el puerto está libre, puede que el servidor prohíba el reenvío, caso que se trata en administratively prohibited.
Si no necesitas un puerto fijo, deja que el servidor elija uno. El cliente muestra el puerto que le tocó:
ssh -R 0:localhost:80 user@server
Allocated port 38587 for remote forward to localhost:80
Haz que un túnel fallido falle a la vista
Por defecto SSH inicia sesión aunque el reenvío haya fallado, así que los scripts siguen adelante y fallan más tarde por un motivo confuso. Con esta opción termina con el código 255:
ssh -o ExitOnForwardFailure=yes -N -L 127.0.0.1:8080:localhost:80 user@server
Con -R, el mensaje es entonces:
Error: remote port forwarding failed for listen port 8080
Usa esta opción en todo lo automatizado, incluido autossh. Así un bucle de reintentos puede ver el fallo y volver a intentarlo cuando el puerto esté libre.
Las conexiones compartidas también ocupan puertos
Con ControlMaster, el reenvío pertenece al proceso maestro en segundo plano, de modo que cerrar la terminal no libera el puerto. Puedes hablar con el maestro usando el mismo host y la misma configuración:
ssh -O check user@server
ssh -O cancel -L 127.0.0.1:8080:localhost:80 user@server
ssh -O exit user@server
Consulta multiplexación SSH para más detalles.
Preguntas
¿Cómo sé qué proceso usa un puerto?
En macOS y Linux ejecuta lsof -nP -iTCP:8080 -sTCP:LISTEN, o ss -ltnp en Linux. En Windows usa netstat -ano | findstr :8080. La salida muestra el programa y su PID.
¿Por qué SSH inicia sesión aunque la redirección de puertos haya fallado?
Por defecto, una redirección fallida es solo un aviso. Añade -o ExitOnForwardFailure=yes y ssh termina con estado 255, así los scripts se enteran.
¿Cómo cierro un túnel SSH que corre en segundo plano?
Busca su proceso ssh con lsof y ejecuta kill con su PID. Si pertenece a una conexión ControlMaster, usa ssh -O cancel o ssh -O exit con el mismo host.