Ricardo's Place Robotics, machine learning, or simply random thoughts!

Running a Jupyter Notebook (IPython) on a remote server

Do you know what is a Jupyter Notebook? If you don’t, please, have a look at the previous link and come back later… just joking… ok, seriously, check the previous link because they will do a much better job explaining what is a Jupyter Notebook than me :wink:.

jupyter notebook
This is what I was doing just before start writing this post.

Why do I love those notebooks? Probably it’s started long time ago while I still was a Mathematica, Maple and MuPad user, but I would say I like notebooks mainly because I can keep, in one place, code, comments (pure text, Markdown, HTML, LaTeX, animations, external images/videos, etc) and, the most important, results. I can also easily share things by exporting a notebook as HTML or PDF or uploading it to a place where there’s a notebook viewer (you can see an example here). I’ve never tested Jupyter with other languages but Python, so I will tell you about my experiences using Python. In the past, Jupyter notebooks used to be called IPython notebooks, therefore it was Python only. However, currently it supports more than 40 programming languages including Python, R, Julia, Ruby and Scala (this is the first time I’ve read about Scala…).

Ok, let’s make a list of the things we want to learn here:

  • Launch a Jupyter Notebook server without automatically opening a browser.
  • Create a SSH tunnel to redirect a local port to the server.
  • Access your remote server from your browser.

Jupyter is capable to serve, just like a web server, notebooks directly to any browser. They give you full instructions here. The problem with that solution, in my opinion, is the complexity. If you just carelessly open things, you are going to expose your server :scream:.

To launch the Jupyter Notebook server (on the remote computer) and keep it running after we logout, we will need help from our friend nohup. Nohup allows us to logout without killing the processes our terminal started and the ampersand (&) sends nohup to the background freeing the terminal (in case you want to do something else after launching it…). The command to launch the notebook without also launching the web browser (even if you are accessing it remotely through ssh using the -X option to redirect the display, it would be a waste of resources and time):

$ nohup jupyter notebook --no-browser &
Caveat: You will only be able to access files (and subdirs) located on the current directory.

After that, you can disconnect from the remote computer, open a terminal on the client computer and type this (more details about the ssh tunneling magic can be found here):

$ ssh -nNT -L 9999:localhost:8888 user@example.com

The command line above has only two things you surely must change: user is the username at the remote computer and example.com will probably be replaced by the remote computer’s IP address. Now we have created a tunnel that will redirect the port 9999 to the remote server port 8888 (this is the default used by Jupyter). I’m using the port number 9999 because, usually, I also have a local Jupyter Notebook server running at 8888.

The only thing you need to do now is launch your browser and access the url localhost:8888 localhost:9999 and done, you have got a remote Jupyter Notebook working!

Recalling the list at the beginning of this post:

  • Launch a Jupyter Notebook server without automatically opening a browser.
  • Create a SSH tunnel to redirect a local port to the server.
  • Access your remote server from your browser.

UPDATE (05/03/2017):

If you execute the command:

$ ssh -nNT -L 9999:localhost:8888 user@example.com

You will be capable to access the port 8888 from example.com, on your local machine, using localhost:9999. However, if you want to allow other machines to easily access that port too, it will not be possible. I had this problem last week when I was trying to show some contents on Pepper’s tablet through a very simple Python web server hosted on a virtual machine. My team from NAO Hackathon was in a hurry and I could not make the redirection work (I should have read the manual:disappointed:). Ok, so there are at least three possible solutions. The first one will work if your computer (the client here) has only one network address:

$ ssh -nNT -L :9999:localhost:8888 user@example.com

If your computer has more than one network adapter, you can bind an IP (forcing the tunnel only through the bound IP) using this command (the second possible solution):

$ ssh -nNT -L ip_you_want_to_bind:9999:localhost:8888 user@example.com

The third possibility (SSH-BASED VIRTUAL PRIVATE NETWORKS) can be found on the ssh manual webpage (or, in case you want a more straightforward link, here) and it involves more than one command line (the -f argument only sends ssh to background) and you will need to mess with ifconfig and route. I’m not sure if route works the same on all Unix flavours, but apparently it does. I think this last solution is a more robust one when the connection is supposed to be perpetual instead of something to run during some minutes only.

UPDATE (11/03/2017):

When you redirect the port using the commands I’ve presented above, you must call %matplotlib inline if you want to generate plots or you will also need to redirect the display, but this may not be available if the external server doesn’t have a screen (ok, you could use this). ssh is full of useful tricks :wink:.