Jupyterhub with SageMath Kernel

Date: March 4, 2016
Tags: software, SageMath, jupyterhub

Recently I made some efforts to get a Jupyterhub instance with a SageMath kernel up and running on one of my servers β€” with success! πŸ™‚ Actually, the installation is really not that difficult. Nevertheless, I want to write a few lines describing the troubles I ran into and my solutions.

Installing Dependencies

The dependencies of Jupyterhub are well-explained on their github page, and their installation should not result in big trouble. However, as my server runs CentOS 7.2, I had to compile a recent Python version by myself:

~ $ sudo yum groupinstall "Development tools"
~ $ sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
~ $ wget http://python.org/ftp/python/3.5.1/Python-3.5.1.tar.xz
~ $ tar xf Python-3.5.1.tar.xz
~ $ cd Python-3.5.1
~/Python-3.5.1 $ ./configure --prefix=/usr/local --enable-shared
~/Python-3.5.1 $ make
~/Python-3.5.1 $ sudo make install

Then, in order to find the library, you have to add the line /usr/local/lib to /etc/ld.so.conf.d/local.conf and reload the config by calling ldconfig. These steps (usually) have to be completed as root. Afterwards, Python 3.5.1 should be installed (you can check with python3.5 -V or pip3.5 -V).

The goal of these steps was to obtain a useable installation of pip.

The installation of the second dependency, the node package manager β€œnpm” was straightforward:

~ $ sudo yum install npm.noarch
~ $ sudo npm install -g configurable-http-proxy

Installation of Jupyterhub and linking the SageMath kernel

The next part is really easy: Jupyterhub (together with the notebook) can be installed with the help of pip just by calling

~ $ sudo pip install jupyterhub
~ $ sudo pip install notebook

The available kernels then can be listed with jupyter-kernelspec:

~ $ jupyter-kernelspec list
Available kernels:
  python3     /usr/local/lib/python3.5/site-packages/ipykernel/resources

In order to add a SageMath-kernel to your installation, you first need a working Sage install. For example, I’ve installed sage-6.10 in the /opt-directory, so that I can run Sage by calling

~ $ /opt/sage-6.10/sage
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ SageMath Version 6.10, Release Date: 2015-12-18                    β”‚
β”‚ Type "notebook()" for the browser-based notebook interface.        β”‚
β”‚ Type "help()" for help.                                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
sage:

Then, all that needs to be done is linking the kernel into a directory, where Jupyter is aware of them:

~ $ sudo mkdir -p /usr/local/share/jupyter/kernels
~ $ cd /usr/local/share/jupyter/kernels
/usr/local/share/jupyter/kernels $ sudo ln -s /opt/sage-6.10/local/share/jupyter/kernels/sagemath

After linking the kernel, jupyter-kernelspec list should already list the new kernel like this:

~ $ jupyter-kernelspec list
Available kernels:
  python3     /usr/local/lib/python3.5/site-packages/ipykernel/resources
  sagemath    /usr/local/share/jupyter/kernels/sagemath

Note: Some versions of SageMath require editing the kernel.json file (which can be found in the folder /path/to/sage/local/share/jupyter/kernels/sagemath) such that the environment variable SAGE_ROOT is set. In this example here, this means adding the line

"env": { "SAGE_ROOT": "/opt/sage-6.10" },

to the kernel.json file. This step is required if the error

Error: You must set the SAGE_ROOT environment variable or run this
script from the SAGE_ROOT or SAGE_ROOT/local/bin/ directory.
Error setting environment variables by sourcing β€˜/opt/sage-6.10/local/bin/sage-env’;
possibly contact sage-devel (see http://groups.google.com/group/sage-devel).

appears when trying to start the SageMath kernel. (Thanks to Clemens Heuberger for pointing this out!)

Configuring the Webserver

In my case, I configured Jupyterhub to run behind a reverse proxy, powered by an Apache web server, such that the service can be reached from a subdomain like https://jupyter.example.com.

First, note that Jupyterhub can be started just by using the command jupyterhub. With jupyterhub --port 98765, you can run the serivce at localhost:98765. The complicated part with the Apache configuration is that you also have to take care of the websockets β€” otherwise the kernels are not able to connect. The following snippet comes from my Apache configuration:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName jupyter.example.com
    ProxyPass / http://localhost:98765/
    ProxyPassReverse / http://localhost:98765/

    Header edit Origin "jupyter.example.com" localhost:98765
    RequestHeader edit Origin "jupyter.example.com" localhost:98765

    Header edit Referer "jupyter.example.com" localhost:98765
    RequestHeader edit Referer "jupyter.example.com" localhost:98765
    <Location ~ "/(user/[^/]*)/(api/kernels/[^/]+/channels|terminals/websocket)/?">
            ProxyPass ws://localhost:98765
            ProxyPassReverse ws://localhost:98765
    </Location>

    # [... SSL Stuff etc ...]

</VirtualHost>

</IfModule>

And finally, in order to have Jupyterhub in a systemd-setting, I’ve put the following into /usr/lib/systemd/system/jupyterhub.service:

[Unit]
Description=Jupyterhub

[Service]
User=root
ExecStart=/usr/local/bin/jupyterhub --port 98765

[Install]
WantedBy=multi-user.target

… and that’s it! The service can then be started by reloading the configuration via sudo systemctl daemon-reload and sudo systemctl start jupyterhub.service.