Reputation: 11813
I wish to tunnel a port over SSH from a remote host. I wish to implement this as an oclif
plugin; I want the user experience to look like this:
laptop$ give-jupyter
http://localhost:4040/
laptop$ kill-jupyter
laptop$
...and that should be relatively straightforward; I just* need to maintain a pidfile, right? Something like:
import child_process from 'child_process';
const childProcess = child_process.spawn('ssh', [/* flags */], {detached: true, stdio: 'ignore'});
childProcess.unref();
writeToSomePidfile({childProcess.pid);
However, all of this is basically besides the point. The problem is I have to figure those flags out! Well, okay; this works:
laptop$ ssh machine -L 4040:localhost:4040
machine$
...however, it also opens a shell on the remote end. No problem, man ssh
says that's what -L
is for:
laptop$ ssh machine -LN 4040:localhost:4040
That's great, but it's now taking my user's shell hostage. Fine, let's just send the process to the background:
laptop$ ssh machine -LN 4040:localhost:4040 &
laptop$ f
f: file not found
laptop$ fg
^C
The background version of ssh
enters a race condition with the shell over STDIN
, and everything is positively terrible. Fine, man ssh
says that's what -n
is for:
laptop$ ssh machine -nLN 4040:localhost:4040 &
laptop$Job 1, 'ssh machine -nNL 40…' has ended
...well, that's just great: ssh
now quits immediately, and so does the tunnel.
SSH mentions -f
should enable some sort of background mode, but ssh -fnN
doesn't do it either; ssh
quits immediately still.
If I can't have nice things, maybe I can approximate them with a command that will run forever even with no STDIN. Server Fault suggests:
laptop$ ssh machine -nL 4040:localhost:4040 tail -f /dev/null &
laptop$
Still no good?! Fine:
laptop$ ssh machine -nL 4040:localhost:4040 sleep infinity &
laptop$
That seems to work at the low, low cost of one tiny process, a far sight better than other iterations I had tried while writing this questions, mostly involving yes
...
Is there however a... less kludgy way to run an SSH tunnel in the background? Bonus points: I need this to work on OSX laptops too...
Upvotes: 14
Views: 4672
Reputation: 2884
I'd personally create a file on the system that binds to the tunnel using -S
control socket. Easier than dealing with PIDs for sure.
ssh -M -S ~/jupyter-tunnel -o "ExitOnForwardFailure yes" -fN machine -L 4040:localhost:4040
ssh -S ~/jupyter-tunnel -O exit machine
Upvotes: 10