Multi-hop tunnel in the background; killing local tunnel does not kill remote tunnel


Multi-hop tunnel:

I am opening a tunnel to a remote server via a jump server.

ssh ${JUMP_HOST} -l ${JUMP_HOST_USER} -L ${PORT}:localhost:${PORT} \
    ssh ${REMOTE_HOST} -l ${REMOTE_HOST_USER} -L ${PORT}:localhost:${PORT}

Now when I open a connection to localhost:port it will forward to jump:port which in turn will forward to remote:port

Run local tunnel in background:

The problem with this is that it opens a shell on remote, whereas I just want the tunnel to run in the background.

So I add the -f option to my local tunnel to request it run in the background

ssh -f ${JUMP_HOST} -l ${JUMP_HOST_USER} -L ${PORT}:localhost:${PORT} \
    ssh ${REMOTE_HOST} -l ${REMOTE_HOST_USER} -L ${PORT}:localhost:${PORT}

This, however, returns an error:

Pseudo-terminal will not be allocated because stdin is not a terminal.

Presumably this error is coming from the tunnel from jump to remote, and is caused because stdin is closed when my local tunnel is daemonized.

Tell remote tunnel I won't be running a command:

I then tried running the jump-> remote tunnel with -N to tell it I'm not going to be running a remote command.

ssh -f ${JUMP_HOST} -l ${JUMP_HOST_USER} -L ${PORT}:localhost:${PORT} \
    ssh -N ${REMOTE_HOST} -l ${REMOTE_HOST_USER} -L ${PORT}:localhost:${PORT}

This works great – the tunnel runs in the background and I can connect successfully to remote:port by connecting to localhost:port.


The problem I'm having is when I want to close the tunnels.

If I send a kill signal to my local ssh tunnel's pid, it will close, but the ssh tunnel running on jump remains running.

It seems that when I daemonize my local tunnel, the tunnel on jump is also daemonized.


Is it possible to run my local tunnel in the background, but when I kill it, have it shut down all the tunnels it has spawned on all remote servers?

Best Answer

Run both ssh-s locally. First connect to the jump server and create a tunnel that will allow you to ssh to the remote host from the local computer:

ssh -fN $jump_host -l $jump_host_user -L ${helper_port}:${remote_host}:22

Then use this tunnel to connect to the remote host, creating the desired tunnel; still from the local computer:

ssh -fN localhost -p $helper_port -l ${remote_host_user} -L ${port}:localhost:${port}

Since the two ssh processes are local, you can kill them both whenever you like; but I think killing the first one should be enough, try it.


  • This approach may be inconvenient if your "secondary" ssh relies on specific config stored in ssh_config on the jump host.
  • I used lowercase variable names; see this answer.