jupyter_safe_port
usage: jupyter_safe_port [-hcdf] {host} [port]
Discovers the next TCP port available for your notebook server and returns
execution instructions. If the argument '-c' is present and the requested
port is already bound on the remote host, return the SSH connection string
Positional arguments:
host host name or IP of remote system
port notebook server port to poll (default: 1024)
Arguments:
-h show this usage statement
-c only generate the SSH connection string
-d dump ports (useful in scripts)
format: local remote
-f apply SSH argument to daemonize session (i.e. ssh -f)
Install
./install.sh --prefix=/usr/local
Examples
Oh no! I need to run two notebook servers on a remote system but which ports should I use?
$ jupyter_safe_port example.lan
Execute on example.lan:
jupyter notebook --no-browser --port=1024
Connect via:
ssh -N -L1024:localhost:1024 user@example.lan
You start the first notebook server. Now run jupyter_safe_port again...
$ jupyter_safe_port example.lan
Execute on example.lan:
jupyter notebook --no-browser --port=1025
Connect via:
ssh -N -L1025:localhost:1025 user@example.lan
The local port 1024 is already bound to the first server so it gives you 1025. On the remote system, example.lan, port 1024 is bound too so it returns 1025 as well. What if you want to use a higher port number on example.lan? Let's see...
$ jupyter_safe_port example.lan 8080
Execute on example.lan:
jupyter notebook --no-browser --port=8081
Connect via:
ssh -N -L1026:localhost:8081 user@example.lan
Oops, you forgot about that web server test. 8080 is already bound so you're given 8081 instead. Locally 1024 and 1025 are already bound so jupyter_safe_port returns 1026.
Let's say you have closed your laptop and lost all of your connections. If you can remember the remote port you used then -c will get you up and running in no time...
$ jupyter_safe_port example.lan -c 8081
Connect via:
ssh -N -L1024:localhost:8081 user@example.lan
Scripting
You can use jupyter_safe_port in your scripts. -d returns the local port followed by the remote port.
$ jupyter_safe_port example.lan -d 8081
1024 8081
Here are a few ways to use it...
#!/usr/bin/env bash
interrupt() {
echo "Interrupted" >&2
exit 0
}
trap interrupt SIGINT SIGTERM
# System to spawn the notebook server on
server=example.lan
# Where is conda located? (Use single-quotes to avoid expanding ~ or variables)
conda_root='~/miniconda3'
# Conda environment to activate
environ=XYZ
# Configure port range (optional)
range_low=
range_high=
if ! [[ -x $(command -v "jupyter_safe_port") ]]; then
echo "jupyter_safe_port is not installed" >&2
exit 1
fi
result="$(jupyter_safe_port -d $server)"
if (( $? )) || [ -z "$result" ]; then
# jupyter_safe_port failed
# case 1: not enough arguments
# case 2: invalid argument
# case 3: invalid port range
# case 4: ssh failed to connect to $server
exit 1
fi
# Extract ports from result
read port_local port_remote <<< "$result"
if [[ -z "$port_local" ]] || [[ -z "$port_remote" ]]; then
# case 1: unhandled exception
exit 1
fi
if (( port_local < 0 )); then
# case 1: no local ports are available in range
exit 1
fi
if (( port_remote < 0 )); then
# case 1: no remote ports are available in range
# case 2: if using '-c', no service is present on the requested port
exit 1
fi
echo "Starting remote jupyter session on $server:$port_remote"
session="jupyter_${port_remote}"
ssh $server "bash -c 'tmux new-session -d -s $session \
\"source ~/.bash_profile \
&& source $conda_root/etc/profile.d/conda.sh \
&& conda activate $environ \
&& jupyter notebook --no-browser --port=$port_remote\"'"
if (( $? )); then
echo "Failed to connect to $server" >&2
exit 1
fi
echo "Remote tmux session name: $session"
echo
echo "To kill the tmux session and the jupyter notebook server:"
echo "ssh $server 'tmux kill-session -t $session'"
echo
# Forward the ports to the local system
echo "Forwarding $server:$port_remote to localhost:$port_local"
echo "To interrupt the session press: ctrl-c"
ssh -N -L$port_local:localhost:$port_remote $server
if (( $? )); then
echo "Failed to forward port." >&2
exit 1
fi
