App.show() Does Not Work When Using Jupyter Notebook Remotely

I installed Anaconda on a CentOS VM on an Ubuntu server. I then created a conda environment for all of my python data science libraries on this VM. I have a matching conda environment on my laptop.

I then followed this guide to allow me to perform data analytics on the server using a Jupyter notebook remotely on my laptop: https://amber-md.github.io/pytraj/latest/tutorials/remote_jupyter_notebook

I am able to successfully load my Jupyter notebook on my laptop and perform analytics on the server. I can also mark my completed app as .servable() in the notebook and then use panel serve --show ... on ther VM terminal to serve the completed interactive app to LAN users via a web browser.

My issue is that when I instead mark my app with .show() to allow me to view the app/report that I am currently working on in the notebook, I get the following message outputted: <bokeh.server.server.Server at 0x7faa92ef5590> but the app does not load in a new browser tab as expected.

How can I make app.show() work when using a Jupyter notebook remotely instead of locally?

I know that I need to specify the port to .show() and make sure the user can access that port on the remote server:

For the illustration of this question(not actuals), say my server VM is address 192.168.0.1 and my laptop is 192.168.0.2 and the port that I want to use with app.show() is 3333 .

  1. Setup the port:

On the server ( 192.168.0.1 ):

  • Check that port 3333 is not being used:
    sudo lsof -i:3333
  • Check that iptables aren’t showing the port as open:
    sudo iptables-save | grep 3333
  • Add the port to /etc/services file:
    sudo nano /etc/services
  • I added the following line to the top of the file and saved:
# service-name  port/protocol  [aliases ...]   [# comment]
bokeh-server    3333/tcp                        # Open port to allow app.show() to work on a remotely executed Jupyter Notebook
  • Enable the firewall:
    sudo systemctl enable firewalld

  • Start the firewall:
    sudo systemctl start firewalld

  • Check the status of the firewall:
    sudo systemctl status firewalld

  • Confirm that this port is now open: sudo iptables-save | grep 3333
    Output:
    -A IN_public_allow -p tcp -m tcp --dport 3333 -m conntrack --ctstate NEW -j ACCEPT

  1. Test that the user can access the port on the server:

I installed ncat on the server ( 192.168.0.1 ):
sudo yum install nmap-ncat -y

Then I set up messaging between the server and my laptop:

  • On server:
    nc -l 3333
  • On laptop:
    nc 192.168.0.1 3333

and also between the laptop and the server:

  • On laptop:
    nc -l 3333
  • On server:
    nc 192.168.0.2 3333
  • Messages successfully make it from server to laptop and vice versa.
  • Confirmation of these two connections:
    sudo lsof -i:3333

which outputted:

COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      1776       XXX    5u  IPv4  23627      0t0  TCP vmserver:bokeh-server->192.168.0.2:55358 (ESTABLISHED)
nc      1846       XXX    3u  IPv4  22895      0t0  TCP vmserver:33658->192.168.0.2:bokeh-server (ESTABLISHED)

showing that the server on port 3333 can communicate with the laptop on a different port and the laptop on port 3333 can communicate with the server on a different port.

I’m not sure how to make them connect on the same port though? ie both on port 3333? Is this the source of my issue?

  1. Then in my jupyter notebook, I replaced app.show() with
app.show(port=3333, websocket_origin=None, threaded=False)

However I am still experiencing the same behaviour as previously in that the app does not load in a new browser tab as expected.

I then experimented with parameters websocket_origin (tried “192.168.0.1”,“192.168.0.2” and “*”) and threaded (True/False) but changing these didn’t give my desired result of the app loading in a new browser tab.

A couple of interesting points :

  1. If I run my notebook which executes
app.show(port=3333, websocket_origin=None, threaded=False)

and then on the server run:
sudo lsof -i:3333
then the following is returned:

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ZMQbg/1 19328 xxx   45u  IPv4  83214      0t0  TCP *:bokeh-server (LISTEN)
ZMQbg/1 19328 xxx   54u  IPv6  83215      0t0  TCP *:bokeh-server (LISTEN)

It seems like the server is waiting for something to happen on port 3333? ie LISTEN ? Unlike when I was messaging between the server and my laptop (and vice versa) there doesn’t actually seem to be an ESTABLISHED connection though.

Please note that those 2 lines above only appear after I run the notebook.

  1. After I have executed my notebook (and the app in the new tab hasn’t opened), if I try to execute the notebook again then I get this warning in my jupyter notebook: OSError: [Errno 98] Address already in use

So it does seem like the connection between the server and laptop has been ESTABLISHED or at very least reserved? To fix this, I then have to close the connection to my server and then on my laptop run the command: lsof -ti:8888 | xargs kill -1 before then reestablishing my connection between the server and my laptop as per https://amber-md.github.io/pytraj/latest/tutorials/remote_jupyter_notebook

As is probably obvious, I am no sysadmin and I’m really at the limits of my knowledge here!

If anyone has any advice or pointers as to how to get this working then I would be massively grateful.

Edit:
The more I look at this the more I think it may be down to my ssh settings rather than Panel itself - I’ll have a play with some different ssh settings tomorrow and will report back if I have any luck getting it working.


Software versions on the conda environment on the VM:

# Name                    Version                   Build  Channel
_anaconda_depends         2019.03                  py37_0  
_libgcc_mutex             0.1                        main  
alabaster                 0.7.12                   py37_0  
anaconda                  custom                   py37_1  
anaconda-client           1.7.2                    py37_0  
anaconda-project          0.8.4                      py_0  
arrow-cpp                 0.11.1          py37h0e61e49_1004    conda-forge
asn1crypto                1.3.0                    py37_0  
astroid                   2.3.3                    py37_0  
astropy                   4.0              py37h7b6447c_0  
atomicwrites              1.3.0                    py37_1  
attrs                     19.3.0                     py_0  
babel                     2.8.0                      py_0  
backcall                  0.1.0                    py37_0  
backports                 1.0                        py_2  
backports.os              0.1.1                    py37_0  
backports.shutil_get_terminal_size 1.0.0                    py37_2  
beautifulsoup4            4.8.2                    py37_0  
bitarray                  1.2.0            py37h7b6447c_0  
bkcharts                  0.2                      py37_0  
blas                      1.0                         mkl  
bleach                    3.1.0                    py37_0  
blosc                     1.16.3               hd408876_0  
bokeh                     1.4.0                    py37_0  
boost-cpp                 1.68.0            h11c811c_1000    conda-forge
boto                      2.49.0                   py37_0  
bottleneck                1.3.1            py37hdd07704_0  
bzip2                     1.0.8                h7b6447c_0  
ca-certificates           2019.11.28           hecc5488_0    conda-forge
cairo                     1.14.12              h8948797_3  
cartopy                   0.17.0           py37hbb7e04d_1  
certifi                   2019.11.28               py37_0  
cffi                      1.13.2           py37h2e261b9_0  
cftime                    1.0.4.2          py37hdd07704_0