JupyterHub brings multi-user support to the Jupyter Notebook.
More specifically, JupyterHub is a multi-user server that manages and proxies multiple instances of the single-user IPython Jupyter notebook server.
If you have a multi-user authentication system in place already, JupyterHub lets you use that authentication for controlling Jupyter Notebook access. For example, a school’s authentication system can be used to allow students to log into the JupyterHub using their student credentials. The individual Notebook server will then run using the student’s credentials and only have access to resources that the student has access to.
Three pieces are required for the hub to work: the configurable http proxy, the hub itself, and single Jupyter Notebook servers.
The configurable http proxy is the entry point for all HTTP requests. The initial requests will be proxied to the hub, which handles authentication. Once the user authenticates and requests a notebook server, the hub launches the notebook server and registers a redirect in the configurable http proxy for that user’s name. Requests under that user’s name are then redirected to their own single notebook server, instead of the hub.
The configurable HTTP proxy is written in JavaScript. However, it does not run inside a web browser, instead it runs in a JavaScript interpreter called Node.js. Node.js is a standalone JavaScript interpreter and environment based on the v8 Javascript engine that powers Google Chrome.
Like the Python community, the JavaScript community has it’s own package management solution. NPM, short for Node Package Manager, is the package manager used to install node.js libraries. NPM behaves differently from Python packaging in that packages are downloaded and installed in the current working directory, unless you explicitly ask it to install globally, using the -g flag.
When developing browser facing JavaScript, there is another package manager called Bower. Bower differs from NPM in that Bower downloads and installs packages in a flat structure, whereas NPM downloads and installs packages in a hierarchy.
The first step is to install Node. You can find an installer for your operating system at their website, https://nodejs.org/. NPM will automatically install with Node.
On Ubuntu/Debian, you can install Node from apt:
sudo apt-get install nodejs-legacy npm
Next, install the configurable http proxy globally by running:
sudo npm install -g configurable-http-proxy
The -g flag installs it globally.
Next, clone the JupyterHub repository:
git clone https://github.com/jupyter/jupyterhub.git
Install JupyterHub’s JavaScript dependencies. First navigate into the freshly cloned repository, cd jupyterhub. Then run:
python3 setup.py js css
Install JupyterHub’s Python dependencies, and Jupyterhub itself, by running:
pip3 install -r requirements.txt
pip3 install .
If everything worked, you should be able to launch JupyterHub by running jupyterhub. Open a web browser and navigate to http://localhost:8000/ to test. You should be able to login using local system credentials.
By default JupyterHub uses PAM - the Unix system authentication - to authenticate users. However, the authentication is configurable. A popular replacement for PAM is the GitHub OAuth plugin, which allows uses to sign in using their GitHub account.
To install GitHub OAuth, first clone the repository:
git clone https://github.com/jupyter/oauthenticator.git
Then navigate into the new directory cd oauthenticator and install the requirements, and oauthenticator itself:
pip3 install -r requirements.txt
pip3 install .
Next, you need to register a GitHub application. The important part here is that the Authorization callback URL is http://localhost:8000/hub/oauth_callback.
Navigate to the directory that you will launch jupyterhub from, I suggest your home directory cd ~. Create a hub configuration file by running:
jupyterhub --generate-config
This should create a jupyterhub_config.py in the current directoy. Anytime you launch the hub, it looks in the current directory to see if a file by that name exists. If it does, it loads it as the configuration file.
Open the new configuration file and add the following lines:
c.JupyterHub.authenticator_class = 'oauthenticator.GitHubOAuthenticator'
c.GitHubOAuthenticator.oauth_callback_url = '' # Fill these in from Github
c.GitHubOAuthenticator.github_client_id = ''
c.GitHubOAuthenticator.github_client_secret = ''
The last 3 values you will need to get from the GitHub application you set-up earlier. Now run JupyterHub and try logging in. You should be able to log on, but when you try to launch a server, you’ll probably see an error. This is because a local user by the same name of the GitHub account isn’t registered on your machine.
To test the GitHub authentication completely, you will install a custom spawner which launches the single user servers in docker containers. This allows any user to login safely without causing harm to your machine beyond what can be done in the container.
First clone the dockerspawner:
git clone https://github.com/jupyter/dockerspawner.git
Then navigate into the directory: cd dockerspawner.
Install the dependencies and the project itself:
pip3 install -r requirements.txt
pip3 install .
Now, open the jupyterhub_config.py file that you created earlier, and add the following line to it:
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
Save and close the file.
Install boot2docker via the instructions for your operating system at https://docs.docker.com/installation. Start boot2docker by running:
boot2docker init
boot2docker up
You should see output that reads To connect the Docker client to the Docker daemon, please set... and below it will be some commands. Run those commands. Then download the single user server image:
docker pull jupyter/singleuser
Don't try to do this in the tutorial - the docker image is about 1GB, so it would probably demolish the wifi.
You should now be able to run jupyterhub from your home directory (or wherever your config file is) and login in using GitHub credentials to launch a server inside a docker container.
In [1]:
%%html
<link rel="stylesheet" type="text/css" href="../style.css">
<script>require(['notebook/js/scrollmanager'], function(sm) { IPython.notebook.scroll_manager = new sm.SlideScrollManager(IPython.notebook); });</script>