Compare commits

..

4 Commits
1.2.2 ... 0.9.3

Author SHA1 Message Date
Min RK
e94f5e043a release 0.9.3 2018-09-12 09:46:02 +02:00
Min RK
5456fb6356 remove spurious print from keepalive code
and send keepalive every 8 seconds

to protect against possibly aggressive proxies dropping connections after 10 seconds of inactivity
2018-09-12 09:46:02 +02:00
Min RK
fb75b9a392 write needs no await 2018-09-11 16:42:29 +02:00
Min RK
90d341e6f7 changelog for 0.9.3
Mainly small fixes, but the token page could be completely broken

This release will include the spawner.handler addition,
but not the oauthlib change currently in master
2018-09-11 16:42:21 +02:00
249 changed files with 6401 additions and 16490 deletions

View File

@@ -19,15 +19,3 @@ jobs:
name: smoke test jupyterhub
command: |
docker run --rm -it jupyterhub/jupyterhub jupyterhub --help
- run:
name: verify static files
command: |
docker run --rm -it -v $PWD/dockerfiles:/io jupyterhub/jupyterhub python3 /io/test.py
# Tell CircleCI to use this workflow when it builds the site
workflows:
version: 2
default:
jobs:
- build

View File

@@ -1,5 +1,4 @@
[run]
parallel = True
branch = False
omit =
jupyterhub/tests/*

View File

@@ -10,12 +10,13 @@
# E402: module level import not at top of file
# I100: Import statements are in the wrong order
# I101: Imported names are in the wrong order. Should be
ignore = E, C, W, F401, F403, F811, F841, E402, I100, I101, D400
builtins = c, get_config
ignore = E, C, W, F401, F403, F811, F841, E402, I100, I101
exclude =
.cache,
.github,
docs,
examples,
jupyterhub/alembic*,
onbuild,
scripts,

37
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,37 @@
---
name: Bug report
about: Create a report to help us improve
---
Hi! Thanks for using JupyterHub.
If you are reporting an issue with JupyterHub, please use the [GitHub issue](https://github.com/jupyterhub/jupyterhub/issues) search feature to check if your issue has been asked already. If it has, please add your comments to the existing issue.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
- Running `jupyter troubleshoot` from the command line, if possible, and posting
its output would also be helpful.
- Running in `--debug` mode can also be helpful for troubleshooting.

View File

@@ -0,0 +1,7 @@
---
name: Installation and configuration issues
about: Installation and configuration assistance
---
If you are having issues with installation or configuration, you may ask for help on the JupyterHub gitter channel or file an issue here.

View File

@@ -1,206 +0,0 @@
# This is a GitHub workflow defining a set of jobs with a set of steps.
# ref: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions
#
name: Run tests
# Trigger the workflow's on all PRs but only on pushed tags or commits to
# main/master branch to avoid PRs developed in a GitHub fork's dedicated branch
# to trigger.
on:
pull_request:
push:
defaults:
run:
# Declare bash be used by default in this workflow's "run" steps.
#
# NOTE: bash will by default run with:
# --noprofile: Ignore ~/.profile etc.
# --norc: Ignore ~/.bashrc etc.
# -e: Exit directly on errors
# -o pipefail: Don't mask errors from a command piped into another command
shell: bash
env:
# UTF-8 content may be interpreted as ascii and causes errors without this.
LANG: C.UTF-8
jobs:
# Run "pre-commit run --all-files"
pre-commit:
runs-on: ubuntu-20.04
timeout-minutes: 2
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.8
# ref: https://github.com/pre-commit/action
- uses: pre-commit/action@v2.0.0
- name: Help message if pre-commit fail
if: ${{ failure() }}
run: |
echo "You can install pre-commit hooks to automatically run formatting"
echo "on each commit with:"
echo " pre-commit install"
echo "or you can run by hand on staged files with"
echo " pre-commit run"
echo "or after-the-fact on already committed files with"
echo " pre-commit run --all-files"
# Run "pytest jupyterhub/tests" in various configurations
pytest:
runs-on: ubuntu-20.04
timeout-minutes: 10
strategy:
# Keep running even if one variation of the job fail
fail-fast: false
matrix:
# We run this job multiple times with different parameterization
# specified below, these parameters have no meaning on their own and
# gain meaning on how job steps use them.
#
# subdomain:
# Tests everything when JupyterHub is configured to add routes for
# users with dedicated subdomains like user1.jupyter.example.com
# rather than jupyter.example.com/user/user1.
#
# db: [mysql/postgres]
# Tests everything when JupyterHub works against a dedicated mysql or
# postgresql server.
#
# jupyter_server:
# Tests everything when the user instances are started with
# jupyter_server instead of notebook.
#
# main_dependencies:
# Tests everything when the we use the latest available dependencies
# from: ipytraitlets.
#
# NOTE: Since only the value of these parameters are presented in the
# GitHub UI when the workflow run, we avoid using true/false as
# values by instead duplicating the name to signal true.
include:
- python: "3.6"
subdomain: subdomain
- python: "3.7"
db: mysql
- python: "3.8"
db: postgres
- python: "3.8"
jupyter_server: jupyter_server
- python: "3.9"
main_dependencies: main_dependencies
steps:
# NOTE: In GitHub workflows, environment variables are set by writing
# assignment statements to a file. They will be set in the following
# steps as if would used `export MY_ENV=my-value`.
- name: Configure environment variables
run: |
if [ "${{ matrix.subdomain }}" != "" ]; then
echo "JUPYTERHUB_TEST_SUBDOMAIN_HOST=http://localhost.jovyan.org:8000" >> $GITHUB_ENV
fi
if [ "${{ matrix.db }}" == "mysql" ]; then
echo "MYSQL_HOST=127.0.0.1" >> $GITHUB_ENV
echo "JUPYTERHUB_TEST_DB_URL=mysql+mysqlconnector://root@127.0.0.1:3306/jupyterhub" >> $GITHUB_ENV
fi
if [ "${{ matrix.db }}" == "postgres" ]; then
echo "PGHOST=127.0.0.1" >> $GITHUB_ENV
echo "PGUSER=test_user" >> $GITHUB_ENV
echo "PGPASSWORD=hub[test/:?" >> $GITHUB_ENV
echo "JUPYTERHUB_TEST_DB_URL=postgresql://test_user:hub%5Btest%2F%3A%3F@127.0.0.1:5432/jupyterhub" >> $GITHUB_ENV
fi
if [ "${{ matrix.jupyter_server }}" != "" ]; then
echo "JUPYTERHUB_SINGLEUSER_APP=jupyterhub.tests.mockserverapp.MockServerApp" >> $GITHUB_ENV
fi
- uses: actions/checkout@v2
# NOTE: actions/setup-node@v1 make use of a cache within the GitHub base
# environment and setup in a fraction of a second.
- name: Install Node v14
uses: actions/setup-node@v1
with:
node-version: "14"
- name: Install Node dependencies
run: |
npm install
npm install -g configurable-http-proxy
npm list
# NOTE: actions/setup-python@v2 make use of a cache within the GitHub base
# environment and setup in a fraction of a second.
- name: Install Python ${{ matrix.python }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install --upgrade . -r dev-requirements.txt
if [ "${{ matrix.main_dependencies }}" != "" ]; then
pip install git+https://github.com/ipython/traitlets#egg=traitlets --force
fi
if [ "${{ matrix.jupyter_server }}" != "" ]; then
pip uninstall notebook --yes
pip install jupyter_server
fi
if [ "${{ matrix.db }}" == "mysql" ]; then
pip install mysql-connector-python
fi
if [ "${{ matrix.db }}" == "postgres" ]; then
pip install psycopg2-binary
fi
pip freeze
# NOTE: If you need to debug this DB setup step, consider the following.
#
# 1. mysql/postgressql are database servers we start as docker containers,
# and we use clients named mysql/psql.
#
# 2. When we start a database server we need to pass environment variables
# explicitly as part of the `docker run` command. These environment
# variables are named differently from the similarly named environment
# variables used by the clients.
#
# - mysql server ref: https://hub.docker.com/_/mysql/
# - mysql client ref: https://dev.mysql.com/doc/refman/5.7/en/environment-variables.html
# - postgres server ref: https://hub.docker.com/_/postgres/
# - psql client ref: https://www.postgresql.org/docs/9.5/libpq-envars.html
#
# 3. When we connect, they should use 127.0.0.1 rather than the
# default way of connecting which leads to errors like below both for
# mysql and postgresql unless we set MYSQL_HOST/PGHOST to 127.0.0.1.
#
# - ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
#
- name: Start a database server (${{ matrix.db }})
if: ${{ matrix.db }}
run: |
if [ "${{ matrix.db }}" == "mysql" ]; then
sudo apt-get update
sudo apt-get install -y mysql-client
DB=mysql bash ci/docker-db.sh
DB=mysql bash ci/init-db.sh
fi
if [ "${{ matrix.db }}" == "postgres" ]; then
sudo apt-get update
sudo apt-get install -y postgresql-client
DB=postgres bash ci/docker-db.sh
DB=postgres bash ci/init-db.sh
fi
- name: Run pytest
# FIXME: --color=yes explicitly set because:
# https://github.com/actions/runner/issues/241
run: |
pytest -v --maxfail=2 --color=yes --cov=jupyterhub jupyterhub/tests
- name: Submit codecov report
run: |
codecov

4
.gitignore vendored
View File

@@ -21,10 +21,6 @@ share/jupyterhub/static/css/style.min.css.map
*.egg-info
MANIFEST
.coverage
.coverage.*
htmlcov
.idea/
.vscode/
.pytest_cache
pip-wheel-metadata
docs/source/reference/metrics.rst

View File

@@ -1,19 +0,0 @@
repos:
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.9.0
hooks:
- id: reorder-python-imports
- repo: https://github.com/psf/black
rev: 19.10b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: end-of-file-fixer
- id: check-json
- id: check-yaml
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: requirements-txt-fixer
- id: flake8

68
.travis.yml Normal file
View File

@@ -0,0 +1,68 @@
language: python
sudo: false
cache:
- pip
python:
- 3.6
- 3.5
- nightly
env:
global:
- ASYNC_TEST_TIMEOUT=15
- MYSQL_HOST=127.0.0.1
- MYSQL_TCP_PORT=13306
services:
- postgres
- docker
# installing dependencies
before_install:
- nvm install 6; nvm use 6
- npm install
- npm install -g configurable-http-proxy
- |
# setup database
if [[ $JUPYTERHUB_TEST_DB_URL == mysql* ]]; then
unset MYSQL_UNIX_PORT
DB=mysql bash ci/docker-db.sh
DB=mysql bash ci/init-db.sh
pip install 'mysql-connector<2.2'
elif [[ $JUPYTERHUB_TEST_DB_URL == postgresql* ]]; then
DB=postgres bash ci/init-db.sh
pip install psycopg2-binary
fi
install:
- pip install --upgrade pip
- pip install --pre -r dev-requirements.txt .
- pip freeze
# running tests
script:
- |
# run tests
set -e
pytest -v --maxfail=2 --cov=jupyterhub jupyterhub/tests
- |
# build docs
pushd docs
pip install -r requirements.txt
make html
popd
after_success:
- codecov
matrix:
fast_finish: true
include:
- python: 3.6
env: JUPYTERHUB_TEST_SUBDOMAIN_HOST=http://localhost.jovyan.org:8000
- python: 3.6
env:
- JUPYTERHUB_TEST_DB_URL=mysql+mysqlconnector://root@127.0.0.1:$MYSQL_TCP_PORT/jupyterhub
- python: 3.6
env:
- JUPYTERHUB_TEST_DB_URL=postgresql://postgres@127.0.0.1/jupyterhub
- python: 3.7
dist: xenial
allow_failures:
- python: nightly

View File

@@ -1,137 +1,98 @@
# Contributing to JupyterHub
# Contributing
Welcome! As a [Jupyter](https://jupyter.org) project,
you can follow the [Jupyter contributor guide](https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html).
Make sure to also follow [Project Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md)
for a friendly and welcoming collaborative environment.
## Setting up a development environment
<!--
https://jupyterhub.readthedocs.io/en/stable/contributing/setup.html
contains a lot of the same information. Should we merge the docs and
just have this page link to that one?
-->
JupyterHub requires Python >= 3.5 and nodejs.
As a Python project, a development install of JupyterHub follows standard practices for the basics (steps 1-2).
Welcome! As a [Jupyter](https://jupyter.org) project, we follow the [Jupyter contributor guide](https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html).
1. clone the repo
```bash
git clone https://github.com/jupyterhub/jupyterhub
```
2. do a development install with pip
## Set up your development system
```bash
cd jupyterhub
python3 -m pip install --editable .
```
3. install the development requirements,
which include things like testing tools
```bash
python3 -m pip install -r dev-requirements.txt
```
4. install configurable-http-proxy with npm:
```bash
npm install -g configurable-http-proxy
```
5. set up pre-commit hooks for automatic code formatting, etc.
```bash
pre-commit install
```
You can also invoke the pre-commit hook manually at any time with
```bash
pre-commit run
```
## Contributing
JupyterHub has adopted automatic code formatting so you shouldn't
need to worry too much about your code style.
As long as your code is valid,
the pre-commit hook should take care of how it should look.
You can invoke the pre-commit hook by hand at any time with:
For a development install, clone the [repository](https://github.com/jupyterhub/jupyterhub)
and then install from source:
```bash
pre-commit run
git clone https://github.com/jupyterhub/jupyterhub
cd jupyterhub
npm install -g configurable-http-proxy
pip3 install -r dev-requirements.txt -e .
```
which should run any autoformatting on your code
and tell you about any errors it couldn't fix automatically.
You may also install [black integration](https://github.com/psf/black#editor-integration)
into your text editor to format code automatically.
### Troubleshooting a development install
If you have already committed files before setting up the pre-commit
hook with `pre-commit install`, you can fix everything up using
`pre-commit run --all-files`. You need to make the fixing commit
yourself after that.
If the `pip3 install` command fails and complains about `lessc` being
unavailable, you may need to explicitly install some additional JavaScript
dependencies:
## Testing
npm install
It's a good idea to write tests to exercise any new features,
or that trigger any bugs that you have fixed to catch regressions.
This will fetch client-side JavaScript dependencies necessary to compile CSS.
You can run the tests with:
You may also need to manually update JavaScript and CSS after some development
updates, with:
```bash
pytest -v
python3 setup.py js # fetch updated client-side js
python3 setup.py css # recompile CSS from LESS sources
```
in the repo directory. If you want to just run certain tests,
check out the [pytest docs](https://pytest.readthedocs.io/en/latest/usage.html)
for how pytest can be called.
For instance, to test only spawner-related things in the REST API:
## Running the test suite
We use [pytest](http://doc.pytest.org/en/latest/) for running tests.
1. Set up a development install as described above.
2. Set environment variable for `ASYNC_TEST_TIMEOUT` to 15 seconds:
```bash
pytest -v -k spawn jupyterhub/tests/test_api.py
export ASYNC_TEST_TIMEOUT=15
```
The tests live in `jupyterhub/tests` and are organized roughly into:
3. Run tests.
1. `test_api.py` tests the REST API
2. `test_pages.py` tests loading the HTML pages
To run all the tests:
and other collections of tests for different components.
When writing a new test, there should usually be a test of
similar functionality already written and related tests should
be added nearby.
```bash
pytest -v jupyterhub/tests
```
The fixtures live in `jupyterhub/tests/conftest.py`. There are
fixtures that can be used for JupyterHub components, such as:
To run an individual test file (i.e. `test_api.py`):
- `app`: an instance of JupyterHub with mocked parts
- `auth_state_enabled`: enables persisting auth_state (like authentication tokens)
- `db`: a sqlite in-memory DB session
- `io_loop`: a Tornado event loop
- `event_loop`: a new asyncio event loop
- `user`: creates a new temporary user
- `admin_user`: creates a new temporary admin user
- single user servers
- `cleanup_after`: allows cleanup of single user servers between tests
- mocked service
- `MockServiceSpawner`: a spawner that mocks services for testing with a short poll interval
- `mockservice`: mocked service with no external service url
- `mockservice_url`: mocked service with a url to test external services
```bash
pytest -v jupyterhub/tests/test_api.py
```
And fixtures to add functionality or spawning behavior:
### Troubleshooting tests
- `admin_access`: grants admin access
- `no_patience`: sets slow-spawning timeouts to zero
- `slow_spawn`: enables the SlowSpawner (a spawner that takes a few seconds to start)
- `never_spawn`: enables the NeverSpawner (a spawner that will never start)
- `bad_spawn`: enables the BadSpawner (a spawner that fails immediately)
- `slow_bad_spawn`: enables the SlowBadSpawner (a spawner that fails after a short delay)
If you see test failures because of timeouts, you may wish to increase the
`ASYNC_TEST_TIMEOUT` used by the
[pytest-tornado-plugin](https://github.com/eugeniy/pytest-tornado/blob/c79f68de2222eb7cf84edcfe28650ebf309a4d0c/README.rst#markers)
from the default of 5 seconds:
To read more about fixtures check out the
[pytest docs](https://docs.pytest.org/en/latest/fixture.html)
for how to use the existing fixtures, and how to create new ones.
```bash
export ASYNC_TEST_TIMEOUT=15
```
When in doubt, feel free to [ask](https://gitter.im/jupyterhub/jupyterhub).
If you see many test errors and failures, double check that you have installed
`configurable-http-proxy`.
## Building the Docs locally
1. Install the development system as described above.
2. Install the dependencies for documentation:
```bash
python3 -m pip install -r docs/requirements.txt
```
3. Build the docs:
```bash
cd docs
make clean
make html
```
4. View the docs:
```bash
open build/html/index.html
```

View File

@@ -21,81 +21,40 @@
# your jupyterhub_config.py will be added automatically
# from your docker directory.
ARG BASE_IMAGE=ubuntu:focal-20200729@sha256:6f2fb2f9fb5582f8b587837afd6ea8f37d8d1d9e41168c90f410a6ef15fa8ce5
FROM $BASE_IMAGE AS builder
USER root
FROM ubuntu:18.04
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
# install nodejs, utf8 locale, set CDN because default httpredir is unreliable
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& apt-get install -yq --no-install-recommends \
build-essential \
ca-certificates \
locales \
python3-dev \
python3-pip \
python3-pycurl \
nodejs \
npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y install wget git bzip2 && \
apt-get purge && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV LANG C.UTF-8
RUN python3 -m pip install --upgrade setuptools pip wheel
# install Python + NodeJS with conda
RUN wget -q https://repo.continuum.io/miniconda/Miniconda3-4.5.1-Linux-x86_64.sh -O /tmp/miniconda.sh && \
echo '0c28787e3126238df24c5d4858bd0744 */tmp/miniconda.sh' | md5sum -c - && \
bash /tmp/miniconda.sh -f -b -p /opt/conda && \
/opt/conda/bin/conda install --yes -c conda-forge \
python=3.6 sqlalchemy tornado jinja2 traitlets requests pip pycurl \
nodejs configurable-http-proxy && \
/opt/conda/bin/pip install --upgrade pip && \
rm /tmp/miniconda.sh
ENV PATH=/opt/conda/bin:$PATH
# copy everything except whats in .dockerignore, its a
# compromise between needing to rebuild and maintaining
# what needs to be part of the build
COPY . /src/jupyterhub/
ADD . /src/jupyterhub
WORKDIR /src/jupyterhub
# Build client component packages (they will be copied into ./share and
# packaged with the built wheel.)
RUN python3 setup.py bdist_wheel
RUN python3 -m pip wheel --wheel-dir wheelhouse dist/*.whl
FROM $BASE_IMAGE
USER root
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -yq --no-install-recommends \
ca-certificates \
curl \
gnupg \
locales \
python3-pip \
python3-pycurl \
nodejs \
npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV SHELL=/bin/bash \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8
RUN locale-gen $LC_ALL
# always make sure pip is up to date!
RUN python3 -m pip install --no-cache --upgrade setuptools pip
RUN npm install -g configurable-http-proxy@^4.2.0 \
&& rm -rf ~/.npm
# install the wheels we built in the first stage
COPY --from=builder /src/jupyterhub/wheelhouse /tmp/wheelhouse
RUN python3 -m pip install --no-cache /tmp/wheelhouse/*
RUN pip install . && \
rm -rf $PWD ~/.cache ~/.npm
RUN mkdir -p /srv/jupyterhub/
WORKDIR /srv/jupyterhub/
EXPOSE 8000
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
LABEL org.jupyter.service="jupyterhub"
CMD ["jupyterhub"]

1
PULL_REQUEST_TEMPLATE.md Normal file
View File

@@ -0,0 +1 @@

View File

@@ -10,16 +10,13 @@
# [JupyterHub](https://github.com/jupyterhub/jupyterhub)
[![Latest PyPI version](https://img.shields.io/pypi/v/jupyterhub?logo=pypi)](https://pypi.python.org/pypi/jupyterhub)
[![Latest conda-forge version](https://img.shields.io/conda/vn/conda-forge/jupyterhub?logo=conda-forge)](https://www.npmjs.com/package/jupyterhub)
[![Documentation build status](https://img.shields.io/readthedocs/jupyterhub?logo=read-the-docs)](https://jupyterhub.readthedocs.org/en/latest/)
[![TravisCI build status](https://img.shields.io/travis/com/jupyterhub/jupyterhub?logo=travis)](https://travis-ci.com/jupyterhub/jupyterhub)
[![DockerHub build status](https://img.shields.io/docker/build/jupyterhub/jupyterhub?logo=docker&label=build)](https://hub.docker.com/r/jupyterhub/jupyterhub/tags)
[![CircleCI build status](https://img.shields.io/circleci/build/github/jupyterhub/jupyterhub?logo=circleci)](https://circleci.com/gh/jupyterhub/jupyterhub)<!-- CircleCI Token: b5b65862eb2617b9a8d39e79340b0a6b816da8cc -->
[![Test coverage of code](https://codecov.io/gh/jupyterhub/jupyterhub/branch/master/graph/badge.svg)](https://codecov.io/gh/jupyterhub/jupyterhub)
[![GitHub](https://img.shields.io/badge/issue_tracking-github-blue?logo=github)](https://github.com/jupyterhub/jupyterhub/issues)
[![Discourse](https://img.shields.io/badge/help_forum-discourse-blue?logo=discourse)](https://discourse.jupyter.org/c/jupyterhub)
[![Gitter](https://img.shields.io/badge/social_chat-gitter-blue?logo=gitter)](https://gitter.im/jupyterhub/jupyterhub)
[![PyPI](https://img.shields.io/pypi/v/jupyterhub.svg)](https://pypi.python.org/pypi/jupyterhub)
[![Documentation Status](https://readthedocs.org/projects/jupyterhub/badge/?version=latest)](https://jupyterhub.readthedocs.org/en/latest/?badge=latest)
[![Documentation Status](http://readthedocs.org/projects/jupyterhub/badge/?version=0.7.2)](https://jupyterhub.readthedocs.io/en/0.7.2/?badge=0.7.2)
[![Build Status](https://travis-ci.org/jupyterhub/jupyterhub.svg?branch=master)](https://travis-ci.org/jupyterhub/jupyterhub)
[![Circle CI](https://circleci.com/gh/jupyterhub/jupyterhub.svg?style=shield&circle-token=b5b65862eb2617b9a8d39e79340b0a6b816da8cc)](https://circleci.com/gh/jupyterhub/jupyterhub)
[![codecov.io](https://codecov.io/github/jupyterhub/jupyterhub/coverage.svg?branch=master)](https://codecov.io/github/jupyterhub/jupyterhub?branch=master)
[![Google Group](https://img.shields.io/badge/google-group-blue.svg)](https://groups.google.com/forum/#!forum/jupyter)
With [JupyterHub](https://jupyterhub.readthedocs.io) you can create a
**multi-user Hub** which spawns, manages, and proxies multiple instances of the
@@ -74,7 +71,6 @@ for administration of the Hub and its users.
The `nodejs-legacy` package installs the `node` executable and is currently
required for npm to work on Debian/Ubuntu.
- If using the default PAM Authenticator, a [pluggable authentication module (PAM)](https://en.wikipedia.org/wiki/Pluggable_authentication_module).
- TLS certificate and key for HTTPS communication
- Domain name
@@ -148,12 +144,12 @@ To start the Hub on a specific url and port ``10.0.1.2:443`` with **https**:
### Authenticators
| Authenticator | Description |
| ---------------------------------------------------------------------------- | ------------------------------------------------- |
| PAMAuthenticator | Default, built-in authenticator |
| [OAuthenticator](https://github.com/jupyterhub/oauthenticator) | OAuth + JupyterHub Authenticator = OAuthenticator |
| [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) | Simple LDAP Authenticator Plugin for JupyterHub |
| [kerberosauthenticator](https://github.com/jupyterhub/kerberosauthenticator) | Kerberos Authenticator Plugin for JupyterHub |
| Authenticator | Description |
| --------------------------------------------------------------------------- | ------------------------------------------------- |
| PAMAuthenticator | Default, built-in authenticator |
| [OAuthenticator](https://github.com/jupyterhub/oauthenticator) | OAuth + JupyterHub Authenticator = OAuthenticator |
| [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) | Simple LDAP Authenticator Plugin for JupyterHub |
| [kdcAuthenticator](https://github.com/bloomberg/jupyterhub-kdcauthenticator)| Kerberos Authenticator Plugin for JupyterHub |
### Spawners
@@ -165,7 +161,6 @@ To start the Hub on a specific url and port ``10.0.1.2:443`` with **https**:
| [sudospawner](https://github.com/jupyterhub/sudospawner) | Spawn single-user servers without being root |
| [systemdspawner](https://github.com/jupyterhub/systemdspawner) | Spawn single-user notebook servers using systemd |
| [batchspawner](https://github.com/jupyterhub/batchspawner) | Designed for clusters using batch scheduling software |
| [yarnspawner](https://github.com/jupyterhub/yarnspawner) | Spawn single-user notebook servers distributed on a Hadoop cluster |
| [wrapspawner](https://github.com/jupyterhub/wrapspawner) | WrapSpawner and ProfilesSpawner enabling runtime configuration of spawners |
## Docker
@@ -209,9 +204,6 @@ and the [`CONTRIBUTING.md`](CONTRIBUTING.md). The `CONTRIBUTING.md` file
explains how to set up a development installation, how to run the test suite,
and how to contribute to documentation.
For a high-level view of the vision and next directions of the project, see the
[JupyterHub community roadmap](docs/source/contributing/roadmap.md).
### A note about platform support
JupyterHub is supported on Linux/Unix based systems.
@@ -245,9 +237,6 @@ our JupyterHub [Gitter](https://gitter.im/jupyterhub/jupyterhub) channel.
- [Documentation for JupyterHub's REST API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/jupyterhub/master/docs/rest-api.yml#/default)
- [Documentation for Project Jupyter](http://jupyter.readthedocs.io/en/latest/index.html) | [PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)
- [Project Jupyter website](https://jupyter.org)
- [Project Jupyter community](https://jupyter.org/community)
JupyterHub follows the Jupyter [Community Guides](https://jupyter.readthedocs.io/en/latest/community/content-community.html).
---

View File

@@ -1,16 +1,19 @@
#!/usr/bin/env python
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
"""
bower-lite
Since Bower's on its way out,
stage frontend dependencies from node_modules into components
"""
import json
import os
import shutil
from os.path import join
import shutil
HERE = os.path.abspath(os.path.dirname(__file__))

View File

@@ -1,60 +1,50 @@
#!/usr/bin/env bash
# The goal of this script is to start a database server as a docker container.
#
# Required environment variables:
# - DB: The database server to start, either "postgres" or "mysql".
#
# - PGUSER/PGPASSWORD: For the creation of a postgresql user with associated
# password.
# source this file to setup postgres and mysql
# for local testing (as similar as possible to docker)
set -eu
set -e
# Stop and remove any existing database container
DOCKER_CONTAINER="hub-test-$DB"
docker rm -f "$DOCKER_CONTAINER" 2>/dev/null || true
export MYSQL_HOST=127.0.0.1
export MYSQL_TCP_PORT=${MYSQL_TCP_PORT:-13306}
export PGHOST=127.0.0.1
NAME="hub-test-$DB"
DOCKER_RUN="docker run -d --name $NAME"
# Prepare environment variables to startup and await readiness of either a mysql
# or postgresql server.
if [[ "$DB" == "mysql" ]]; then
# Environment variables can influence both the mysql server in the docker
# container and the mysql client.
#
# ref server: https://hub.docker.com/_/mysql/
# ref client: https://dev.mysql.com/doc/refman/5.7/en/setting-environment-variables.html
#
DOCKER_RUN_ARGS="-p 3306:3306 --env MYSQL_ALLOW_EMPTY_PASSWORD=1 mysql:5.7"
READINESS_CHECK="mysql --user root --execute \q"
elif [[ "$DB" == "postgres" ]]; then
# Environment variables can influence both the postgresql server in the
# docker container and the postgresql client (psql).
#
# ref server: https://hub.docker.com/_/postgres/
# ref client: https://www.postgresql.org/docs/9.5/libpq-envars.html
#
# POSTGRES_USER / POSTGRES_PASSWORD will create a user on startup of the
# postgres server, but PGUSER and PGPASSWORD are the environment variables
# used by the postgresql client psql, so we configure the user based on how
# we want to connect.
#
DOCKER_RUN_ARGS="-p 5432:5432 --env "POSTGRES_USER=${PGUSER}" --env "POSTGRES_PASSWORD=${PGPASSWORD}" postgres:9.5"
READINESS_CHECK="psql --command \q"
else
echo '$DB must be mysql or postgres'
exit 1
fi
docker rm -f "$NAME" 2>/dev/null || true
# Start the database server
docker run --detach --name "$DOCKER_CONTAINER" $DOCKER_RUN_ARGS
case "$DB" in
"mysql")
RUN_ARGS="-e MYSQL_ALLOW_EMPTY_PASSWORD=1 -p $MYSQL_TCP_PORT:3306 mysql:5.7"
CHECK="mysql --host $MYSQL_HOST --port $MYSQL_TCP_PORT --user root -e \q"
;;
"postgres")
RUN_ARGS="-p 5432:5432 postgres:9.5"
CHECK="psql --user postgres -c \q"
;;
*)
echo '$DB must be mysql or postgres'
exit 1
esac
$DOCKER_RUN $RUN_ARGS
# Wait for the database server to start
echo -n "waiting for $DB "
for i in {1..60}; do
if $READINESS_CHECK; then
echo 'done'
break
else
echo -n '.'
sleep 1
fi
if $CHECK; then
echo 'done'
break
else
echo -n '.'
sleep 1
fi
done
$READINESS_CHECK
$CHECK
echo -e "
Set these environment variables:
export MYSQL_HOST=127.0.0.1
export MYSQL_TCP_PORT=$MYSQL_TCP_PORT
export PGHOST=127.0.0.1
"

View File

@@ -1,26 +1,27 @@
#!/usr/bin/env bash
# The goal of this script is to initialize a running database server with clean
# databases for use during tests.
#
# Required environment variables:
# - DB: The database server to start, either "postgres" or "mysql".
# initialize jupyterhub databases for testing
set -eu
set -e
# Prepare env vars SQL_CLIENT and EXTRA_CREATE_DATABASE_ARGS
if [[ "$DB" == "mysql" ]]; then
SQL_CLIENT="mysql --user root --execute "
EXTRA_CREATE_DATABASE_ARGS='CHARACTER SET utf8 COLLATE utf8_general_ci'
elif [[ "$DB" == "postgres" ]]; then
SQL_CLIENT="psql --command "
else
echo '$DB must be mysql or postgres'
exit 1
fi
MYSQL="mysql --user root --host $MYSQL_HOST --port $MYSQL_TCP_PORT -e "
PSQL="psql --user postgres -c "
case "$DB" in
"mysql")
EXTRA_CREATE='CHARACTER SET utf8 COLLATE utf8_general_ci'
SQL="$MYSQL"
;;
"postgres")
SQL="$PSQL"
;;
*)
echo '$DB must be mysql or postgres'
exit 1
esac
# Configure a set of databases in the database server for upgrade tests
set -x
for SUFFIX in '' _upgrade_072 _upgrade_081 _upgrade_094; do
$SQL_CLIENT "DROP DATABASE jupyterhub${SUFFIX};" 2>/dev/null || true
$SQL_CLIENT "CREATE DATABASE jupyterhub${SUFFIX} ${EXTRA_CREATE_DATABASE_ARGS:-};"
for SUFFIX in '' _upgrade_072 _upgrade_081; do
$SQL "DROP DATABASE jupyterhub${SUFFIX};" 2>/dev/null || true
$SQL "CREATE DATABASE jupyterhub${SUFFIX} ${EXTRA_CREATE};"
done

View File

@@ -1,16 +0,0 @@
# Demo JupyterHub Docker image
#
# This should only be used for demo or testing and not as a base image to build on.
#
# It includes the notebook package and it uses the DummyAuthenticator and the SimpleLocalProcessSpawner.
ARG BASE_IMAGE=jupyterhub/jupyterhub-onbuild
FROM ${BASE_IMAGE}
# Install the notebook package
RUN python3 -m pip install notebook
# Create a demo user
RUN useradd --create-home demo
RUN chown demo .
USER demo

View File

@@ -1,25 +0,0 @@
## Demo Dockerfile
This is a demo JupyterHub Docker image to help you get a quick overview of what
JupyterHub is and how it works.
It uses the SimpleLocalProcessSpawner to spawn new user servers and
DummyAuthenticator for authentication.
The DummyAuthenticator allows you to log in with any username & password and the
SimpleLocalProcessSpawner allows starting servers without having to create a
local user for each JupyterHub user.
### Important!
This should only be used for demo or testing purposes!
It shouldn't be used as a base image to build on.
### Try it
1. `cd` to the root of your jupyterhub repo.
2. Build the demo image with `docker build -t jupyterhub-demo demo-image`.
3. Run the demo image with `docker run -d -p 8000:8000 jupyterhub-demo`.
4. Visit http://localhost:8000 and login with any username and password
5. Happy demo-ing :tada:!

View File

@@ -1,7 +0,0 @@
# Configuration file for jupyterhub-demo
c = get_config()
# Use DummyAuthenticator and SimpleSpawner
c.JupyterHub.spawner_class = "simple"
c.JupyterHub.authenticator_class = "dummy"

View File

@@ -1,20 +1,14 @@
-r requirements.txt
mock
beautifulsoup4
codecov
cryptography
pytest-cov
pytest-tornado
pytest>=3.3
notebook
requests-mock
virtualenv
# temporary pin of attrs for jsonschema 0.3.0a1
# seems to be a pip bug
attrs>=17.4.0
beautifulsoup4
codecov
coverage
cryptography
html5lib # needed for beautifulsoup
mock
notebook
pre-commit
pytest-asyncio
pytest-cov
pytest>=3.3
requests-mock
# blacklist urllib3 releases affected by https://github.com/urllib3/urllib3/issues/1683
# I *think* this should only affect testing, not production
urllib3!=1.25.4,!=1.25.5
virtualenv

View File

@@ -7,3 +7,5 @@ ENV LANG=en_US.UTF-8
USER nobody
CMD ["jupyterhub"]

View File

@@ -12,9 +12,10 @@ Dockerfile.alpine contains base image for jupyterhub. It does not work independ
* start configurable-http-proxy in another container
* specify CONFIGPROXY_AUTH_TOKEN env in both containers
* put both containers on the same network (e.g. docker network create jupyterhub; docker run ... --net jupyterhub)
* put both containers on the same network (e.g. docker create network jupyterhub; docker run ... --net jupyterhub)
* tell jupyterhub where CHP is (e.g. c.ConfigurableHTTPProxy.api_url = 'http://chp:8001')
* tell jupyterhub not to start the proxy itself (c.ConfigurableHTTPProxy.should_start = False)
* Use dummy authenticator for ease of testing. Update following in jupyterhub_config file
- c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
- c.DummyAuthenticator.password = "your strong password"

View File

@@ -1,9 +0,0 @@
import os
from jupyterhub._data import DATA_FILES_PATH
print(f"DATA_FILES_PATH={DATA_FILES_PATH}")
for sub_path in ("templates", "static/components", "static/css/style.min.css"):
path = os.path.join(DATA_FILES_PATH, sub_path)
assert os.path.exists(path), path

View File

@@ -48,7 +48,6 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
@echo " spelling to run spell check on documentation"
@echo " metrics to generate documentation for metrics by inspecting the source code"
clean:
rm -rf $(BUILDDIR)/*
@@ -61,12 +60,7 @@ rest-api: source/_static/rest-api/index.html
source/_static/rest-api/index.html: rest-api.yml node_modules
npm run rest-api
metrics: source/reference/metrics.rst
source/reference/metrics.rst: generate-metrics.py
python3 generate-metrics.py
html: rest-api metrics
html: rest-api
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

22
docs/environment.yml Normal file
View File

@@ -0,0 +1,22 @@
# ReadTheDocs uses the `environment.yaml` so make sure to update that as well
# if you change the dependencies of JupyterHub in the various `requirements.txt`
name: jhub_docs
channels:
- conda-forge
dependencies:
- nodejs
- python=3.6
- alembic
- jinja2
- pamela
- requests
- sqlalchemy>=1
- tornado>=5.0
- traitlets>=4.1
- sphinx>=1.7
- pip:
- python-oauth2
- recommonmark==0.4.0
- async_generator
- prometheus_client
- attrs>=17.4.0

View File

@@ -1,57 +0,0 @@
import os
from os.path import join
from pytablewriter import RstSimpleTableWriter
from pytablewriter.style import Style
import jupyterhub.metrics
HERE = os.path.abspath(os.path.dirname(__file__))
class Generator:
@classmethod
def create_writer(cls, table_name, headers, values):
writer = RstSimpleTableWriter()
writer.table_name = table_name
writer.headers = headers
writer.value_matrix = values
writer.margin = 1
[writer.set_style(header, Style(align="center")) for header in headers]
return writer
def _parse_metrics(self):
table_rows = []
for name in dir(jupyterhub.metrics):
obj = getattr(jupyterhub.metrics, name)
if obj.__class__.__module__.startswith('prometheus_client.'):
for metric in obj.describe():
table_rows.append([metric.type, metric.name, metric.documentation])
return table_rows
def prometheus_metrics(self):
generated_directory = f"{HERE}/source/reference"
if not os.path.exists(generated_directory):
os.makedirs(generated_directory)
filename = f"{generated_directory}/metrics.rst"
table_name = ""
headers = ["Type", "Name", "Description"]
values = self._parse_metrics()
writer = self.create_writer(table_name, headers, values)
title = "List of Prometheus Metrics"
underline = "============================"
content = f"{title}\n{underline}\n{writer.dumps()}"
with open(filename, 'w') as f:
f.write(content)
print(f"Generated {filename}.")
def main():
doc_generator = Generator()
doc_generator.prometheus_metrics()
if __name__ == "__main__":
main()

View File

@@ -1,12 +1,5 @@
# ReadTheDocs uses the `environment.yaml` so make sure to update that as well
# if you change this file
-r ../requirements.txt
alabaster_jupyterhub
# Temporary fix of #3021. Revert back to released autodoc-traits when
# 0.1.0 released.
https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip
pydata-sphinx-theme
pytablewriter>=0.56
recommonmark>=0.6
sphinx-copybutton
sphinx-jsonschema
sphinx>=1.7
recommonmark==0.4.0

View File

@@ -1,13 +1,13 @@
# see me at: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#/default
# see me at: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/jupyterhub/master/docs/rest-api.yml#/default
swagger: '2.0'
info:
title: JupyterHub
description: The REST API for JupyterHub
version: 1.2.0dev
version: 0.9.0dev
license:
name: BSD-3-Clause
schemes:
[http, https]
- [http, https]
securityDefinitions:
token:
type: apiKey
@@ -89,7 +89,7 @@ paths:
post:
summary: Create multiple users
parameters:
- name: body
- name: data
in: body
required: true
schema:
@@ -147,7 +147,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: Updated user info. At least one key to be updated (name or admin) is required.
@@ -176,63 +176,6 @@ paths:
responses:
'204':
description: The user has been deleted
/users/{name}/activity:
post:
summary:
Notify Hub of activity for a given user.
description:
Notify the Hub of activity by the user,
e.g. accessing a service or (more likely)
actively using a server.
parameters:
- name: name
description: username
in: path
required: true
type: string
- name: body
in: body
schema:
type: object
properties:
last_activity:
type: string
format: date-time
description: |
Timestamp of last-seen activity for this user.
Only needed if this is not activity associated
with using a given server.
servers:
description: |
Register activity for specific servers by name.
The keys of this dict are the names of servers.
The default server has an empty name ('').
type: object
properties:
'<server name>':
description: |
Activity for a single server.
type: object
required:
- last_activity
properties:
last_activity:
type: string
format: date-time
description: |
Timestamp of last-seen activity on this server.
example:
last_activity: '2019-02-06T12:54:14Z'
servers:
'':
last_activity: '2019-02-06T12:54:14Z'
gpu:
last_activity: '2019-02-06T12:54:14Z'
responses:
'401':
$ref: '#/responses/Unauthorized'
'404':
description: No such user
/users/{name}/server:
post:
summary: Start a user's single-user notebook server
@@ -242,19 +185,6 @@ paths:
in: path
required: true
type: string
- name: options
description: |
Spawn options can be passed as a JSON body
when spawning via the API instead of spawn form.
The structure of the options
will depend on the Spawner's configuration.
The body itself will be available as `user_options` for the
Spawner.
in: body
required: false
schema:
type: object
responses:
'201':
description: The user's notebook server has started
@@ -283,23 +213,10 @@ paths:
required: true
type: string
- name: server_name
description: |
name given to a named-server.
Note that depending on your JupyterHub infrastructure there are chracterter size limitation to `server_name`. Default spawner with K8s pod will not allow Jupyter Notebooks to be spawned with a name that contains more than 253 characters (keep in mind that the pod will be spawned with extra characters to identify the user and hub).
description: name given to a named-server
in: path
required: true
type: string
- name: options
description: |
Spawn options can be passed as a JSON body
when spawning via the API instead of spawn form.
The structure of the options
will depend on the Spawner's configuration.
in: body
required: false
schema:
type: object
responses:
'201':
description: The user's notebook named-server has started
@@ -318,30 +235,12 @@ paths:
in: path
required: true
type: string
- name: body
in: body
required: false
schema:
type: object
properties:
remove:
type: boolean
description: |
Whether to fully remove the server, rather than just stop it.
Removing a server deletes things like the state of the stopped server.
Default: false.
responses:
'204':
description: The user's notebook named-server has stopped
'202':
description: The user's notebook named-server has not yet stopped as it is taking a while to stop
/users/{name}/tokens:
parameters:
- name: name
description: username
in: path
required: true
type: string
get:
summary: List tokens for the user
responses:
@@ -351,43 +250,25 @@ paths:
type: array
items:
$ref: '#/definitions/Token'
'401':
$ref: '#/responses/Unauthorized'
'404':
description: No such user
post:
summary: Create a new token for the user
parameters:
- name: token_params
in: body
- name: expires_in
type: number
required: false
schema:
type: object
properties:
expires_in:
type: number
description: lifetime (in seconds) after which the requested token will expire.
note:
type: string
description: A note attached to the token for future bookkeeping
in: body
description: lifetime (in seconds) after which the requested token will expire.
- name: note
type: string
required: false
in: body
description: A note attached to the token for future bookkeeping
responses:
'201':
description: The newly created token
schema:
$ref: '#/definitions/Token'
'400':
description: Body must be a JSON dict or empty
/users/{name}/tokens/{token_id}:
parameters:
- name: name
description: username
in: path
required: true
type: string
- name: token_id
in: path
required: true
type: string
get:
summary: Get the model for a token by id
responses:
@@ -401,13 +282,12 @@ paths:
'204':
description: The token has been deleted
/user:
get:
summary: Return authenticated user's model
responses:
'200':
description: The authenticated user's model is returned.
schema:
$ref: '#/definitions/User'
summary: Return authenticated user's model
description:
parameters:
responses:
'200':
description: The authenticated user's model is returned.
/groups:
get:
summary: List groups
@@ -465,7 +345,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: The users to add to the group
@@ -490,7 +370,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: The users to remove from the group
@@ -548,7 +428,7 @@ paths:
summary: Notify the Hub about a new proxy
description: Notifies the Hub of a new proxy to use.
parameters:
- name: body
- name: data
in: body
required: true
description: Any values that have changed for the new proxy. All keys are optional.
@@ -580,15 +460,14 @@ paths:
Logging in via this method is only available when the active Authenticator
accepts passwords (e.g. not OAuth).
parameters:
- name: credentials
- name: username
in: body
schema:
type: object
properties:
username:
type: string
password:
type: string
required: false
type: string
- name: password
in: body
required: false
type: string
responses:
'200':
description: The new API token
@@ -604,10 +483,10 @@ paths:
get:
summary: Identify a user or service from an API token
parameters:
- name: token
in: path
required: true
type: string
- name: token
in: path
required: true
type: string
responses:
'200':
description: The user or service identified by the API token
@@ -618,14 +497,14 @@ paths:
summary: Identify a user from a cookie
description: Used by single-user notebook servers to hand off cookie authentication to the Hub
parameters:
- name: cookie_name
in: path
required: true
type: string
- name: cookie_value
in: path
required: true
type: string
- name: cookie_name
in: path
required: true
type: string
- name: cookie_value
in: path
required: true
type: string
responses:
'200':
description: The user identified by the cookie
@@ -660,11 +539,6 @@ paths:
in: query
required: true
type: string
responses:
'200':
description: Success
'400':
description: OAuth2Error
/oauth2/token:
post:
summary: Request an OAuth2 token
@@ -676,27 +550,27 @@ paths:
parameters:
- name: client_id
description: The client id
in: formData
in: form
required: true
type: string
- name: client_secret
description: The client secret
in: formData
in: form
required: true
type: string
- name: grant_type
description: The grant type (always 'authorization_code')
in: formData
in: form
required: true
type: string
- name: code
description: The code provided by the authorization redirect
in: formData
in: form
required: true
type: string
- name: redirect_uri
description: The redirect url
in: formData
in: form
required: true
type: string
responses:
@@ -715,28 +589,14 @@ paths:
post:
summary: Shutdown the Hub
parameters:
- name: body
- name: proxy
in: body
schema:
type: object
properties:
proxy:
type: boolean
description: Whether the proxy should be shutdown as well (default from Hub config)
servers:
type: boolean
description: Whether users' notebook servers should be shutdown as well (default from Hub config)
responses:
'202':
description: Shutdown successful
'400':
description: Unexpeced value for proxy or servers
# Descriptions of common responses
responses:
NotFound:
description: The specified resource was not found
Unauthorized:
description: Authentication/Authorization error
type: boolean
description: Whether the proxy should be shutdown as well (default from Hub config)
- name: servers
in: body
type: boolean
description: Whether users' notebook servers should be shutdown as well (default from Hub config)
definitions:
User:
type: object
@@ -764,10 +624,11 @@ definitions:
format: date-time
description: Timestamp of last-seen activity from the user
servers:
type: array
type: object
description: The active servers for this user.
items:
$ref: '#/definitions/Server'
schema:
$ref: '#/definitions/Server'
Server:
type: object
properties:
@@ -805,9 +666,6 @@ definitions:
state:
type: object
description: Arbitrary internal state from this server's spawner. Only available on the hub's users list or get-user-by-name method, and only if a hub admin. None otherwise.
user_options:
type: object
description: User specified options for the user's spawned instance of a single-user server.
Group:
type: object
properties:

View File

@@ -1,4 +1,106 @@
/* Added to avoid logo being too squeezed */
.navbar-brand {
height: 4rem !important;
div#helm-chart-schema h2,
div#helm-chart-schema h3,
div#helm-chart-schema h4,
div#helm-chart-schema h5,
div#helm-chart-schema h6 {
font-family: courier new;
}
h3, h3 ~ * {
margin-left: 3% !important;
}
h4, h4 ~ * {
margin-left: 6% !important;
}
h5, h5 ~ * {
margin-left: 9% !important;
}
h6, h6 ~ * {
margin-left: 12% !important;
}
h7, h7 ~ * {
margin-left: 15% !important;
}
img.logo {
width:100%
}
.right-next {
float: right;
max-width: 45%;
overflow: auto;
text-overflow: ellipsis;
white-space: nowrap;
}
.right-next::after{
content: ' »';
}
.left-prev {
float: left;
max-width: 45%;
overflow: auto;
text-overflow: ellipsis;
white-space: nowrap;
}
.left-prev::before{
content: '« ';
}
.prev-next-bottom {
margin-top: 3em;
}
.prev-next-top {
margin-bottom: 1em;
}
/* Sidebar TOC and headers */
div.sphinxsidebarwrapper div {
margin-bottom: .8em;
}
div.sphinxsidebar h3 {
font-size: 1.3em;
padding-top: 0px;
font-weight: 800;
margin-left: 0px !important;
}
div.sphinxsidebar p.caption {
font-size: 1.2em;
margin-bottom: 0px;
margin-left: 0px !important;
font-weight: 900;
color: #767676;
}
div.sphinxsidebar ul {
font-size: .8em;
margin-top: 0px;
padding-left: 3%;
margin-left: 0px !important;
}
div.relations ul {
font-size: 1em;
margin-left: 0px !important;
}
div#searchbox form {
margin-left: 0px !important;
}
/* body elements */
.toctree-wrapper span.caption-text {
color: #767676;
font-style: italic;
font-weight: 300;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,16 @@
{# Custom template for navigation.html
alabaster theme does not provide blocks for titles to
be overridden so this custom theme handles title and
toctree for sidebar
#}
<h3>{{ _('Table of Contents') }}</h3>
{{ toctree(includehidden=theme_sidebar_includehidden, collapse=theme_sidebar_collapse) }}
{% if theme_extra_nav_links %}
<hr />
<ul>
{% for text, uri in theme_extra_nav_links.items() %}
<li class="toctree-l1"><a href="{{ uri }}">{{ text }}</a></li>
{% endfor %}
</ul>
{% endif %}

View File

@@ -0,0 +1,30 @@
{% extends '!page.html' %}
{# Custom template for page.html
Alabaster theme does not provide blocks for prev/next at bottom of each page.
This is _in addition_ to the prev/next in the sidebar. The "Prev/Next" text
or symbols are handled by CSS classes in _static/custom.css
#}
{% macro prev_next(prev, next, prev_title='', next_title='') %}
{%- if prev %}
<a class='left-prev' href="{{ prev.link|e }}" title="{{ _('previous chapter')}}">{{ prev_title or prev.title }}</a>
{%- endif %}
{%- if next %}
<a class='right-next' href="{{ next.link|e }}" title="{{ _('next chapter')}}">{{ next_title or next.title }}</a>
{%- endif %}
<div style='clear:both;'></div>
{% endmacro %}
{% block body %}
<div class='prev-next-top'>
{{ prev_next(prev, next, 'Previous', 'Next') }}
</div>
{{super()}}
<div class='prev-next-bottom'>
{{ prev_next(prev, next) }}
</div>
{% endblock %}

View File

@@ -0,0 +1,17 @@
{# Custom template for relations.html
alabaster theme does not provide previous/next page by default
#}
<div class="relations">
<h3>Navigation</h3>
<ul>
<li><a href="{{ pathto(master_doc) }}">Documentation Home</a><ul>
{%- if prev %}
<li><a href="{{ prev.link|e }}" title="Previous">Previous topic</a></li>
{%- endif %}
{%- if next %}
<li><a href="{{ next.link|e }}" title="Next">Next topic</a></li>
{%- endif %}
</ul>
</ul>
</div>

View File

@@ -1,159 +0,0 @@
.. _admin/upgrading:
====================
Upgrading JupyterHub
====================
JupyterHub offers easy upgrade pathways between minor versions. This
document describes how to do these upgrades.
If you are using :ref:`a JupyterHub distribution <index/distributions>`, you
should consult the distribution's documentation on how to upgrade. This
document is if you have set up your own JupyterHub without using a
distribution.
It is long because is pretty detailed! Most likely, upgrading
JupyterHub is painless, quick and with minimal user interruption.
Read the Changelog
==================
The `changelog <../changelog.html>`_ contains information on what has
changed with the new JupyterHub release, and any deprecation warnings.
Read these notes to familiarize yourself with the coming changes. There
might be new releases of authenticators & spawners you are using, so
read the changelogs for those too!
Notify your users
=================
If you are using the default configuration where ``configurable-http-proxy``
is managed by JupyterHub, your users will see service disruption during
the upgrade process. You should notify them, and pick a time to do the
upgrade where they will be least disrupted.
If you are using a different proxy, or running ``configurable-http-proxy``
independent of JupyterHub, your users will be able to continue using notebook
servers they had already launched, but will not be able to launch new servers
nor sign in.
Backup database & config
========================
Before doing an upgrade, it is critical to back up:
#. Your JupyterHub database (sqlite by default, or MySQL / Postgres
if you used those). If you are using sqlite (the default), you
should backup the ``jupyterhub.sqlite`` file.
#. Your ``jupyterhub_config.py`` file.
#. Your user's home directories. This is unlikely to be affected directly by
a JupyterHub upgrade, but we recommend a backup since user data is very
critical.
Shutdown JupyterHub
===================
Shutdown the JupyterHub process. This would vary depending on how you
have set up JupyterHub to run. Most likely, it is using a process
supervisor of some sort (``systemd`` or ``supervisord`` or even ``docker``).
Use the supervisor specific command to stop the JupyterHub process.
Upgrade JupyterHub packages
===========================
There are two environments where the ``jupyterhub`` package is installed:
#. The *hub environment*, which is where the JupyterHub server process
runs. This is started with the ``jupyterhub`` command, and is what
people generally think of as JupyterHub.
#. The *notebook user environments*. This is where the user notebook
servers are launched from, and is probably custom to your own
installation. This could be just one environment (different from the
hub environment) that is shared by all users, one environment
per user, or same environment as the hub environment. The hub
launched the ``jupyterhub-singleuser`` command in this environment,
which in turn starts the notebook server.
You need to make sure the version of the ``jupyterhub`` package matches
in both these environments. If you installed ``jupyterhub`` with pip,
you can upgrade it with:
.. code-block:: bash
python3 -m pip install --upgrade jupyterhub==<version>
Where ``<version>`` is the version of JupyterHub you are upgrading to.
If you used ``conda`` to install ``jupyterhub``, you should upgrade it
with:
.. code-block:: bash
conda install -c conda-forge jupyterhub==<version>
Where ``<version>`` is the version of JupyterHub you are upgrading to.
You should also check for new releases of the authenticator & spawner you
are using. You might wish to upgrade those packages too along with JupyterHub,
or upgrade them separately.
Upgrade JupyterHub database
===========================
Once new packages are installed, you need to upgrade the JupyterHub
database. From the hub environment, in the same directory as your
``jupyterhub_config.py`` file, you should run:
.. code-block:: bash
jupyterhub upgrade-db
This should find the location of your database, and run necessary upgrades
for it.
SQLite database disadvantages
-----------------------------
SQLite has some disadvantages when it comes to upgrading JupyterHub. These
are:
- ``upgrade-db`` may not work, and you may need delete your database
and start with a fresh one.
- ``downgrade-db`` **will not** work if you want to rollback to an
earlier version, so backup the ``jupyterhub.sqlite`` file before
upgrading
What happens if I delete my database?
-------------------------------------
Losing the Hub database is often not a big deal. Information that
resides only in the Hub database includes:
- active login tokens (user cookies, service tokens)
- users added via JupyterHub UI, instead of config files
- info about running servers
If the following conditions are true, you should be fine clearing the
Hub database and starting over:
- users specified in config file, or login using an external
authentication provider (Google, GitHub, LDAP, etc)
- user servers are stopped during upgrade
- don't mind causing users to login again after upgrade
Start JupyterHub
================
Once the database upgrade is completed, start the ``jupyterhub``
process again.
#. Log-in and start the server to make sure things work as
expected.
#. Check the logs for any errors or deprecation warnings. You
might have to update your ``jupyterhub_config.py`` file to
deal with any deprecated options.
Congratulations, your JupyterHub has been upgraded!

View File

@@ -13,3 +13,4 @@ Module: :mod:`jupyterhub.app`
-------------------
.. autoconfigurable:: JupyterHub

View File

@@ -26,7 +26,3 @@ Module: :mod:`jupyterhub.auth`
.. autoconfigurable:: PAMAuthenticator
:class:`DummyAuthenticator`
---------------------------
.. autoconfigurable:: DummyAuthenticator

View File

@@ -1,8 +1,8 @@
.. _api-index:
##############
JupyterHub API
##############
##################
The JupyterHub API
##################
:Release: |release|
:Date: |today|

View File

@@ -20,3 +20,4 @@ Module: :mod:`jupyterhub.proxy`
.. autoconfigurable:: ConfigurableHTTPProxy
:members: debug, auth_token, check_running_interval, api_url, command

View File

@@ -14,3 +14,4 @@ Module: :mod:`jupyterhub.services.service`
.. autoconfigurable:: Service
:members: name, admin, url, api_token, managed, kind, command, cwd, environment, user, oauth_client_id, server, prefix, proxy_spec

View File

@@ -38,3 +38,4 @@ Module: :mod:`jupyterhub.services.auth`
--------------------------------
.. autoclass:: HubOAuthCallbackHandler

View File

@@ -13,9 +13,10 @@ Module: :mod:`jupyterhub.spawner`
----------------
.. autoconfigurable:: Spawner
:members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string, create_certs, move_certs
:members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string
:class:`LocalProcessSpawner`
----------------------------
.. autoconfigurable:: LocalProcessSpawner

View File

@@ -34,3 +34,4 @@ Module: :mod:`jupyterhub.user`
.. attribute:: spawner
The user's :class:`~.Spawner` instance.

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
#
import os
import sys
import os
import shlex
# For conversion from markdown to html
import recommonmark.parser
# Set paths
sys.path.insert(0, os.path.abspath('.'))
@@ -17,11 +21,10 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'autodoc_traits',
'sphinx_copybutton',
'sphinx-jsonschema',
'recommonmark',
]
templates_path = ['_templates']
# The master toctree document.
master_doc = 'index'
@@ -36,6 +39,7 @@ from os.path import dirname
docs = dirname(dirname(__file__))
root = dirname(docs)
sys.path.insert(0, root)
sys.path.insert(0, os.path.join(docs, 'sphinxext'))
import jupyterhub
@@ -54,69 +58,7 @@ default_role = 'literal'
# -- Source -------------------------------------------------------------
import recommonmark
from recommonmark.transform import AutoStructify
# -- Config -------------------------------------------------------------
from jupyterhub.app import JupyterHub
from docutils import nodes
from sphinx.directives.other import SphinxDirective
from contextlib import redirect_stdout
from io import StringIO
# create a temp instance of JupyterHub just to get the output of the generate-config
# and help --all commands.
jupyterhub_app = JupyterHub()
class ConfigDirective(SphinxDirective):
"""Generate the configuration file output for use in the documentation."""
has_content = False
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
# The generated configuration file for this version
generated_config = jupyterhub_app.generate_config_file()
# post-process output
home_dir = os.environ['HOME']
generated_config = generated_config.replace(home_dir, '$HOME', 1)
par = nodes.literal_block(text=generated_config)
return [par]
class HelpAllDirective(SphinxDirective):
"""Print the output of jupyterhub help --all for use in the documentation."""
has_content = False
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
# The output of the help command for this version
buffer = StringIO()
with redirect_stdout(buffer):
jupyterhub_app.print_help('--help-all')
all_help = buffer.getvalue()
# post-process output
home_dir = os.environ['HOME']
all_help = all_help.replace(home_dir, '$HOME', 1)
par = nodes.literal_block(text=all_help)
return [par]
def setup(app):
app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True)
app.add_css_file('custom.css')
app.add_transform(AutoStructify)
app.add_directive('jupyterhub-generate-config', ConfigDirective)
app.add_directive('jupyterhub-help-all', HelpAllDirective)
source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'}
source_suffix = ['.rst', '.md']
# source_encoding = 'utf-8-sig'
@@ -124,7 +66,7 @@ source_suffix = ['.rst', '.md']
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages.
html_theme = 'pydata_sphinx_theme'
html_theme = 'alabaster'
html_logo = '_static/images/logo/logo.png'
html_favicon = '_static/images/logo/favicon.ico'
@@ -132,6 +74,31 @@ html_favicon = '_static/images/logo/favicon.ico'
# Paths that contain custom static files (such as style sheets)
html_static_path = ['_static']
html_theme_options = {
'show_related': True,
'description': 'Documentation for JupyterHub',
'github_user': 'jupyterhub',
'github_repo': 'jupyterhub',
'github_banner': False,
'github_button': True,
'github_type': 'star',
'show_powered_by': False,
'extra_nav_links': {
'GitHub Repo': 'http://github.com/jupyterhub/jupyterhub',
'Issue Tracker': 'http://github.com/jupyterhub/jupyterhub/issues',
},
}
html_sidebars = {
'**': [
'about.html',
'searchbox.html',
'navigation.html',
'relations.html',
'sourcelink.html',
]
}
htmlhelp_basename = 'JupyterHubdoc'
# -- Options for LaTeX output ---------------------------------------------
@@ -214,12 +181,14 @@ intersphinx_mapping = {'https://docs.python.org/3/': None}
# -- Read The Docs --------------------------------------------------------
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if on_rtd:
if not on_rtd:
html_theme = 'alabaster'
else:
# readthedocs.org uses their theme by default, so no need to specify it
# build both metrics and rest-api, since RTD doesn't run make
# build rest-api, since RTD doesn't run make
from subprocess import check_call as sh
sh(['make', 'metrics', 'rest-api'], cwd=docs)
sh(['make', 'rest-api'], cwd=docs)
# -- Spell checking -------------------------------------------------------

View File

@@ -1,30 +0,0 @@
.. _contributing/community:
================================
Community communication channels
================================
We use `Discourse <https://discourse.jupyter.org>` for online discussion.
Everyone in the Jupyter community is welcome to bring ideas and questions there.
In addition, we use `Gitter <https://gitter.im>`_ for online, real-time text chat,
a place for more ephemeral discussions.
The primary Gitter channel for JupyterHub is `jupyterhub/jupyterhub <https://gitter.im/jupyterhub/jupyterhub>`_.
Gitter isn't archived or searchable, so we recommend going to discourse first
to make sure that discussions are most useful and accessible to the community.
Remember that our community is distributed across the world in various
timezones, so be patient if you do not get an answer immediately!
GitHub issues are used for most long-form project discussions, bug reports
and feature requests. Issues related to a specific authenticator or
spawner should be directed to the appropriate repository for the
authenticator or spawner. If you are using a specific JupyterHub
distribution (such as `Zero to JupyterHub on Kubernetes <http://github.com/jupyterhub/zero-to-jupyterhub-k8s>`_
or `The Littlest JupyterHub <http://github.com/jupyterhub/the-littlest-jupyterhub/>`_),
you should open issues directly in their repository. If you can not
find a repository to open your issue in, do not worry! Create it in the `main
JupyterHub repository <https://github.com/jupyterhub/jupyterhub/>`_ and our
community will help you figure it out.
A `mailing list <https://groups.google.com/forum/#!forum/jupyter>`_ for all
of Project Jupyter exists, along with one for `teaching with Jupyter
<https://groups.google.com/forum/#!forum/jupyter-education>`_.

View File

@@ -1,78 +0,0 @@
.. _contributing/docs:
==========================
Contributing Documentation
==========================
Documentation is often more important than code. This page helps
you get set up on how to contribute documentation to JupyterHub.
Building documentation locally
==============================
We use `sphinx <http://sphinx-doc.org>`_ to build our documentation. It takes
our documentation source files (written in `markdown
<https://daringfireball.net/projects/markdown/>`_ or `reStructuredText
<http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html>`_ &
stored under the ``docs/source`` directory) and converts it into various
formats for people to read. To make sure the documentation you write or
change renders correctly, it is good practice to test it locally.
#. Make sure you have successfuly completed :ref:`contributing/setup`.
#. Install the packages required to build the docs.
.. code-block:: bash
python3 -m pip install -r docs/requirements.txt
#. Build the html version of the docs. This is the most commonly used
output format, so verifying it renders as you should is usually good
enough.
.. code-block:: bash
cd docs
make html
This step will display any syntax or formatting errors in the documentation,
along with the filename / line number in which they occurred. Fix them,
and re-run the ``make html`` command to re-render the documentation.
#. View the rendered documentation by opening ``build/html/index.html`` in
a web browser.
.. tip::
On macOS, you can open a file from the terminal with ``open <path-to-file>``.
On Linux, you can do the same with ``xdg-open <path-to-file>``.
.. _contributing/docs/conventions:
Documentation conventions
=========================
This section lists various conventions we use in our documentation. This is a
living document that grows over time, so feel free to add to it / change it!
Our entire documentation does not yet fully conform to these conventions yet,
so help in making it so would be appreciated!
``pip`` invocation
------------------
There are many ways to invoke a ``pip`` command, we recommend the following
approach:
.. code-block:: bash
python3 -m pip
This invokes pip explicitly using the python3 binary that you are
currently using. This is the **recommended way** to invoke pip
in our documentation, since it is least likely to cause problems
with python3 and pip being from different environments.
For more information on how to invoke ``pip`` commands, see
`the pip documentation <https://pip.pypa.io/en/stable/>`_.

View File

@@ -1,21 +0,0 @@
============
Contributing
============
We want you to contribute to JupyterHub in ways that are most exciting
& useful to you. We value documentation, testing, bug reporting & code equally,
and are glad to have your contributions in whatever form you wish :)
Our `Code of Conduct <https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md>`_
(`reporting guidelines <https://github.com/jupyter/governance/blob/master/conduct/reporting_online.md>`_)
helps keep our community welcoming to as many people as possible.
.. toctree::
:maxdepth: 2
community
setup
docs
tests
roadmap
security

View File

@@ -1,97 +0,0 @@
# The JupyterHub roadmap
This roadmap collects "next steps" for JupyterHub. It is about creating a
shared understanding of the project's vision and direction amongst
the community of users, contributors, and maintainers.
The goal is to communicate priorities and upcoming release plans.
It is not a aimed at limiting contributions to what is listed here.
## Using the roadmap
### Sharing Feedback on the Roadmap
All of the community is encouraged to provide feedback as well as share new
ideas with the community. Please do so by submitting an issue. If you want to
have an informal conversation first use one of the other communication channels.
After submitting the issue, others from the community will probably
respond with questions or comments they have to clarify the issue. The
maintainers will help identify what a good next step is for the issue.
### What do we mean by "next step"?
When submitting an issue, think about what "next step" category best describes
your issue:
* **now**, concrete/actionable step that is ready for someone to start work on.
These might be items that have a link to an issue or more abstract like
"decrease typos and dead links in the documentation"
* **soon**, less concrete/actionable step that is going to happen soon,
discussions around the topic are coming close to an end at which point it can
move into the "now" category
* **later**, abstract ideas or tasks, need a lot of discussion or
experimentation to shape the idea so that it can be executed. Can also
contain concrete/actionable steps that have been postponed on purpose
(these are steps that could be in "now" but the decision was taken to work on
them later)
### Reviewing and Updating the Roadmap
The roadmap will get updated as time passes (next review by 1st December) based
on discussions and ideas captured as issues.
This means this list should not be exhaustive, it should only represent
the "top of the stack" of ideas. It should
not function as a wish list, collection of feature requests or todo list.
For those please create a
[new issue](https://github.com/jupyterhub/jupyterhub/issues/new).
The roadmap should give the reader an idea of what is happening next, what needs
input and discussion before it can happen and what has been postponed.
## The roadmap proper
### Project vision
JupyterHub is a dependable tool used by humans that reduces the complexity of
creating the environment in which a piece of software can be executed.
### Now
These "Now" items are considered active areas of focus for the project:
* HubShare - a sharing service for use with JupyterHub.
* Users should be able to:
- Push a project to other users.
- Get a checkout of a project from other users.
- Push updates to a published project.
- Pull updates from a published project.
- Manage conflicts/merges by simply picking a version (our/theirs)
- Get a checkout of a project from the internet. These steps are completely different from saving notebooks/files.
- Have directories that are managed by git completely separately from our stuff.
- Look at pushed content that they have access to without an explicit pull.
- Define and manage teams of users.
- Adding/removing a user to/from a team gives/removes them access to all projects that team has access to.
- Build other services, such as static HTML publishing and dashboarding on top of these things.
### Soon
These "Soon" items are under discussion. Once an item reaches the point of an
actionable plan, the item will be moved to the "Now" section. Typically,
these will be moved at a future review of the roadmap.
* resource monitoring and management:
- (prometheus?) API for resource monitoring
- tracking activity on single-user servers instead of the proxy
- notes and activity tracking per API token
### Later
The "Later" items are things that are at the back of the project's mind. At this
time there is no active plan for an item. The project would like to find the
resources and time to discuss these ideas.
- real-time collaboration
- Enter into real-time collaboration mode for a project that starts a shared execution context.
- Once the single-user notebook package supports realtime collaboration,
implement sharing mechanism integrated into the Hub.

View File

@@ -1,10 +0,0 @@
Reporting security issues in Jupyter or JupyterHub
==================================================
If you find a security vulnerability in Jupyter or JupyterHub,
whether it is a failure of the security model described in :doc:`../reference/websecurity`
or a failure in implementation,
please report it to security@ipython.org.
If you prefer to encrypt your security reports,
you can use :download:`this PGP public key </ipython_security.asc>`.

View File

@@ -1,188 +0,0 @@
.. _contributing/setup:
================================
Setting up a development install
================================
System requirements
===================
JupyterHub can only run on MacOS or Linux operating systems. If you are
using Windows, we recommend using `VirtualBox <https://virtualbox.org>`_
or a similar system to run `Ubuntu Linux <https://ubuntu.com>`_ for
development.
Install Python
--------------
JupyterHub is written in the `Python <https://python.org>`_ programming language, and
requires you have at least version 3.5 installed locally. If you havent
installed Python before, the recommended way to install it is to use
`miniconda <https://conda.io/miniconda.html>`_. Remember to get the Python 3 version,
and **not** the Python 2 version!
Install nodejs
--------------
``configurable-http-proxy``, the default proxy implementation for
JupyterHub, is written in Javascript to run on `NodeJS
<https://nodejs.org/en/>`_. If you have not installed nodejs before, we
recommend installing it in the ``miniconda`` environment you set up for
Python. You can do so with ``conda install nodejs``.
Install git
-----------
JupyterHub uses `git <https://git-scm.com>`_ & `GitHub <https://github.com>`_
for development & collaboration. You need to `install git
<https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_ to work on
JupyterHub. We also recommend getting a free account on GitHub.com.
Setting up a development install
================================
When developing JupyterHub, you need to make changes to the code & see
their effects quickly. You need to do a developer install to make that
happen.
.. note:: This guide does not attempt to dictate *how* development
environements should be isolated since that is a personal preference and can
be achieved in many ways, for example `tox`, `conda`, `docker`, etc. See this
`forum thread <https://discourse.jupyter.org/t/thoughts-on-using-tox/3497>`_ for
a more detailed discussion.
1. Clone the `JupyterHub git repository <https://github.com/jupyterhub/jupyterhub>`_
to your computer.
.. code:: bash
git clone https://github.com/jupyterhub/jupyterhub
cd jupyterhub
2. Make sure the ``python`` you installed and the ``npm`` you installed
are available to you on the command line.
.. code:: bash
python -V
This should return a version number greater than or equal to 3.5.
.. code:: bash
npm -v
This should return a version number greater than or equal to 5.0.
3. Install ``configurable-http-proxy``. This is required to run
JupyterHub.
.. code:: bash
npm install -g configurable-http-proxy
If you get an error that says ``Error: EACCES: permission denied``,
you might need to prefix the command with ``sudo``. If you do not
have access to sudo, you may instead run the following commands:
.. code:: bash
npm install configurable-http-proxy
export PATH=$PATH:$(pwd)/node_modules/.bin
The second line needs to be run every time you open a new terminal.
4. Install the python packages required for JupyterHub development.
.. code:: bash
python3 -m pip install -r dev-requirements.txt
python3 -m pip install -r requirements.txt
5. Setup a database.
The default database engine is ``sqlite`` so if you are just trying
to get up and running quickly for local development that should be
available via `python <https://docs.python.org/3.5/library/sqlite3.html>`__.
See :doc:`/reference/database` for details on other supported databases.
6. Install the development version of JupyterHub. This lets you edit
JupyterHub code in a text editor & restart the JupyterHub process to
see your code changes immediately.
.. code:: bash
python3 -m pip install --editable .
7. You are now ready to start JupyterHub!
.. code:: bash
jupyterhub
8. You can access JupyterHub from your browser at
``http://localhost:8000`` now.
Happy developing!
Using DummyAuthenticator & SimpleLocalProcessSpawner
====================================================
To simplify testing of JupyterHub, its helpful to use
:class:`~jupyterhub.auth.DummyAuthenticator` instead of the default JupyterHub
authenticator and SimpleLocalProcessSpawner instead of the default spawner.
There is a sample configuration file that does this in
``testing/jupyterhub_config.py``. To launch jupyterhub with this
configuration:
.. code:: bash
jupyterhub -f testing/jupyterhub_config.py
The default JupyterHub `authenticator
<https://jupyterhub.readthedocs.io/en/stable/reference/authenticators.html#the-default-pam-authenticator>`_
& `spawner
<https://jupyterhub.readthedocs.io/en/stable/api/spawner.html#localprocessspawner>`_
require your system to have user accounts for each user you want to log in to
JupyterHub as.
DummyAuthenticator allows you to log in with any username & password,
while SimpleLocalProcessSpawner allows you to start servers without having to
create a unix user for each JupyterHub user. Together, these make it
much easier to test JupyterHub.
Tip: If you are working on parts of JupyterHub that are common to all
authenticators & spawners, we recommend using both DummyAuthenticator &
SimpleLocalProcessSpawner. If you are working on just authenticator related
parts, use only SimpleLocalProcessSpawner. Similarly, if you are working on
just spawner related parts, use only DummyAuthenticator.
Troubleshooting
===============
This section lists common ways setting up your development environment may
fail, and how to fix them. Please add to the list if you encounter yet
another way it can fail!
``lessc`` not found
-------------------
If the ``python3 -m pip install --editable .`` command fails and complains about
``lessc`` being unavailable, you may need to explicitly install some
additional JavaScript dependencies:
.. code:: bash
npm install
This will fetch client-side JavaScript dependencies necessary to compile
CSS.
You may also need to manually update JavaScript and CSS after some
development updates, with:
.. code:: bash
python3 setup.py js # fetch updated client-side js
python3 setup.py css # recompile CSS from LESS sources

View File

@@ -1,68 +0,0 @@
.. _contributing/tests:
==================
Testing JupyterHub
==================
Unit test help validate that JupyterHub works the way we think it does,
and continues to do so when changes occur. They also help communicate
precisely what we expect our code to do.
JupyterHub uses `pytest <https://pytest.org>`_ for all our tests. You
can find them under ``jupyterhub/tests`` directory in the git repository.
Running the tests
==================
#. Make sure you have completed :ref:`contributing/setup`. You should be able
to start ``jupyterhub`` from the commandline & access it from your
web browser. This ensures that the dev environment is properly set
up for tests to run.
#. You can run all tests in JupyterHub
.. code-block:: bash
pytest -v jupyterhub/tests
This should display progress as it runs all the tests, printing
information about any test failures as they occur.
If you wish to confirm test coverage the run tests with the `--cov` flag:
.. code-block:: bash
pytest -v --cov=jupyterhub jupyterhub/tests
#. You can also run tests in just a specific file:
.. code-block:: bash
pytest -v jupyterhub/tests/<test-file-name>
#. To run a specific test only, you can do:
.. code-block:: bash
pytest -v jupyterhub/tests/<test-file-name>::<test-name>
This runs the test with function name ``<test-name>`` defined in
``<test-file-name>``. This is very useful when you are iteratively
developing a single test.
For example, to run the test ``test_shutdown`` in the file ``test_api.py``,
you would run:
.. code-block:: bash
pytest -v jupyterhub/tests/test_api.py::test_shutdown
Troubleshooting Test Failures
=============================
All the tests are failing
-------------------------
Make sure you have completed all the steps in :ref:`contributing/setup` successfully, and
can launch ``jupyterhub`` from the terminal.

View File

@@ -1,50 +0,0 @@
Eventlogging and Telemetry
==========================
JupyterHub can be configured to record structured events from a running server using Jupyter's `Telemetry System`_. The types of events that JupyterHub emits are defined by `JSON schemas`_ listed below_
emitted as JSON data, defined and validated by the JSON schemas listed below.
.. _logging: https://docs.python.org/3/library/logging.html
.. _`Telemetry System`: https://github.com/jupyter/telemetry
.. _`JSON schemas`: https://json-schema.org/
How to emit events
------------------
Event logging is handled by its ``Eventlog`` object. This leverages Python's standing logging_ library to emit, filter, and collect event data.
To begin recording events, you'll need to set two configurations:
1. ``handlers``: tells the EventLog *where* to route your events. This trait is a list of Python logging handlers that route events to
2. ``allows_schemas``: tells the EventLog *which* events should be recorded. No events are emitted by default; all recorded events must be listed here.
Here's a basic example:
.. code-block::
import logging
c.EventLog.handlers = [
logging.FileHandler('event.log'),
]
c.EventLog.allowed_schemas = [
'hub.jupyter.org/server-action'
]
The output is a file, ``"event.log"``, with events recorded as JSON data.
.. _below:
Event schemas
-------------
.. toctree::
:maxdepth: 2
server-actions.rst

View File

@@ -1 +0,0 @@
.. jsonschema:: ../../../jupyterhub/event-schemas/server-actions/v1.yaml

View File

@@ -77,25 +77,16 @@ easy to do with RStudio too.
- Earth Lab at CU
- [Tutorial on Parallel R on JupyterHub](https://earthdatascience.org/tutorials/parallel-r-on-jupyterhub/)
### George Washington University
- [Jupyter Hub](http://go.gwu.edu/jupyter) with university single-sign-on. Deployed early 2017.
### HTCondor
- [HTCondor Python Bindings Tutorial from HTCondor Week 2017 includes information on their JupyterHub tutorials](https://research.cs.wisc.edu/htcondor/HTCondorWeek2017/presentations/TueBockelman_Python.pdf)
### University of Illinois
- https://datascience.business.illinois.edu (currently down; checked 04/26/19)
### IllustrisTNG Simulation Project
- [JupyterHub/Lab-based analysis platform, part of the TNG public data release](http://www.tng-project.org/data/)
- https://datascience.business.illinois.edu
### MIT and Lincoln Labs
- https://supercloud.mit.edu/
### Michigan State University
@@ -109,15 +100,6 @@ easy to do with RStudio too.
- https://dsa.missouri.edu/faq/
### Paderborn University
- [Data Science (DICE) group](https://dice.cs.uni-paderborn.de/)
- [nbgraderutils](https://github.com/dice-group/nbgraderutils): Use JupyterHub + nbgrader + iJava kernel for online Java exercises. Used in lecture Statistical Natural Language Processing.
### Penn State University
- [Press release](https://news.psu.edu/story/523093/2018/05/24/new-open-source-web-apps-available-students-and-faculty): "New open-source web apps available for students and faculty" (but Hub is currently down; checked 04/26/19)
### University of Rochester CIRC
- [JupyterHub Userguide](https://info.circ.rochester.edu/Web_Applications/JupyterHub.html) - Slurm, beehive
@@ -142,10 +124,7 @@ easy to do with RStudio too.
- Kristen Thyng - Oceanography
- [Teaching with JupyterHub and nbgrader](http://kristenthyng.com/blog/2016/09/07/jupyterhub+nbgrader/)
### Elucidata
- What's new in Jupyter Notebooks @[Elucidata](https://elucidata.io/):
- Using Jupyter Notebooks with Jupyterhub on GCP, managed by GKE
- https://medium.com/elucidata/why-you-should-be-using-a-jupyter-notebook-8385a4ccd93d
## Service Providers
@@ -162,6 +141,7 @@ easy to do with RStudio too.
[Everware](https://github.com/everware) Reproducible and reusable science powered by jupyterhub and docker. Like nbviewer, but executable. CERN, Geneva [website](http://everware.xyz/)
### Microsoft Azure
- https://docs.microsoft.com/en-us/azure/machine-learning/machine-learning-data-science-linux-dsvm-intro
@@ -171,11 +151,9 @@ easy to do with RStudio too.
- https://getcarina.com/blog/learning-how-to-whale/
- http://carolynvanslyck.com/talk/carina/jupyterhub/#/
### Hadoop
- [Deploying JupyterHub on Hadoop](https://jupyterhub-on-hadoop.readthedocs.io)
### jcloud.io
- Open to public JupyterHub server
- https://jcloud.io
## Miscellaneous
- https://medium.com/@ybarraud/setting-up-jupyterhub-with-sudospawner-and-anaconda-844628c0dbee#.rm3yt87e1

View File

@@ -4,23 +4,23 @@ The default Authenticator uses [PAM][] to authenticate system users with
their username and password. With the default Authenticator, any user
with an account and password on the system will be allowed to login.
## Create a set of allowed users
## Create a whitelist of users
You can restrict which users are allowed to login with a set,
`Authenticator.allowed_users`:
You can restrict which users are allowed to login with a whitelist,
`Authenticator.whitelist`:
```python
c.Authenticator.allowed_users = {'mal', 'zoe', 'inara', 'kaylee'}
c.Authenticator.whitelist = {'mal', 'zoe', 'inara', 'kaylee'}
```
Users in the `allowed_users` set are added to the Hub database when the Hub is
Users in the whitelist are added to the Hub database when the Hub is
started.
## Configure admins (`admin_users`)
Admin users of JupyterHub, `admin_users`, can add and remove users from
the user `allowed_users` set. `admin_users` can take actions on other users'
the user `whitelist`. `admin_users` can take actions on other users'
behalf, such as stopping and restarting their servers.
A set of initial admin users, `admin_users` can configured be as follows:
@@ -28,18 +28,9 @@ A set of initial admin users, `admin_users` can configured be as follows:
```python
c.Authenticator.admin_users = {'mal', 'zoe'}
```
Users in the admin set are automatically added to the user `allowed_users` set,
Users in the admin list are automatically added to the user `whitelist`,
if they are not already present.
Each authenticator may have different ways of determining whether a user is an
administrator. By default JupyterHub use the PAMAuthenticator which provide the
`admin_groups` option and can determine administrator status base on a user
groups. For example we can let any users in the `wheel` group be admin:
```python
c.PAMAuthenticator.admin_groups = {'wheel'}
```
## Give admin access to other users' notebook servers (`admin_access`)
Since the default `JupyterHub.admin_access` setting is False, the admins
@@ -53,12 +44,12 @@ sure your users know if admin_access is enabled.**
Users can be added to and removed from the Hub via either the admin
panel or the REST API. When a user is **added**, the user will be
automatically added to the allowed users set and database. Restarting the Hub
will not require manually updating the allowed users set in your config file,
automatically added to the whitelist and database. Restarting the Hub
will not require manually updating the whitelist in your config file,
as the users will be loaded from the database.
After starting the Hub once, it is not sufficient to **remove** a user
from the allowed users set in your config file. You must also remove the user
from the whitelist in your config file. You must also remove the user
from the Hub's database, either by deleting the user from JupyterHub's
admin page, or you can clear the `jupyterhub.sqlite` database and start
fresh.
@@ -104,16 +95,5 @@ popular services:
A generic implementation, which you can use for OAuth authentication
with any provider, is also available.
## Use DummyAuthenticator for testing
The :class:`~jupyterhub.auth.DummyAuthenticator` is a simple authenticator that
allows for any username/password unless if a global password has been set. If
set, it will allow for any username as long as the correct password is provided.
To set a global password, add this to the config file:
```python
c.DummyAuthenticator.password = "some_password"
```
[PAM]: https://en.wikipedia.org/wiki/Pluggable_authentication_module
[OAuthenticator]: https://github.com/jupyterhub/oauthenticator

View File

@@ -1,7 +1,7 @@
# Configuration Basics
The section contains basic information about configuring settings for a JupyterHub
deployment. The [Technical Reference](../reference/index)
deployment. The [Technical Reference](../reference/index.html)
documentation provides additional details.
This section will help you learn how to:
@@ -44,7 +44,7 @@ jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
```
The IPython documentation provides additional information on the
[config system](http://ipython.readthedocs.io/en/stable/development/config)
[config system](http://ipython.readthedocs.io/en/stable/development/config.html)
that Jupyter uses.
## Configure using command line options
@@ -77,24 +77,11 @@ jupyterhub --Spawner.notebook_dir='~/assignments'
## Configure for various deployment environments
The default authentication and process spawning mechanisms can be replaced, and
specific [authenticators](./authenticators-users-basics) and
[spawners](./spawners-basics) can be set in the configuration file.
specific [authenticators](./authenticators-users-basics.html) and
[spawners](./spawners-basics.html) can be set in the configuration file.
This enables JupyterHub to be used with a variety of authentication methods or
process control and deployment environments. [Some examples](../reference/config-examples),
process control and deployment environments. [Some examples](../reference/config-examples.html),
meant as illustration, are:
- Using GitHub OAuth instead of PAM with [OAuthenticator](https://github.com/jupyterhub/oauthenticator)
- Spawning single-user servers with Docker, using the [DockerSpawner](https://github.com/jupyterhub/dockerspawner)
## Run the proxy separately
This is *not* strictly necessary, but useful in many cases. If you
use a custom proxy (e.g. Traefik), this also not needed.
Connections to user servers go through the proxy, and *not* the hub
itself. If the proxy stays running when the hub restarts (for
maintenance, re-configuration, etc.), then use connections are not
interrupted. For simplicity, by default the hub starts the proxy
automatically, so if the hub restarts, the proxy restarts, and user
connections are interrupted. It is easy to run the proxy separately,
for information see [the separate proxy page](../reference/separate-proxy).

View File

@@ -1,36 +0,0 @@
# Frequently asked questions
### How do I share links to notebooks?
In short, where you see `/user/name/notebooks/foo.ipynb` use `/hub/user-redirect/notebooks/foo.ipynb` (replace `/user/name` with `/hub/user-redirect`).
Sharing links to notebooks is a common activity,
and can look different based on what you mean.
Your first instinct might be to copy the URL you see in the browser,
e.g. `hub.jupyter.org/user/yourname/notebooks/coolthing.ipynb`.
However, let's break down what this URL means:
`hub.jupyter.org/user/yourname/` is the URL prefix handled by *your server*,
which means that sharing this URL is asking the person you share the link with
to come to *your server* and look at the exact same file.
In most circumstances, this is forbidden by permissions because the person you share with does not have access to your server.
What actually happens when someone visits this URL will depend on whether your server is running and other factors.
But what is our actual goal?
A typical situation is that you have some shared or common filesystem,
such that the same path corresponds to the same document
(either the exact same document or another copy of it).
Typically, what folks want when they do sharing like this
is for each visitor to open the same file *on their own server*,
so Breq would open `/user/breq/notebooks/foo.ipynb` and
Seivarden would open `/user/seivarden/notebooks/foo.ipynb`, etc.
JupyterHub has a special URL that does exactly this!
It's called `/hub/user-redirect/...` and after the visitor logs in,
So if you replace `/user/yourname` in your URL bar
with `/hub/user-redirect` any visitor should get the same
URL on their own server, rather than visiting yours.
In JupyterLab 2.0, this should also be the result of the "Copy Shareable Link"
action in the file browser.

View File

@@ -1,10 +1,5 @@
Get Started
===========
This section covers how to configure and customize JupyterHub for your
needs. It contains information about authentication, networking, security, and
other topics that are relevant to individuals or organizations deploying their
own JupyterHub.
Getting Started
===============
.. toctree::
:maxdepth: 2
@@ -15,5 +10,3 @@ own JupyterHub.
authenticators-users-basics
spawners-basics
services-basics
faq
institutional-faq

View File

@@ -1,266 +0,0 @@
# Institutional FAQ
This page contains common questions from users of JupyterHub,
broken down by their roles within organizations.
## For all
### Is it appropriate for adoption within a larger institutional context?
Yes! JupyterHub has been used at-scale for large pools of users, as well
as complex and high-performance computing. For example, UC Berkeley uses
JupyterHub for its Data Science Education Program courses (serving over
3,000 students). The Pangeo project uses JupyterHub to provide access
to scalable cloud computing with Dask. JupyterHub is stable customizable
to the use-cases of large organizations.
### I keep hearing about Jupyter Notebook, JupyterLab, and now JupyterHub. Whats the difference?
Here is a quick breakdown of these three tools:
* **The Jupyter Notebook** is a document specification (the `.ipynb`) file that interweaves
narrative text with code cells and their outputs. It is also a graphical interface
that allows users to edit these documents. There are also several other graphical interfaces
that allow users to edit the `.ipynb` format (nteract, Jupyter Lab, Google Colab, Kaggle, etc).
* **JupyterLab** is a flexible and extendible user interface for interactive computing. It
has several extensions that are tailored for using Jupyter Notebooks, as well as extensions
for other parts of the data science stack.
* **JupyterHub** is an application that manages interactive computing sessions for **multiple users**.
It also connects them with infrastructure those users wish to access. It can provide
remote access to Jupyter Notebooks and Jupyter Lab for many people.
## For management
### Briefly, what problem does JupyterHub solve for us?
JupyterHub provides a shared platform for data science and collaboration.
It allows users to utilize familiar data science workflows (such as the scientific python stack,
the R tidyverse, and Jupyter Notebooks) on institutional infrastructure. It also allows administrators
some control over access to resources, security, environments, and authentication.
### Is JupyterHub mature? Why should we trust it?
Yes - the core JupyterHub application recently
reached 1.0 status, and is considered stable and performant for most institutions.
JupyterHub has also been deployed (along with other tools) to work on
scalable infrastructure, large datasets, and high-performance computing.
### Who else uses JupyterHub?
JupyterHub is used at a variety of institutions in academia,
industry, and government research labs. It is most-commonly used by two kinds of groups:
* Small teams (e.g., data science teams, research labs, or collaborative projects) to provide a
shared resource for interactive computing, collaboration, and analytics.
* Large teams (e.g., a department, a large class, or a large group of remote users) to provide
access to organizational hardware, data, and analytics environments at scale.
Here are a sample of organizations that use JupyterHub:
* **Universities and colleges**: UC Berkeley, UC San Diego, Cal Poly SLO, Harvard University, University of Chicago,
University of Oslo, University of Sheffield, Université Paris Sud, University of Versailles
* **Research laboratories**: NASA, NCAR, NOAA, the Large Synoptic Survey Telescope, Brookhaven National Lab,
Minnesota Supercomputing Institute, ALCF, CERN, Lawrence Livermore National Laboratory
* **Online communities**: Pangeo, Quantopian, mybinder.org, MathHub, Open Humans
* **Computing infrastructure providers**: NERSC, San Diego Supercomputing Center, Compute Canada
* **Companies**: Capital One, SANDVIK code, Globus
See the [Gallery of JupyterHub deployments](../gallery-jhub-deployments.md) for
a more complete list of JupyterHub deployments at institutions.
### How does JupyterHub compare with hosted products, like Google Colaboratory, RStudio.cloud, or Anaconda Enterprise?
JupyterHub puts you in control of your data, infrastructure, and coding environment.
In addition, it is vendor neutral, which reduces lock-in to a particular vendor or service.
JupyterHub provides access to interactive computing environments in the cloud (similar to each of these services).
Compared with the tools above, it is more flexible, more customizable, free, and
gives administrators more control over their setup and hardware.
Because JupyterHub is an open-source, community-driven tool, it can be extended and
modified to fit an institution's needs. It plays nicely with the open source data science
stack, and can serve a variety of computing enviroments, user interfaces, and
computational hardware. It can also be deployed anywhere - on enterprise cloud infrastructure, on
High-Performance-Computing machines, on local hardware, or even on a single laptop, which
is not possible with most other tools for shared interactive computing.
## For IT
### How would I set up JupyterHub on institutional hardware?
That depends on what kind of hardware you've got. JupyterHub is flexible enough to be deployed
on a variety of hardware, including in-room hardware, on-prem clusters, cloud infrastructure,
etc.
The most common way to set up a JupyterHub is to use a JupyterHub distribution, these are pre-configured
and opinionated ways to set up a JupyterHub on particular kinds of infrastructure. The two distributions
that we currently suggest are:
* [Zero to JupyterHub for Kubernetes](https://z2jh.jupyter.org) is a scalable JupyterHub deployment and
guide that runs on Kubernetes. Better for larger or dynamic user groups (50-10,000) or more complex
compute/data needs.
* [The Littlest JupyterHub](https://tljh.jupyter.org) is a lightweight JupyterHub that runs on a single
single machine (in the cloud or under your desk). Better for smaller usergroups (4-80) or more
lightweight computational resources.
### Does JupyterHub run well in the cloud?
Yes - most deployments of JupyterHub are run via cloud infrastructure and on a variety of cloud providers.
Depending on the distribution of JupyterHub that you'd like to use, you can also connect your JupyterHub
deployment with a number of other cloud-native services so that users have access to other resources from
their interactive computing sessions.
For example, if you use the [Zero to JupyterHub for Kubernetes](https://z2jh.jupyter.org) distribution,
you'll be able to utilize container-based workflows of other technologies such as the [dask-kubernetes](https://kubernetes.dask.org/en/latest/)
project for distributed computing.
The Z2JH Helm Chart also has some functionality built in for auto-scaling your cluster up and down
as more resources are needed - allowing you to utilize the benefits of a flexible cloud-based deployment.
### Is JupyterHub secure?
The short answer: yes. JupyterHub as a standalone application has been battle-tested at an institutional
level for several years, and makes a number of "default" security decisions that are reasonable for most
users.
* For security considerations in the base JupyterHub application,
[see the JupyterHub security page](https://jupyterhub.readthedocs.io/en/stable/reference/websecurity.html)
* For security considerations when deploying JupyterHub on Kubernetes, see the
[JupyterHub on Kubernetes security page](https://zero-to-jupyterhub.readthedocs.io/en/latest/security.html).
The longer answer: it depends on your deployment. Because JupyterHub is very flexible, it can be used
in a variety of deployment setups. This often entails connecting your JupyterHub to **other** infrastructure
(such as a [Dask Gateway service](https://gateway.dask.org/)). There are many security decisions to be made
in these cases, and the security of your JupyterHub deployment will often depend on these decisions.
If you are worried about security, don't hesitate to reach out to the JupyterHub community in the
[Jupyter Community Forum](https://discourse.jupyter.org/c/jupyterhub). This community of practice has many
individuals with experience running secure JupyterHub deployments.
### Does JupyterHub provide computing or data infrastructure?
No - JupyterHub manages user sessions and can *control* computing infrastructure, but it does not provide these
things itself. You are expected to run JupyterHub on your own infrastructure (local or in the cloud). Moreover,
JupyterHub has no internal concept of "data", but is designed to be able to communicate with data repositories
(again, either locally or remotely) for use within interactive computing sessions.
### How do I manage users?
JupyterHub offers a few options for managing your users. Upon setting up a JupyterHub, you can choose what
kind of **authentication** you'd like to use. For example, you can have users sign up with an institutional
email address, or choose a username / password when they first log-in, or offload authentication onto
another service such as an organization's OAuth.
The users of a JupyterHub are stored locally, and can be modified manually by an administrator of the JupyterHub.
Moreover, the *active* users on a JupyterHub can be found on the administrator's page. This page
gives you the abiltiy to stop or restart kernels, inspect user filesystems, and even take over user
sessions to assist them with debugging.
### How do I manage software environments?
A key benefit of JupyterHub is the ability for an administrator to define the environment(s) that users
have access to. There are many ways to do this, depending on what kind of infrastructure you're using for
your JupyterHub.
For example, **The Littlest JupyterHub** runs on a single VM. In this case, the administrator defines
an environment by installing packages to a shared folder that exists on the path of all users. The
**JupyterHub for Kubernetes** deployment uses Docker images to define environments. You can create your
own list of Docker images that users can select from, and can also control things like the amount of
RAM available to users, or the types of machines that their sessions will use in the cloud.
### How does JupyterHub manage computational resources?
For interactive computing sessions, JupyterHub controls computational resources via a **spawner**.
Spawners define how a new user session is created, and are customized for particular kinds of
infrastructure. For example, the KubeSpawner knows how to control a Kubernetes deployment
to create new pods when users log in.
For more sophisticated computational resources (like distributed computing), JupyterHub can
connect with other infrastructure tools (like Dask or Spark). This allows users to control
scalable or high-performance resources from within their JupyterHub sessions. The logic of
how those resources are controlled is taken care of by the non-JupyterHub application.
### Can JupyterHub be used with my high-performance computing resources?
Yes - JupyterHub can provide access to many kinds of computing infrastructure.
Especially when combined with other open-source schedulers such as Dask, you can manage fairly
complex computing infrastructure from the interactive sessions of a JupyterHub. For example
[see the Dask HPC page](https://docs.dask.org/en/latest/setup/hpc.html).
### How much resources do user sessions take?
This is highly configurable by the administrator. If you wish for your users to have simple
data analytics environments for prototyping and light data exploring, you can restrict their
memory and CPU based on the resources that you have available. If you'd like your JupyterHub
to serve as a gateway to high-performance compute or data resources, you may increase the
resources available on user machines, or connect them with computing infrastructure elsewhere.
### Can I customize the look and feel of a JupyterHub?
JupyterHub provides some customization of the graphics displayed to users. The most common
modification is to add custom branding to the JupyterHub login page, loading pages, and
various elements that persist across all pages (such as headers).
## For Technical Leads
### Will JupyterHub “just work” with our team's interactive computing setup?
Depending on the complexity of your setup, you'll have different experiences with "out of the box"
distributions of JupyterHub. If all of the resources you need will fit on a single VM, then
[The Littlest JupyterHub](https://tljh.jupyter.org) should get you up-and-running within
a half day or so. For more complex setups, such as scalable Kubernetes clusters or access
to high-performance computing and data, it will require more time and expertise with
the technologies your JupyterHub will use (e.g., dev-ops knowledge with cloud computing).
In general, the base JupyterHub deployment is not the bottleneck for setup, it is connecting
your JupyterHub with the various services and tools that you wish to provide to your users.
### How well does JupyterHub scale? What are JupyterHub's limitations?
JupyterHub works well at both a small scale (e.g., a single VM or machine) as well as a
high scale (e.g., a scalable Kubernetes cluster). It can be used for teams as small a 2, and
for user bases as large as 10,000. The scalability of JupyterHub largely depends on the
infrastructure on which it is deployed. JupyterHub has been designed to be lightweight and
flexible, so you can tailor your JupyterHub deployment to your needs.
### Is JupyterHub resilient? What happens when a machine goes down?
For JupyterHubs that are deployed in a containerized environment (e.g., Kubernetes), it is
possible to configure the JupyterHub to be fairly resistant to failures in the system.
For example, if JupyterHub fails, then user sessions will not be affected (though new
users will not be able to log in). When a JupyterHub process is restarted, it should
seamlessly connect with the user database and the system will return to normal.
Again, the details of your JupyterHub deployment (e.g., whether it's deployed on a scalable cluster)
will affect the resiliency of the deployment.
### What interfaces does JupyterHub support?
Out of the box, JupyterHub supports a variety of popular data science interfaces for user sessions,
such as JupyterLab, Jupyter Notebooks, and RStudio. Any interface that can be served
via a web address can be served with a JupyterHub (with the right setup).
### Does JupyterHub make it easier for our team to collaborate?
JupyterHub provides a standardized environment and access to shared resources for your teams.
This greatly reduces the cost associated with sharing analyses and content with other team
members, and makes it easier to collaborate and build off of one another's ideas. Combined with
access to high-performance computing and data, JupyterHub provides a common resource to
amplify your team's ability to prototype their analyses, scale them to larger data, and then
share their results with one another.
JupyterHub also provides a computational framework to share computational narratives between
different levels of an organization. For example, data scientists can share Jupyter Notebooks
rendered as [voila dashboards](https://voila.readthedocs.io/en/stable/) with those who are not
familiar with programming, or create publicly-available interactive analyses to allow others to
interact with your work.
### Can I use JupyterHub with R/RStudio or other languages and environments?
Yes, Jupyter is a polyglot project, and there are over 40 community-provided kernels for a variety
of languages (the most common being Python, Julia, and R). You can also use a JupyterHub to provide
access to other interfaces, such as RStudio, that provide their own access to a language kernel.

View File

@@ -41,7 +41,7 @@ port.
## Set the Proxy's REST API communication URL (optional)
By default, this REST API listens on port 8001 of `localhost` only.
By default, this REST API listens on port 8081 of `localhost` only.
The Hub service talks to the proxy via a REST API on a secondary port. The
API URL can be configured separately and override the default settings.

View File

@@ -80,49 +80,6 @@ To achieve this, simply omit the configuration settings
``c.JupyterHub.ssl_key`` and ``c.JupyterHub.ssl_cert``
(setting them to ``None`` does not have the same effect, and is an error).
.. _authentication-token:
Proxy authentication token
--------------------------
The Hub authenticates its requests to the Proxy using a secret token that
the Hub and Proxy agree upon. Note that this applies to the default
``ConfigurableHTTPProxy`` implementation. Not all proxy implementations
use an auth token.
The value of this token should be a random string (for example, generated by
``openssl rand -hex 32``). You can store it in the configuration file or an
environment variable
Generating and storing token in the configuration file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can set the value in the configuration file, ``jupyterhub_config.py``:
.. code-block:: python
c.ConfigurableHTTPProxy.api_token = 'abc123...' # any random string
Generating and storing as an environment variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can pass this value of the proxy authentication token to the Hub and Proxy
using the ``CONFIGPROXY_AUTH_TOKEN`` environment variable:
.. code-block:: bash
export CONFIGPROXY_AUTH_TOKEN=$(openssl rand -hex 32)
This environment variable needs to be visible to the Hub and Proxy.
Default if token is not set
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you don't set the Proxy authentication token, the Hub will generate a random
key itself, which means that any time you restart the Hub you **must also
restart the Proxy**. If the proxy is a subprocess of the Hub, this should happen
automatically (this is the default configuration).
.. _cookie-secret:
Cookie secret
@@ -167,7 +124,7 @@ hex-encoded string. You can set it this way:
.. code-block:: bash
export JPY_COOKIE_SECRET=$(openssl rand -hex 32)
export JPY_COOKIE_SECRET=`openssl rand -hex 32`
For security reasons, this environment variable should only be visible to the
Hub. If you set it dynamically as above, all users will be logged out each time
@@ -189,73 +146,41 @@ itself, ``jupyterhub_config.py``, as a binary string:
If the cookie secret value changes for the Hub, all single-user notebook
servers must also be restarted.
.. _cookies:
Cookies used by JupyterHub authentication
-----------------------------------------
.. _authentication-token:
The following cookies are used by the Hub for handling user authentication.
Proxy authentication token
--------------------------
This section was created based on this post_ from Discourse.
The Hub authenticates its requests to the Proxy using a secret token that
the Hub and Proxy agree upon. The value of this string should be a random
string (for example, generated by ``openssl rand -hex 32``).
.. _post: https://discourse.jupyter.org/t/how-to-force-re-login-for-users/1998/6
Generating and storing token in the configuration file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jupyterhub-hub-login
~~~~~~~~~~~~~~~~~~~~
Or you can set the value in the configuration file, ``jupyterhub_config.py``:
This is the login token used when visiting Hub-served pages that are
protected by authentication such as the main home, the spawn form, etc.
If this cookie is set, then the user is logged in.
.. code-block:: python
Resetting the Hub cookie secret effectively revokes this cookie.
c.JupyterHub.proxy_auth_token = '0bc02bede919e99a26de1e2a7a5aadfaf6228de836ec39a05a6c6942831d8fe5'
This cookie is restricted to the path ``/hub/``.
Generating and storing as an environment variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jupyterhub-user-<username>
~~~~~~~~~~~~~~~~~~~~~~~~~~
You can pass this value of the proxy authentication token to the Hub and Proxy
using the ``CONFIGPROXY_AUTH_TOKEN`` environment variable:
This is the cookie used for authenticating with a single-user server.
It is set by the single-user server after OAuth with the Hub.
.. code-block:: bash
Effectively the same as ``jupyterhub-hub-login``, but for the
single-user server instead of the Hub. It contains an OAuth access token,
which is checked with the Hub to authenticate the browser.
export CONFIGPROXY_AUTH_TOKEN='openssl rand -hex 32'
Each OAuth access token is associated with a session id (see ``jupyterhub-session-id`` section
below).
This environment variable needs to be visible to the Hub and Proxy.
To avoid hitting the Hub on every request, the authentication response
is cached. And to avoid a stale cache the cache key is comprised of both
the token and session id.
Default if token is not set
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Resetting the Hub cookie secret effectively revokes this cookie.
This cookie is restricted to the path ``/user/<username>``, so that
only the users server receives it.
jupyterhub-session-id
~~~~~~~~~~~~~~~~~~~~~
This is a random string, meaningless in itself, and the only cookie
shared by the Hub and single-user servers.
Its sole purpose is to coordinate logout of the multiple OAuth cookies.
This cookie is set to ``/`` so all endpoints can receive it, or clear it, etc.
jupyterhub-user-<username>-oauth-state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A short-lived cookie, used solely to store and validate OAuth state.
It is only set while OAuth between the single-user server and the Hub
is processing.
If you use your browser development tools, you should see this cookie
for a very brief moment before your are logged in,
with an expiration date shorter than ``jupyterhub-hub-login`` or
``jupyterhub-user-<username>``.
This cookie should not exist after you have successfully logged in.
This cookie is restricted to the path ``/user/<username>``, so that only
the users server receives it.
If you don't set the Proxy authentication token, the Hub will generate a random
key itself, which means that any time you restart the Hub you **must also
restart the Proxy**. If the proxy is a subprocess of the Hub, this should happen
automatically (this is the default configuration).

View File

@@ -3,9 +3,9 @@
When working with JupyterHub, a **Service** is defined as a process
that interacts with the Hub's REST API. A Service may perform a specific
or action or task. For example, shutting down individuals' single user
notebook servers that have been idle for some time is a good example of
a task that could be automated by a Service. Let's look at how the
[jupyterhub_idle_culler][] script can be used as a Service.
notebook servers that have been is a good example of a task that could
be automated by a Service. Let's look at how the [cull_idle_servers][]
script can be used as a Service.
## Real-world example to cull idle servers
@@ -14,12 +14,12 @@ document will:
- explain some basic information about API tokens
- clarify that API tokens can be used to authenticate to
single-user servers as of [version 0.8.0](../changelog)
- show how the [jupyterhub_idle_culler][] script can be:
single-user servers as of [version 0.8.0](../changelog.html)
- show how the [cull_idle_servers][] script can be:
- used in a Hub-managed service
- run as a standalone script
Both examples for `jupyterhub_idle_culler` will communicate tasks to the
Both examples for `cull_idle_servers` will communicate tasks to the
Hub via the REST API.
## API Token basics
@@ -29,14 +29,14 @@ Hub via the REST API.
To run such an external service, an API token must be created and
provided to the service.
As of [version 0.6.0](../changelog), the preferred way of doing
As of [version 0.6.0](../changelog.html), the preferred way of doing
this is to first generate an API token:
```bash
openssl rand -hex 32
```
In [version 0.8.0](../changelog), a TOKEN request page for
In [version 0.8.0](../changelog.html), a TOKEN request page for
generating an API token is available from the JupyterHub user interface:
![Request API TOKEN page](../images/token-request.png)
@@ -78,23 +78,17 @@ single-user servers, and only cookies can be used for authentication.
0.8 supports using JupyterHub API tokens to authenticate to single-user
servers.
## Configure the idle culler to run as a Hub-Managed Service
Install the idle culler:
```
pip install jupyterhub-idle-culler
```
## Configure `cull-idle` to run as a Hub-Managed Service
In `jupyterhub_config.py`, add the following dictionary for the
`idle-culler` Service to the `c.JupyterHub.services` list:
`cull-idle` Service to the `c.JupyterHub.services` list:
```python
c.JupyterHub.services = [
{
'name': 'idle-culler',
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, '-m', 'jupyterhub_idle_culler', '--timeout=3600'],
'command': 'python3 cull_idle_servers.py --timeout=3600'.split(),
}
]
```
@@ -107,21 +101,21 @@ where:
## Run `cull-idle` manually as a standalone script
Now you can run your script by providing it
Now you can run your script, i.e. `cull_idle_servers`, by providing it
the API token and it will authenticate through the REST API to
interact with it.
This will run the idle culler service manually. It can be run as a standalone
This will run `cull-idle` manually. `cull-idle` can be run as a standalone
script anywhere with access to the Hub, and will periodically check for idle
servers and shut them down via the Hub's REST API. In order to shutdown the
servers, the token given to cull-idle must have admin privileges.
Generate an API token and store it in the `JUPYTERHUB_API_TOKEN` environment
variable. Run `jupyterhub_idle_culler` manually.
variable. Run `cull_idle_servers.py` manually.
```bash
export JUPYTERHUB_API_TOKEN='token'
python -m jupyterhub_idle_culler [--timeout=900] [--url=http://127.0.0.1:8081/hub/api]
python3 cull_idle_servers.py [--timeout=900] [--url=http://127.0.0.1:8081/hub/api]
```
[jupyterhub_idle_culler]: https://github.com/jupyterhub/jupyterhub-idle-culler
[cull_idle_servers]: https://github.com/jupyterhub/jupyterhub/blob/master/examples/cull-idle/cull_idle_servers.py

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -1,15 +0,0 @@
=====
About
=====
JupyterHub is an open source project and community. It is a part of the
`Jupyter Project <https://jupyter.org>`_. JupyterHub is an open and inclusive
community, and invites contributions from anyone. This section covers information
about our community, as well as ways that you can connect and get involved.
.. toctree::
:maxdepth: 1
contributor-list
changelog
gallery-jhub-deployments

View File

@@ -1,13 +0,0 @@
=====================
Administrator's Guide
=====================
This guide covers best-practices, tips, common questions and operations, as
well as other information relevant to running your own JupyterHub over time.
.. toctree::
:maxdepth: 2
troubleshooting
admin/upgrading
changelog

View File

@@ -1,38 +1,21 @@
==========
JupyterHub
==========
`JupyterHub`_ is the best way to serve `Jupyter notebook`_ for multiple users.
It can be used in a class of students, a corporate data science group or scientific
research group. It is a multi-user **Hub** that spawns, manages, and proxies multiple
`JupyterHub`_, a multi-user **Hub**, spawns, manages, and proxies multiple
instances of the single-user `Jupyter notebook`_ server.
JupyterHub can be used to serve notebooks to a class of students, a corporate
data science group, or a scientific research group.
To make life easier, JupyterHub has distributions. Be sure to
take a look at them before continuing with the configuration of the broad
original system of `JupyterHub`_. Today, you can find two main cases:
1. If you need a simple case for a small amount of users (0-100) and single server
take a look at
`The Littlest JupyterHub <https://github.com/jupyterhub/the-littlest-jupyterhub>`__ distribution.
2. If you need to allow for even more users, a dynamic amount of servers can be used on a cloud,
take a look at the `Zero to JupyterHub with Kubernetes <https://github.com/jupyterhub/zero-to-jupyterhub-k8s>`__ .
Four subsystems make up JupyterHub:
* a **Hub** (tornado process) that is the heart of JupyterHub
* a **configurable http proxy** (node-http-proxy) that receives the requests from the client's browser
* multiple **single-user Jupyter notebook servers** (Python/IPython/tornado) that are monitored by Spawners
* an **authentication class** that manages how users can access the system
Besides these central pieces, you can add optional configurations through a `config.py` file and manage users kernels on an admin panel. A simplification of the whole system can be seen in the figure below:
.. image:: images/jhub-fluxogram.jpeg
.. image:: images/jhub-parts.png
:alt: JupyterHub subsystems
:width: 80%
:align: center
:width: 40%
:align: right
Three subsystems make up JupyterHub:
* a multi-user **Hub** (tornado process)
* a **configurable http proxy** (node-http-proxy)
* multiple **single-user Jupyter notebook servers** (Python/IPython/tornado)
JupyterHub performs the following functions:
@@ -45,106 +28,98 @@ JupyterHub performs the following functions:
For convenient administration of the Hub, its users, and services,
JupyterHub also provides a `REST API`_.
The JupyterHub team and Project Jupyter value our community, and JupyterHub
follows the Jupyter `Community Guides <https://jupyter.readthedocs.io/en/latest/community/content-community.html>`_.
Contents
========
--------
.. _index/distributions:
**Installation Guide**
Distributions
-------------
* :doc:`installation-guide`
* :doc:`quickstart`
* :doc:`quickstart-docker`
* :doc:`installation-basics`
A JupyterHub **distribution** is tailored towards a particular set of
use cases. These are generally easier to set up than setting up
JupyterHub from scratch, assuming they fit your use case.
**Getting Started**
The two popular ones are:
* :doc:`getting-started/index`
* :doc:`getting-started/config-basics`
* :doc:`getting-started/networking-basics`
* :doc:`getting-started/security-basics`
* :doc:`getting-started/authenticators-users-basics`
* :doc:`getting-started/spawners-basics`
* :doc:`getting-started/services-basics`
* `Zero to JupyterHub on Kubernetes <http://z2jh.jupyter.org>`_, for
running JupyterHub on top of `Kubernetes <https://k8s.io>`_. This
can scale to large number of machines & users.
* `The Littlest JupyterHub <http://tljh.jupyter.org>`_, for an easy
to set up & run JupyterHub supporting 1-100 users on a single machine.
**Technical Reference**
Installation Guide
------------------
* :doc:`reference/index`
* :doc:`reference/technical-overview`
* :doc:`reference/websecurity`
* :doc:`reference/authenticators`
* :doc:`reference/spawners`
* :doc:`reference/services`
* :doc:`reference/rest`
* :doc:`reference/upgrading`
* :doc:`reference/templates`
* :doc:`reference/config-user-env`
* :doc:`reference/config-examples`
* :doc:`reference/config-ghoauth`
* :doc:`reference/config-proxy`
* :doc:`reference/config-sudo`
.. toctree::
:maxdepth: 2
**API Reference**
installation-guide
* :doc:`api/index`
Getting Started
---------------
**Tutorials**
.. toctree::
:maxdepth: 2
* :doc:`tutorials/index`
* :doc:`tutorials/upgrade-dot-eight`
* `Zero to JupyterHub with Kubernetes <https://zero-to-jupyterhub.readthedocs.io/en/latest/>`_
getting-started/index
**Troubleshooting**
Technical Reference
-------------------
* :doc:`troubleshooting`
.. toctree::
:maxdepth: 2
**About JupyterHub**
reference/index
* :doc:`contributor-list`
* :doc:`gallery-jhub-deployments`
Administrators guide
--------------------
**Changelog**
.. toctree::
:maxdepth: 2
index-admin
API Reference
-------------
.. toctree::
:maxdepth: 2
api/index
Contributing
------------
We want you to contribute to JupyterHub in ways that are most exciting
& useful to you. We value documentation, testing, bug reporting & code equally,
and are glad to have your contributions in whatever form you wish :)
Our `Code of Conduct <https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md>`_
(`reporting guidelines <https://github.com/jupyter/governance/blob/master/conduct/reporting_online.md>`_)
helps keep our community welcoming to as many people as possible.
.. toctree::
:maxdepth: 2
contributing/index
About JupyterHub
----------------
.. toctree::
:maxdepth: 2
index-about
* :doc:`changelog`
Indices and tables
==================
------------------
* :ref:`genindex`
* :ref:`modindex`
Questions? Suggestions?
=======================
-----------------------
- `Jupyter mailing list <https://groups.google.com/forum/#!forum/jupyter>`_
- `Jupyter website <https://jupyter.org>`_
.. _contents:
Full Table of Contents
----------------------
.. toctree::
:maxdepth: 2
installation-guide
getting-started/index
reference/index
api/index
tutorials/index
troubleshooting
contributor-list
gallery-jhub-deployments
changelog
.. _JupyterHub: https://github.com/jupyterhub/jupyterhub
.. _Jupyter notebook: https://jupyter-notebook.readthedocs.io/en/latest/
.. _REST API: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default

View File

@@ -6,7 +6,7 @@ JupyterHub is supported on Linux/Unix based systems. To use JupyterHub, you need
a Unix server (typically Linux) running somewhere that is accessible to your
team on the network. The JupyterHub server can be on an internal network at your
organization, or it can run on the public internet (in which case, take care
with the Hub's [security](./getting-started/security-basics)).
with the Hub's [security](./security-basics.html)).
JupyterHub officially **does not** support Windows. You may be able to use
JupyterHub on Windows if you use a Spawner and Authenticator that work on

View File

@@ -1,347 +0,0 @@
# Install JupyterHub and JupyterLab from the ground up
The combination of [JupyterHub](https://jupyterhub.readthedocs.io) and [JupyterLab](https://jupyterlab.readthedocs.io)
is a great way to make shared computing resources available to a group.
These instructions are a guide for a manual, 'bare metal' install of [JupyterHub](https://jupyterhub.readthedocs.io)
and [JupyterLab](https://jupyterlab.readthedocs.io). This is ideal for running on a single server: build a beast
of a machine and share it within your lab, or use a virtual machine from any VPS or cloud provider.
This guide has similar goals to [The Littlest JupyterHub](https://the-littlest-jupyterhub.readthedocs.io) setup
script. However, instead of bundling all these step for you into one installer, we will perform every step manually.
This makes it easy to customize any part (e.g. if you want to run other services on the same system and need to make them
work together), as well as giving you full control and understanding of your setup.
## Prerequisites
Your own server with administrator (root) access. This could be a local machine, a remotely hosted one, or a cloud instance
or VPS. Each user who will access JupyterHub should have a standard user account on the machine. The install will be done
through the command line - useful if you log into your machine remotely using SSH.
This tutorial was tested on **Ubuntu 18.04**. No other Linux distributions have been tested, but the instructions
should be reasonably straightforward to adapt.
## Goals
JupyterLab enables access to a multiple 'kernels', each one being a given environment for a given language. The most
common is a Python environment, for scientific computing usually one managed by the `conda` package manager.
This guide will set up JupyterHub and JupyterLab seperately from the Python environment. In other words, we treat
JupyterHub+JupyterLab as a 'app' or webservice, which will connect to the kernels available on the system. Specifically:
- We will create an installation of JupyterHub and JupyterLab using a virtualenv under `/opt` using the system Python.
- We will install conda globally.
- We will create a shared conda environment which can be used (but not modified) by all users.
- We will show how users can create their own private conda environments, where they can install whatever they like.
The default JupyterHub Authenticator uses PAM to authenticate system users with their username and password. One can
[choose the authenticator](https://jupyterhub.readthedocs.io/en/stable/reference/authenticators.html#authenticators)
that best suits their needs. In this guide we will use the default Authenticator because it makes it easy for everyone to manage data
in their home folder and to mix and match different services and access methods (e.g. SSH) which all work using the
Linux system user accounts. Therefore, each user of JupyterHub will need a standard system user account.
Another goal of this guide is to use system provided packages wherever possible. This has the advantage that these packages
get automatic patches and security updates (be sure to turn on automatic updates in Ubuntu). This means less maintenance
work and a more reliable system.
## Part 1: JupyterHub and JupyterLab
### Setup the JupyterHub and JupyterLab in a virtual environment
First we create a virtual environment under '/opt/jupyterhub'. The '/opt' folder is where apps not belonging to the operating
system are [commonly installed](https://unix.stackexchange.com/questions/11544/what-is-the-difference-between-opt-and-usr-local).
Both jupyterlab and jupyterhub will be installed into this virtualenv. Create it with the command:
```sh
sudo python3 -m venv /opt/jupyterhub/
```
Now we use pip to install the required Python packages into the new virtual environment. Be sure to install
`wheel` first. Since we are separating the user interface from the computing kernels, we don't install
any Python scientific packages here. The only exception is `ipywidgets` because this is needed to allow connection
between interactive tools running in the kernel and the user interface.
Note that we use `/opt/jupyterhub/bin/python3 -m pip install` each time - this [makes sure](https://snarky.ca/why-you-should-use-python-m-pip/)
that the packages are installed to the correct virtual environment.
Perform the install using the following commands:
```sh
sudo /opt/jupyterhub/bin/python3 -m pip install wheel
sudo /opt/jupyterhub/bin/python3 -m pip install jupyterhub jupyterlab
sudo /opt/jupyterhub/bin/python3 -m pip install ipywidgets
```
JupyterHub also currently defaults to requiring `configurable-http-proxy`, which needs `nodejs` and `npm`. The versions
of these available in Ubuntu therefore need to be installed first (they are a bit old but this is ok for our needs):
```sh
sudo apt install nodejs npm
```
Then install `configurable-http-proxy`:
```sh
sudo npm install -g configurable-http-proxy
```
### Create the configuration for JupyterHub
Now we start creating configuration files. To keep everything together, we put all the configuration into the folder
created for the virtualenv, under `/opt/jupyterhub/etc/`. For each thing needing configuration, we will create a further
subfolder and necessary files.
First create the folder for the JupyterHub configuration and navigate to it:
```sh
sudo mkdir -p /opt/jupyterhub/etc/jupyterhub/
cd /opt/jupyterhub/etc/jupyterhub/
```
Then generate the default configuration file
```sh
sudo /opt/jupyterhub/bin/jupyterhub --generate-config
```
This will produce the default configuration file `/opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py`
You will need to edit the configuration file to make the JupyterLab interface by the default.
Set the following configuration option in your `jupyterhub_config.py` file:
```python
c.Spawner.default_url = '/lab'
```
Further configuration options may be found in the documentation.
### Setup Systemd service
We will setup JupyterHub to run as a system service using Systemd (which is responsible for managing all services and
servers that run on startup in Ubuntu). We will create a service file in a suitable location in the virtualenv folder
and then link it to the system services. First create the folder for the service file:
```sh
sudo mkdir -p /opt/jupyterhub/etc/systemd
```
Then create the following text file using your [favourite editor](https://micro-editor.github.io/) at
```sh
/opt/jupyterhub/etc/systemd/jupyterhub.service
```
Paste the following service unit definition into the file:
```
[Unit]
Description=JupyterHub
After=syslog.target network.target
[Service]
User=root
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/jupyterhub/bin"
ExecStart=/opt/jupyterhub/bin/jupyterhub -f /opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py
[Install]
WantedBy=multi-user.target
```
This sets up the environment to use the virtual environment we created, tells Systemd how to start jupyterhub using
the configuration file we created, specifies that jupyterhub will be started as the `root` user (needed so that it can
start jupyter on behalf of other logged in users), and specifies that jupyterhub should start on boot after the network
is enabled.
Finally, we need to make systemd aware of our service file. First we symlink our file into systemd's directory:
```sh
sudo ln -s /opt/jupyterhub/etc/systemd/jupyterhub.service /etc/systemd/system/jupyterhub.service
```
Then tell systemd to reload its configuration files
```sh
sudo systemctl daemon-reload
```
And finally enable the service
```sh
sudo systemctl enable jupyterhub.service
```
The service will start on reboot, but we can start it straight away using:
```sh
sudo systemctl start jupyterhub.service
```
...and check that it's running using:
```sh
sudo systemctl status jupyterhub.service
```
You should now be already be able to access jupyterhub using `<your servers ip>:8000` (assuming you haven't already set
up a firewall or something). However, when you log in the jupyter notebooks will be trying to use the Python virtualenv
that was created to install JupyterHub, this is not what we want. So on to part 2
## Part 2: Conda environments
### Install conda for the whole system
We will use `conda` to manage Python environments. We will install the officially maintained `conda` packages for Ubuntu,
this means they will get automatic updates with the rest of the system. Setup repo for the official Conda debian packages,
instructions are copied from [here](https://docs.conda.io/projects/conda/en/latest/user-guide/install/rpm-debian.html):
Install Anacononda public gpg key to trusted store
```sh
curl https://repo.anaconda.com/pkgs/misc/gpgkeys/anaconda.asc | gpg --dearmor > conda.gpg
sudo install -o root -g root -m 644 conda.gpg /etc/apt/trusted.gpg.d/
```
Add Debian repo
```sh
echo "deb [arch=amd64] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main" | sudo tee /etc/apt/sources.list.d/conda.list
```
Install conda
```sh
sudo apt update
sudo apt install conda
```
This will install conda into the folder `/opt/conda/`, with the conda command available at `/opt/conda/bin/conda`.
Finally, we can make conda more easily available to users by symlinking the conda shell setup script to the profile
'drop in' folder so that it gets run on login
```sh
sudo ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh
```
### Install a default conda environment for all users
First create a folder for conda envs (might exist already):
```sh
sudo mkdir /opt/conda/envs/
```
Then create a conda environment to your liking within that folder. Here we have called it 'python' because it will
be the obvious default - call it whatever you like. You can install whatever you like into this environment, but you MUST at least install `ipykernel`.
```sh
sudo /opt/conda/bin/conda create --prefix /opt/conda/envs/python python=3.7 ipykernel
```
Once your env is set up as desired, make it visible to Jupyter by installing the kernel spec. There are two options here:
1 ) Install into the JupyterHub virtualenv - this ensures it overrides the default python version. It will only be visible
to the JupyterHub installation we have just created. This is useful to avoid conda environments appearing where they are not expected.
```sh
sudo /opt/conda/envs/python/bin/python -m ipykernel install --prefix=/opt/jupyterhub/ --name 'python' --display-name "Python (default)"
```
2 ) Install it system-wide by putting it into `/usr/local`. It will be visible to any parallel install of JupyterHub or
JupyterLab, and will persist even if you later delete or modify the JupyterHub installation. This is useful if the kernels
might be used by other services, or if you want to modify the JupyterHub installation independently from the conda environments.
```sh
sudo /opt/conda/envs/python/bin/python -m ipykernel install --prefix /usr/local/ --name 'python' --display-name "Python (default)"
````
### Setting up users' own conda environments
There is relatively little for the administrator to do here, as users will have to set up their own environments using the shell.
On login they should run `conda init` or `/opt/conda/bin/conda`. The can then use conda to set up their environment,
although they must also install `ipykernel`. Once done, they can enable their kernel using:
```sh
/path/to/kernel/env/bin/python -m ipykernel install --name 'python-my-env' --display-name "Python My Env"
```
This will place the kernel spec into their home folder, where Jupyter will look for it on startup.
## Setting up a reverse proxy
The guide so far results in JupyterHub running on port 8000. It is not generally advisable to run open web services in
this way - instead, use a reverse proxy running on standard HTTP/HTTPS ports.
> **Important**: Be aware of the security implications especially if you are running a server that is accessible from the open internet
> i.e. not protected within an institutional intranet or private home/office network. You should set up a firewall and
> HTTPS encryption, which is outside of the scope of this guide. For HTTPS consider using [LetsEncrypt](https://letsencrypt.org/)
> or setting up a [self-signed certificate](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-ubuntu-18-04).
> Firewalls may be set up using `ufw` or `firewalld` and combined with `fail2ban`.
### Using Nginx
Nginx is a mature and established web server and reverse proxy and is easy to install using `sudo apt install nginx`.
Details on using Nginx as a reverse proxy can be found elsewhere. Here, we will only outline the additional steps needed
to setup JupyterHub with Nginx and host it at a given URL e.g. `<your-server-ip-or-url>/jupyter`.
This could be useful for example if you are running several services or web pages on the same server.
To achieve this needs a few tweaks to both the JupyterHub configuration and the Nginx config. First, edit the
configuration file `/opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py` and add the line:
```python
c.JupyterHub.bind_url = 'http://:8000/jupyter'
```
where `/jupyter` will be the relative URL of the JupyterHub.
Now Nginx must be configured with a to pass all traffic from `/jupyter` to the the local address `127.0.0.1:8000`.
Add the following snippet to your nginx configuration file (e.g. `/etc/nginx/sites-available/default`).
```
location /jupyter/ {
# NOTE important to also set base url of jupyterhub to /jupyter in its config
proxy_pass http://127.0.0.1:8000;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# websocket headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
```
Also add this snippet before the *server* block:
```
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
```
Nginx will not run if there are errors in the configuration, check your configuration using:
```sh
nginx -t
```
If there are no errors, you can restart the Nginx service for the new configuration to take effect.
```sh
sudo systemctl restart nginx.service
```
## Getting started using your new JupyterHub
Once you have setup JupyterHub and Nginx proxy as described, you can browse to your JupyterHub IP or URL
(e.g. if your server IP address is `123.456.789.1` and you decided to host JupyterHub at the `/jupyter` URL, browse
to `123.456.789.1/jupyter`). You will find a login page where you enter your Linux username and password. On login
you will be presented with the JupyterLab interface, with the file browser pane showing the contents of your users'
home directory on the server.

View File

@@ -1,9 +1,5 @@
Installation
============
These sections cover how to get up-and-running with JupyterHub. They cover
some basics of the tools needed to deploy JupyterHub as well as how to get it
running on your own infrastructure.
Installation Guide
==================
.. toctree::
:maxdepth: 3
@@ -11,4 +7,3 @@ running on your own infrastructure.
quickstart
quickstart-docker
installation-basics
installation-guide-hard

View File

@@ -1,52 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
mQINBFMx2LoBEAC9xU8JiKI1VlCJ4PT9zqhU5nChQZ06/bj1BBftiMJG07fdGVO0
ibOn4TrCoRYaeRlet0UpHzxT4zDa5h3/usJaJNTSRwtWePw2o7Lik8J+F3LionRf
8Jz81WpJ+81Klg4UWKErXjBHsu/50aoQm6ZNYG4S2nwOmMVEC4nc44IAA0bb+6kW
saFKKzEDsASGyuvyutdyUHiCfvvh5GOC2h9mXYvl4FaMW7K+d2UgCYERcXDNy7C1
Bw+uepQ9ELKdG4ZpvonO6BNr1BWLln3wk93AQfD5qhfsYRJIyj0hJlaRLtBU3i6c
xs+gQNF4mPmybpPSGuOyUr4FYC7NfoG7IUMLj+DYa6d8LcMJO+9px4IbdhQvzGtC
qz5av1TX7/+gnS4L8C9i1g8xgI+MtvogngPmPY4repOlK6y3l/WtxUPkGkyYkn3s
RzYyE/GJgTwuxFXzMQs91s+/iELFQq/QwmEJf+g/QYfSAuM+lVGajEDNBYVAQkxf
gau4s8Gm0GzTZmINilk+7TxpXtKbFc/Yr4A/fMIHmaQ7KmJB84zKwONsQdVv7Jjj
0dpwu8EIQdHxX3k7/Q+KKubEivgoSkVwuoQTG15X9xrOsDZNwfOVQh+JKazPvJtd
SNfep96r9t/8gnXv9JI95CGCQ8lNhXBUSBM3BDPTbudc4b6lFUyMXN0mKQARAQAB
tCxJUHl0aG9uIFNlY3VyaXR5IFRlYW0gPHNlY3VyaXR5QGlweXRob24ub3JnPokC
OAQTAQIAIgUCUzHYugIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQEwJc
LcmZYkjuXg//R/t6nMNQmf9W1h52IVfUbRAVmvZ5d063hQHKV2dssxtnA2dRm/x5
JZu8Wz7ZrEZpyqwRJO14sxN1/lC3v+zs9XzYXr2lBTZuKCPIBypYVGIynCuWJBQJ
rWnfG4+u1RHahnjqlTWTY1C/le6v7SjAvCb6GbdA6k4ZL2EJjQlRaHDmzw3rV/+l
LLx6/tYzIsotuflm/bFumyOMmpQQpJjnCkWIVjnRICZvuAn97jLgtTI0+0Rzf4Zb
k2BwmHwDRqWCTTcRI9QvTl8AzjW+dNImN22TpGOBPfYj8BCZ9twrpKUbf+jNqJ1K
THQzFtpdJ6SzqiFVm74xW4TKqCLkbCQ/HtVjTGMGGz/y7KTtaLpGutQ6XE8SSy6P
EffSb5u+kKlQOWaH7Mc3B0yAojz6T3j5RSI8ts6pFi6pZhDg9hBfPK2dT0v/7Mkv
E1Z7q2IdjZnhhtGWjDAMtDDn2NbY2wuGoa5jAWAR0WvIbEZ3kOxuLE5/ZOG1FyYm
noJRliBz7038nT92EoD5g1pdzuxgXtGCpYyyjRZwaLmmi4CvA+oThKmnqWNY5lyY
ricdNHDiyEXK0YafJL1oZgM86MSb0jKJMp5U11nUkUGzkroFfpGDmzBwAzEPgeiF
40+qgsKB9lqwb3G7PxvfSi3XwxfXgpm1cTyEaPSzsVzve3d1xeqb7Yq5Ag0EUzHY
ugEQALQ5FtLdNoxTxMsgvrRr1ejLiUeRNUfXtN1TYttOfvAhfBVnszjtkpIW8DCB
JF/bA7ETiH8OYYn/Fm6MPI5H64IHEncpzxjf57jgpXd9CA9U2OMk/P1nve5zYchP
QmP2fJxeAWr0aRH0Mse5JS5nCkh8Xv4nAjsBYeLTJEVOb1gPQFXOiFcVp3gaKAzX
GWOZ/mtG/uaNsabH/3TkcQQEgJefd11DWgMB7575GU+eME7c6hn3FPITA5TC5HUX
azvjv/PsWGTTVAJluJ3fUDvhpbGwYOh1uV0rB68lPpqVIro18IIJhNDnccM/xqko
4fpJdokdg4L1wih+B04OEXnwgjWG8OIphR/oL/+M37VV2U7Om/GE6LGefaYccC9c
tIaacRQJmZpG/8RsimFIY2wJ07z8xYBITmhMmOt0bLBv0mU0ym5KH9Dnru1m9QDO
AHwcKrDgL85f9MCn+YYw0d1lYxjOXjf+moaeW3izXCJ5brM+MqVtixY6aos3YO29
J7SzQ4aEDv3h/oKdDfZny21jcVPQxGDui8sqaZCi8usCcyqWsKvFHcr6vkwaufcm
3Knr2HKVotOUF5CDZybopIz1sJvY/5Dx9yfRmtivJtglrxoDKsLi1rQTlEQcFhCS
ACjf7txLtv03vWHxmp4YKQFkkOlbyhIcvfPVLTvqGerdT2FHABEBAAGJAh8EGAEC
AAkFAlMx2LoCGwwACgkQEwJcLcmZYkgK0BAAny0YUugpZldiHzYNf8I6p2OpiDWv
ZHaguTTPg2LJSKaTd+5UHZwRFIWjcSiFu+qTGLNtZAdcr0D5f991CPvyDSLYgOwb
Jm2p3GM2KxfECWzFbB/n/PjbZ5iky3+5sPlOdBR4TkfG4fcu5GwUgCkVe5u3USAk
C6W5lpeaspDz39HAPRSIOFEX70+xV+6FZ17B7nixFGN+giTpGYOEdGFxtUNmHmf+
waJoPECyImDwJvmlMTeP9jfahlB6Pzaxt6TBZYHetI/JR9FU69EmA+XfCSGt5S+0
Eoc330gpsSzo2VlxwRCVNrcuKmG7PsFFANok05ssFq1/Djv5rJ++3lYb88b8HSP2
3pQJPrM7cQNU8iPku9yLXkY5qsoZOH+3yAia554Dgc8WBhp6fWh58R0dIONQxbbo
apNdwvlI8hKFB7TiUL6PNShE1yL+XD201iNkGAJXbLMIC1ImGLirUfU267A3Cop5
hoGs179HGBcyj/sKA3uUIFdNtP+NndaP3v4iYhCitdVCvBJMm6K3tW88qkyRGzOk
4PW422oyWKwbAPeMk5PubvEFuFAIoBAFn1zecrcOg85RzRnEeXaiemmmH8GOe1Xu
Kh+7h8XXyG6RPFy8tCcLOTk+miTqX+4VWy+kVqoS2cQ5IV8WsJ3S7aeIy0H89Z8n
5vmLc+Ibz+eT+rM=
=XVDe
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -25,7 +25,7 @@ Starting JupyterHub with docker
The JupyterHub docker image can be started with the following command::
docker run -d -p 8000:8000 --name jupyterhub jupyterhub/jupyterhub jupyterhub
docker run -d --name jupyterhub jupyterhub/jupyterhub jupyterhub
This command will create a container named ``jupyterhub`` that you can
**stop and resume** with ``docker stop/start``.

View File

@@ -26,10 +26,6 @@ Before installing JupyterHub, you will need:
The `nodejs-legacy` package installs the `node` executable and is currently
required for npm to work on Debian/Ubuntu.
- A [pluggable authentication module (PAM)](https://en.wikipedia.org/wiki/Pluggable_authentication_module)
to use the [default Authenticator](./getting-started/authenticators-users-basics.md).
PAM is often available by default on most distributions, if this is not the case it can be installed by
using the operating system's package manager.
- TLS certificate and key for HTTPS communication
- Domain name

View File

@@ -5,8 +5,8 @@ Hub and single user notebook servers.
## The default PAM Authenticator
JupyterHub ships with the default [PAM][]-based Authenticator, for
logging in with local user accounts via a username and password.
JupyterHub ships only with the default [PAM][]-based Authenticator,
for logging in with local user accounts via a username and password.
## The OAuthenticator
@@ -34,17 +34,12 @@ popular services:
A generic implementation, which you can use for OAuth authentication
with any provider, is also available.
## The Dummy Authenticator
When testing, it may be helpful to use the
:class:`~jupyterhub.auth.DummyAuthenticator`. This allows for any username and
password unless if a global password has been set. Once set, any username will
still be accepted but the correct password will need to be provided.
## Additional Authenticators
A partial list of other authenticators is available on the
[JupyterHub wiki](https://github.com/jupyterhub/jupyterhub/wiki/Authenticators).
- ldapauthenticator for LDAP
- tmpauthenticator for temporary accounts
- For Shibboleth, [jhub_shibboleth_auth](https://github.com/gesiscss/jhub_shibboleth_auth)
and [jhub_remote_user_authenticator](https://github.com/cwaldbieser/jhub_remote_user_authenticator)
## Technical Overview of Authentication
@@ -75,6 +70,7 @@ Writing an Authenticator that looks up passwords in a dictionary
requires only overriding this one method:
```python
from tornado import gen
from IPython.utils.traitlets import Dict
from jupyterhub.auth import Authenticator
@@ -84,7 +80,8 @@ class DictionaryAuthenticator(Authenticator):
help="""dict of username:password for authentication"""
)
async def authenticate(self, handler, data):
@gen.coroutine
def authenticate(self, handler, data):
if self.passwords.get(data['username']) == data['password']:
return data['username']
```
@@ -106,16 +103,6 @@ c.Authenticator.username_map = {
}
```
When using `PAMAuthenticator`, you can set
`c.PAMAuthenticator.pam_normalize_username = True`, which will
normalize usernames using PAM (basically round-tripping them: username
to uid to username), which is useful in case you use some external
service that allows multiple usernames mapping to the same user (such
as ActiveDirectory, yes, this really happens). When
`pam_normalize_username` is on, usernames are *not* normalized to
lowercase.
#### Validate usernames
In most cases, there is a very limited set of acceptable usernames.
@@ -151,41 +138,6 @@ See a list of custom Authenticators [on the wiki](https://github.com/jupyterhub/
If you are interested in writing a custom authenticator, you can read
[this tutorial](http://jupyterhub-tutorial.readthedocs.io/en/latest/authenticators.html).
### Registering custom Authenticators via entry points
As of JupyterHub 1.0, custom authenticators can register themselves via
the `jupyterhub.authenticators` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.authenticators': [
'myservice = mypackage:MyAuthenticator',
],
},
)
```
If you have added this metadata to your package,
users can select your authenticator with the configuration:
```python
c.JupyterHub.authenticator_class = 'myservice'
```
instead of the full
```python
c.JupyterHub.authenticator_class = 'mypackage:MyAuthenticator'
```
previously required.
Additionally, configurable attributes for your authenticator will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.
### Authentication state

View File

@@ -52,7 +52,7 @@ c.GitHubOAuthenticator.oauth_callback_url = os.environ['OAUTH_CALLBACK_URL']
c.LocalAuthenticator.create_system_users = True
# specify users and admin
c.Authenticator.allowed_users = {'rgbkrk', 'minrk', 'jhamrick'}
c.Authenticator.whitelist = {'rgbkrk', 'minrk', 'jhamrick'}
c.Authenticator.admin_users = {'jhamrick', 'rgbkrk'}
# uses the default spawner

View File

@@ -17,12 +17,10 @@ satisfy the following:
Let's start out with needed JupyterHub configuration in `jupyterhub_config.py`:
```python
# Force the proxy to only listen to connections to 127.0.0.1 (on port 8000)
c.JupyterHub.bind_url = 'http://127.0.0.1:8000'
# Force the proxy to only listen to connections to 127.0.0.1
c.JupyterHub.ip = '127.0.0.1'
```
(For Jupyterhub < 0.9 use `c.JupyterHub.ip = '127.0.0.1'`.)
For high-quality SSL configuration, we also generate Diffie-Helman parameters.
This can take a few minutes:
@@ -83,11 +81,8 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# websocket headers
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
}
# Managing requests to verify letsencrypt host
@@ -142,20 +137,6 @@ Now restart `nginx`, restart the JupyterHub, and enjoy accessing
`https://HUB.DOMAIN.TLD` while serving other content securely on
`https://NO_HUB.DOMAIN.TLD`.
### SELinux permissions for nginx
On distributions with SELinux enabled (e.g. Fedora), one may encounter permission errors
when the nginx service is started.
We need to allow nginx to perform network relay and connect to the jupyterhub port. The
following commands do that:
```bash
semanage port -a -t http_port_t -p tcp 8000
setsebool -P httpd_can_network_relay 1
setsebool -P httpd_can_network_connect 1
```
Replace 8000 with the port the jupyterhub server is running from.
## Apache
@@ -209,23 +190,3 @@ Listen 443
</Location>
</VirtualHost>
```
In case of the need to run the jupyterhub under /jhub/ or other location please use the below configurations:
- JupyterHub running locally at http://127.0.0.1:8000/jhub/ or other location
httpd.conf amendments:
```bash
RewriteRule /jhub/(.*) ws://127.0.0.1:8000/jhub/$1 [NE.P,L]
RewriteRule /jhub/(.*) http://127.0.0.1:8000/jhub/$1 [NE,P,L]
ProxyPass /jhub/ http://127.0.0.1:8000/jhub/
ProxyPassReverse /jhub/ http://127.0.0.1:8000/jhub/
```
jupyterhub_config.py amendments:
```bash
--The public facing URL of the whole JupyterHub application.
--This is the address on which the proxy will bind. Sets protocol, ip, base_url
c.JupyterHub.bind_url = 'http://127.0.0.1:8000/jhub/'
```

View File

@@ -1,30 +0,0 @@
==============================
Configuration Reference
==============================
.. important::
Make sure the version of JupyterHub for this documentation matches your
installation version, as the output of this command may change between versions.
JupyterHub configuration
------------------------
As explained in the `Configuration Basics <../getting-started/config-basics.html#generate-a-default-config-file>`_
section, the ``jupyterhub_config.py`` can be automatically generated via
.. code-block:: bash
jupyterhub --generate-config
The following contains the output of that command for reference.
.. jupyterhub-generate-config::
JupyterHub help command output
------------------------------
This section contains the output of the command ``jupyterhub --help-all``.
.. jupyterhub-help-all::

View File

@@ -37,7 +37,7 @@ Next, you will need [sudospawner](https://github.com/jupyter/sudospawner)
to enable monitoring the single-user servers with sudo:
```bash
sudo python3 -m pip install sudospawner
sudo pip install sudospawner
```
Now we have to configure sudo to allow the Hub user (`rhea`) to launch
@@ -57,7 +57,7 @@ To do this we add to `/etc/sudoers` (use `visudo` for safe editing of sudoers):
For example:
```bash
# comma-separated list of users that can spawn single-user servers
# comma-separated whitelist of users that can spawn single-user servers
# this should include all of your Hub users
Runas_Alias JUPYTER_USERS = rhea, zoe, wash
@@ -120,11 +120,6 @@ the shadow password database.
### Shadow group (Linux)
**Note:** On Fedora based distributions there is no clear way to configure
the PAM database to allow sufficient access for authenticating with the target user's password
from JupyterHub. As a workaround we recommend use an
[alternative authentication method](https://github.com/jupyterhub/jupyterhub/wiki/Authenticators).
```bash
$ ls -l /etc/shadow
-rw-r----- 1 root shadow 2197 Jul 21 13:41 shadow
@@ -209,8 +204,8 @@ The simplest way to deal with this is to make a directory owned by your Hub user
and use that as the CWD when launching the server.
```bash
$ sudo mkdir /etc/jupyterhub
$ sudo chown rhea /etc/jupyterhub
$ sudo mkdir /etc/jupyterhub
$ sudo chown rhea /etc/jupyterhub
```
## Start jupyterhub
@@ -218,20 +213,20 @@ $ sudo chown rhea /etc/jupyterhub
Finally, start the server as our newly configured user, `rhea`:
```bash
$ cd /etc/jupyterhub
$ sudo -u rhea jupyterhub --JupyterHub.spawner_class=sudospawner.SudoSpawner
$ cd /etc/jupyterhub
$ sudo -u rhea jupyterhub --JupyterHub.spawner_class=sudospawner.SudoSpawner
```
And try logging in.
## Troubleshooting: SELinux
### Troubleshooting: SELinux
If you still get a generic `Permission denied` `PermissionError`, it's possible SELinux is blocking you.
Here's how you can make a module to allow this.
First, put this in a file named `sudo_exec_selinux.te`:
First, put this in a file sudo_exec_selinux.te:
```bash
module sudo_exec_selinux 1.1;
module sudo_exec 1.1;
require {
type unconfined_t;
@@ -251,9 +246,9 @@ $ semodule_package -o sudo_exec_selinux.pp -m sudo_exec_selinux.mod
$ semodule -i sudo_exec_selinux.pp
```
## Troubleshooting: PAM session errors
### Troubleshooting: PAM session errors
If the PAM authentication doesn't work and you see errors for
`login:session-auth`, or similar, considering updating to a more recent version
of jupyterhub and disabling the opening of PAM sessions with
`c.PAMAuthenticator.open_sessions=False`.
`login:session-auth`, or similar, considering updating to `master`
and/or incorporating this commit https://github.com/jupyter/jupyterhub/commit/40368b8f555f04ffdd662ffe99d32392a088b1d2
and configuration option, `c.PAMAuthenticator.open_sessions = False`.

View File

@@ -145,37 +145,3 @@ In both cases, you want to *avoid putting configuration in user home
directories* because users can change those configuration settings. Also,
home directories typically persist once they are created, so they are
difficult for admins to update later.
## Named servers
By default, in a JupyterHub deployment each user has exactly one server.
JupyterHub can, however, have multiple servers per user.
This is most useful in deployments where users can configure the environment
in which their server will start (e.g. resource requests on an HPC cluster),
so that a given user can have multiple configurations running at the same time,
without having to stop and restart their one server.
To allow named servers:
```python
c.JupyterHub.allow_named_servers = True
```
Named servers were implemented in the REST API in JupyterHub 0.8,
and JupyterHub 1.0 introduces UI for managing named servers via the user home page:
![named servers on the home page](../images/named-servers-home.png)
as well as the admin page:
![named servers on the admin page](../images/named-servers-admin.png)
Named servers can be accessed, created, started, stopped, and deleted
from these pages. Activity tracking is now per-server as well.
The number of named servers per user can be limited by setting
```python
c.JupyterHub.named_server_limit_per_user = 5
```

View File

@@ -1,28 +1,21 @@
Technical Reference
===================
This section covers more of the details of the JupyterHub architecture, as well as
what happens under-the-hood when you deploy and configure your JupyterHub.
.. toctree::
:maxdepth: 2
technical-overview
urls
websecurity
authenticators
spawners
services
proxy
separate-proxy
rest
monitoring
database
upgrading
templates
../events/index
config-user-env
config-examples
config-ghoauth
config-proxy
config-sudo
config-reference

View File

@@ -1,20 +0,0 @@
Monitoring
==========
This section covers details on monitoring the state of your JupyterHub installation.
JupyterHub expose the ``/metrics`` endpoint that returns text describing its current
operational state formatted in a way `Prometheus <https://prometheus.io/docs/introduction/overview/>`_ understands.
Prometheus is a separate open source tool that can be configured to repeatedly poll
JupyterHub's ``/metrics`` endpoint to parse and save its current state.
By doing so, Prometheus can describe JupyterHub's evolving state over time.
This evolving state can then be accessed through Prometheus that expose its underlying
storage to those allowed to access it, and be presented with dashboards by a
tool like `Grafana <https://grafana.com/docs/grafana/latest/getting-started/what-is-grafana/>`_.
.. toctree::
:maxdepth: 2
metrics

View File

@@ -45,12 +45,15 @@ If your proxy should be launched when the Hub starts, you must define how
to start and stop your proxy:
```python
from tornado import gen
class MyProxy(Proxy):
...
async def start(self):
@gen.coroutine
def start(self):
"""Start the proxy"""
async def stop(self):
@gen.coroutine
def stop(self):
"""Stop the proxy"""
```
@@ -59,18 +62,6 @@ These methods **may** be coroutines.
`c.Proxy.should_start` is a configurable flag that determines whether the
Hub should call these methods when the Hub itself starts and stops.
## Encryption
When using `internal_ssl` to encrypt traffic behind the proxy, at minimum,
your `Proxy` will need client ssl certificates which the `Hub` must be made
aware of. These can be generated with the command `jupyterhub --generate-certs`
which will write them to the `internal_certs_location` in folders named
`proxy_api` and `proxy_client`. Alternatively, these can be provided to the
hub via the `jupyterhub_config.py` file by providing a `dict` of named paths
to the `external_authorities` option. The hub will include all certificates
provided in that `dict` in the trust bundle utilized by all internal
components.
### Purely external proxies
Probably most custom proxies will be externally managed,
@@ -102,14 +93,15 @@ route to be proxied, such as `/user/name/`. A routespec will:
### Adding a route
When adding a route, JupyterHub may pass a JSON-serializable dict as a `data`
argument that should be attached to the proxy route. When that route is
argument that should be attacked to the proxy route. When that route is
retrieved, the `data` argument should be returned as well. If your proxy
implementation doesn't support storing data attached to routes, then your
Python wrapper may have to handle storing the `data` piece itself, e.g in a
simple file or database.
```python
async def add_route(self, routespec, target, data):
@gen.coroutine
def add_route(self, routespec, target, data):
"""Proxy `routespec` to `target`.
Store `data` associated with the routespec
@@ -120,7 +112,7 @@ async def add_route(self, routespec, target, data):
Adding a route for a user looks like this:
```python
await proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
{'user': 'pgeorgiou'})
```
@@ -130,7 +122,8 @@ await proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
`delete_route` should still succeed, but a warning may be issued.
```python
async def delete_route(self, routespec):
@gen.coroutine
def delete_route(self, routespec):
"""Delete the route"""
```
@@ -142,7 +135,8 @@ routes. The return value for this function should be a dictionary, keyed by
`add_route` (`routespec`, `target`, `data`)
```python
async def get_all_routes(self):
@gen.coroutine
def get_all_routes(self):
"""Return all routes, keyed by routespec"""
```
@@ -185,38 +179,3 @@ tracked, and services such as cull-idle will not work.
Now that `notebook-5.0` tracks activity internally, we can retrieve activity
information from the single-user servers instead, removing the need to track
activity in the proxy. But this is not yet implemented in JupyterHub 0.8.0.
### Registering custom Proxies via entry points
As of JupyterHub 1.0, custom proxy implementations can register themselves via
the `jupyterhub.proxies` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.proxies': [
'mything = mypackage:MyProxy',
],
},
)
```
If you have added this metadata to your package,
users can select your proxy with the configuration:
```python
c.JupyterHub.proxy_class = 'mything'
```
instead of the full
```python
c.JupyterHub.proxy_class = 'mypackage:MyProxy'
```
previously required.
Additionally, configurable attributes for your proxy will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.

View File

@@ -1,14 +0,0 @@
:orphan:
===================
JupyterHub REST API
===================
.. this doc exists as a resolvable link target
.. which _static files are not
.. meta::
:http-equiv=refresh: 0;url=../_static/rest-api/index.html
The rest API docs are `here <../_static/rest-api/index.html>`_
if you are not redirected automatically.

View File

@@ -27,7 +27,7 @@ Hub.
To send requests using JupyterHub API, you must pass an API token with
the request.
As of [version 0.6.0](../changelog.md), the preferred way of
As of [version 0.6.0](../changelog.html), the preferred way of
generating an API token is:
```bash
@@ -48,7 +48,7 @@ jupyterhub token <username>
This command generates a random string to use as a token and registers
it for the given user with the Hub's database.
In [version 0.8.0](../changelog.md), a TOKEN request page for
In [version 0.8.0](../changelog.html), a TOKEN request page for
generating an API token is available from the JupyterHub user interface:
![Request API TOKEN page](../images/token-request.png)
@@ -57,9 +57,6 @@ generating an API token is available from the JupyterHub user interface:
## Add API tokens to the config file
**This is deprecated. We are in no rush to remove this feature,
but please consider if service tokens are right for you.**
You may also add a dictionary of API tokens and usernames to the hub's
configuration file, `jupyterhub_config.py` (note that
the **key** is the 'secret-token' while the **value** is the 'username'):
@@ -70,41 +67,6 @@ c.JupyterHub.api_tokens = {
}
```
### Updating to admin services
The `api_tokens` configuration has been softly deprecated since the introduction of services.
We have no plans to remove it,
but users are encouraged to use service configuration instead.
If you have been using `api_tokens` to create an admin user
and a token for that user to perform some automations,
the services mechanism may be a better fit.
If you have the following configuration:
```python
c.JupyterHub.admin_users = {"service-admin",}
c.JupyterHub.api_tokens = {
"secret-token": "service-admin",
}
```
This can be updated to create an admin service, with the following configuration:
```python
c.JupyterHub.services = [
{
"name": "service-token",
"admin": True,
"api_token": "secret-token",
},
]
```
The token will have the same admin permissions,
but there will no longer be a user account created to house it.
The main noticeable difference is that there will be no notebook server associated with the account
and the service will not show up in the various user list pages and APIs.
## Make an API request
To authenticate your requests, pass the API token in the request's
@@ -196,6 +158,11 @@ The same servers can be stopped by substituting `DELETE` for `POST` above.
### Some caveats for using named-servers
The named-server capabilities are not fully implemented for JupyterHub as yet.
While it's possible to start/stop a server via the API, the UI on the
JupyterHub control-panel has not been implemented, and so it may not be obvious
to those viewing the panel that a named-server may be running for a given user.
For named-servers via the API to work, the spawner used to spawn these servers
will need to be able to handle the case of multiple servers per user and ensure
uniqueness of names, particularly if servers are spawned via docker containers
@@ -211,5 +178,5 @@ Note: The Swagger specification is being renamed the [OpenAPI Initiative][].
[interactive style on swagger's petstore]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default
[OpenAPI Initiative]: https://www.openapis.org/
[JupyterHub REST API]: ./rest-api
[JupyterHub REST API]: ../_static/rest-api/index.html
[Jupyter Notebook REST API]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml

View File

@@ -1,80 +0,0 @@
# Running proxy separately from the hub
## Background
The thing which users directly connect to is the proxy, by default
`configurable-http-proxy`. The proxy either redirects users to the
hub (for login and managing servers), or to their own single-user
servers. Thus, as long as the proxy stays running, access to existing
servers continues, even if the hub itself restarts or goes down.
When you first configure the hub, you may not even realize this
because the proxy is automatically managed by the hub. This is great
for getting started and even most use, but everytime you restart the
hub, all user connections also get restarted. But it's also simple to
run the proxy as a service separate from the hub, so that you are free
to reconfigure the hub while only interrupting users who are currently
actively starting the hub.
The default JupyterHub proxy is
[configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy),
and that page has some docs. If you are using a different proxy, such
as Traefik, these instructions are probably not relevant to you.
## Configuration options
`c.JupyterHub.cleanup_servers = False` should be set, which tells the
hub to not stop servers when the hub restarts (this is useful even if
you don't run the proxy separately).
`c.ConfigurableHTTPProxy.should_start = False` should be set, which
tells the hub that the proxy should not be started (because you start
it yourself).
`c.ConfigurableHTTPProxy.auth_token = "CONFIGPROXY_AUTH_TOKEN"` should be set to a
token for authenticating communication with the proxy.
`c.ConfigurableHTTPProxy.api_url = 'http://localhost:8001'` should be
set to the URL which the hub uses to connect *to the proxy's API*.
## Proxy configuration
You need to configure a service to start the proxy. An example
command line for this is `configurable-http-proxy --ip=127.0.0.1
--port=8000 --api-ip=127.0.0.1 --api-port=8001
--default-target=http://localhost:8081
--error-target=http://localhost:8081/hub/error`. (Details for how to
do this is out of scope for this tutorial - for example it might be a
systemd service on within another docker cotainer). The proxy has no
configuration files, all configuration is via the command line and
environment variables.
`--api-ip` and `--api-port` (which tells the proxy where to listen) should match the hub's `ConfigurableHTTPProxy.api_url`.
`--ip`, `-port`, and other options configure the *user* connections to the proxy.
`--default-target` and `--error-target` should point to the hub, and used when users navigate to the proxy originally.
You must define the environment variable `CONFIGPROXY_AUTH_TOKEN` to
match the token given to `c.ConfigurableHTTPProxy.auth_token`.
You should check the [configurable-http-proxy
options](https://github.com/jupyterhub/configurable-http-proxy) to see
what other options are needed, for example SSL options. Note that
these are configured in the hub if the hub is starting the proxy - you
need to move the options to here.
## Docker image
You can use [jupyterhub configurable-http-proxy docker
image](https://hub.docker.com/r/jupyterhub/configurable-http-proxy/)
to run the proxy.
## See also
* [jupyterhub configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy)

View File

@@ -93,7 +93,7 @@ c.JupyterHub.services = [
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, '/path/to/cull-idle.py', '--timeout']
'command': ['python', '/path/to/cull-idle.py', '--timeout']
}
]
```
@@ -151,8 +151,6 @@ c.JupyterHub.services = [
{
'name': 'my-web-service',
'url': 'https://10.0.1.1:1984',
# any secret >8 characters, you'll use api_token to
# authenticate api requests to the hub from your service
'api_token': 'super-secret',
}
]
@@ -251,7 +249,7 @@ prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/')
auth = HubAuth(
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
cache_max_age=60,
cookie_cache_max_age=60,
)
app = Flask(__name__)
@@ -315,7 +313,7 @@ class MyHandler(HubAuthenticated, web.RequestHandler):
The HubAuth will automatically load the desired configuration from the Service
environment variables.
If you want to limit user access, you can specify allowed users through either the
If you want to limit user access, you can whitelist users through either the
`.hub_users` attribute or `.hub_groups`. These are sets that check against the
username and user group list, respectively. If a user matches neither the user
list nor the group list, they will not be allowed access. If both are left
@@ -333,9 +331,7 @@ and taking note of the following process:
1. retrieve the cookie `jupyterhub-services` from the request.
2. Make an API request `GET /hub/api/authorizations/cookie/jupyterhub-services/cookie-value`,
where cookie-value is the url-encoded value of the `jupyterhub-services` cookie.
This request must be authenticated with a Hub API token in the `Authorization` header,
for example using the `api_token` from your [external service's configuration](#externally-managed-services).
This request must be authenticated with a Hub API token in the `Authorization` header.
For example, with [requests][]:
```python
@@ -364,7 +360,7 @@ and taking note of the following process:
An example of using an Externally-Managed Service and authentication is
in [nbviewer README][nbviewer example] section on securing the notebook viewer,
and an example of its configuration is found [here](https://github.com/jupyter/nbviewer/blob/ed942b10a52b6259099e2dd687930871dc8aac22/nbviewer/providers/base.py#L95).
and an example of its configuration is found [here](https://github.com/jupyter/nbviewer/blob/master/nbviewer/providers/base.py#L94).
nbviewer can also be run as a Hub-Managed Service as described [nbviewer README][nbviewer example]
section on securing the notebook viewer.

View File

@@ -10,7 +10,6 @@ and a custom Spawner needs to be able to take three actions:
## Examples
Custom Spawners for JupyterHub can be found on the [JupyterHub wiki](https://github.com/jupyterhub/jupyterhub/wiki/Spawners).
Some examples include:
@@ -25,10 +24,8 @@ Some examples include:
run without being root, by spawning an intermediate process via `sudo`
- [BatchSpawner](https://github.com/jupyterhub/batchspawner) for spawning remote
servers using batch systems
- [YarnSpawner](https://github.com/jupyterhub/yarnspawner) for spawning notebook
servers in YARN containers on a Hadoop cluster
- [SSHSpawner](https://github.com/NERSC/sshspawner) to spawn notebooks
on a remote server using SSH
- [RemoteSpawner](https://github.com/zonca/remotespawner) to spawn notebooks
and a remote server and tunnel the port via SSH
## Spawner control methods
@@ -74,7 +71,7 @@ It should return `None` if it is still running,
and an integer exit status, otherwise.
For the local process case, `Spawner.poll` uses `os.kill(PID, 0)`
to check if the local process is still running. On Windows, it uses `psutil.pid_exists`.
to check if the local process is still running.
### Spawner.stop
@@ -177,42 +174,6 @@ When `Spawner.start` is called, this dictionary is accessible as `self.user_opti
If you are interested in building a custom spawner, you can read [this tutorial](http://jupyterhub-tutorial.readthedocs.io/en/latest/spawners.html).
### Registering custom Spawners via entry points
As of JupyterHub 1.0, custom Spawners can register themselves via
the `jupyterhub.spawners` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.spawners': [
'myservice = mypackage:MySpawner',
],
},
)
```
If you have added this metadata to your package,
users can select your spawner with the configuration:
```python
c.JupyterHub.spawner_class = 'myservice'
```
instead of the full
```python
c.JupyterHub.spawner_class = 'mypackage:MySpawner'
```
previously required.
Additionally, configurable attributes for your spawner will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.
## Spawners, resource limits, and guarantees (Optional)
Some spawners of the single-user notebook servers allow setting limits or
@@ -262,30 +223,3 @@ in the single-user notebook server when a guarantee is being provided.
**The spawner's underlying system or cluster is responsible for enforcing these
limits and providing these guarantees.** If these values are set to `None`, no
limits or guarantees are provided, and no environment values are set.
### Encryption
Communication between the `Proxy`, `Hub`, and `Notebook` can be secured by
turning on `internal_ssl` in `jupyterhub_config.py`. For a custom spawner to
utilize these certs, there are two methods of interest on the base `Spawner`
class: `.create_certs` and `.move_certs`.
The first method, `.create_certs` will sign a key-cert pair using an internally
trusted authority for notebooks. During this process, `.create_certs` can
apply `ip` and `dns` name information to the cert via an `alt_names` `kwarg`.
This is used for certificate authentication (verification). Without proper
verification, the `Notebook` will be unable to communicate with the `Hub` and
vice versa when `internal_ssl` is enabled. For example, given a deployment
using the `DockerSpawner` which will start containers with `ips` from the
`docker` subnet pool, the `DockerSpawner` would need to instead choose a
container `ip` prior to starting and pass that to `.create_certs` (TODO: edit).
In general though, this method will not need to be changed and the default
`ip`/`dns` (localhost) info will suffice.
When `.create_certs` is run, it will `.create_certs` in a default, central
location specified by `c.JupyterHub.internal_certs_location`. For `Spawners`
that need access to these certs elsewhere (i.e. on another host altogether),
the `.move_certs` method can be overridden to move the certs appropriately.
Again, using `DockerSpawner` as an example, this would entail moving certs
to a directory that will get mounted into the container this spawner starts.

View File

@@ -49,14 +49,14 @@ The proxy is the only process that listens on a public interface. The Hub sits
behind the proxy at `/hub`. Single-user servers sit behind the proxy at
`/user/[username]`.
Different **[authenticators](./authenticators.md)** control access
Different **[authenticators](./authenticators.html)** control access
to JupyterHub. The default one (PAM) uses the user accounts on the server where
JupyterHub is running. If you use this, you will need to create a user account
on the system for each user on your team. Using other authenticators, you can
allow users to sign in with e.g. a GitHub account, or with any single-sign-on
system your organization has.
Next, **[spawners](./spawners.md)** control how JupyterHub starts
Next, **[spawners](./spawners.html)** control how JupyterHub starts
the individual notebook server for each user. The default spawner will
start a notebook server on the same machine running under their system username.
The other main option is to start each server in a separate container, often
@@ -66,10 +66,10 @@ using Docker.
When a user accesses JupyterHub, the following events take place:
- Login data is handed to the [Authenticator](./authenticators.md) instance for
- Login data is handed to the [Authenticator](./authenticators.html) instance for
validation
- The Authenticator returns the username if the login information is valid
- A single-user notebook server instance is [spawned](./spawners.md) for the
- A single-user notebook server instance is [spawned](./spawners.html) for the
logged-in user
- When the single-user notebook server starts, the proxy is notified to forward
requests to `/user/[username]/*` to the single-user notebook server.
@@ -111,7 +111,7 @@ working directory:
This file needs to persist so that a **Hub** server restart will avoid
invalidating cookies. Conversely, deleting this file and restarting the server
effectively invalidates all login cookies. The cookie secret file is discussed
in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.md).
in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.html).
The location of these files can be specified via configuration settings. It is
recommended that these files be stored in standard UNIX filesystem locations,
@@ -122,9 +122,9 @@ all security and runtime files.
There are two basic extension points for JupyterHub:
- How users are authenticated by [Authenticators](./authenticators.md)
- How users are authenticated by [Authenticators](./authenticators.html)
- How user's single-user notebook server processes are started by
[Spawners](./spawners.md)
[Spawners](./spawners.html)
Each is governed by a customizable class, and JupyterHub ships with basic
defaults for each.

View File

@@ -25,19 +25,19 @@ supplement the material in the block. The
make extensive use of blocks, which allows you to customize parts of the
interface easily.
In general, a child template can extend a base template, `page.html`, by beginning with:
In general, a child template can extend a base template, `base.html`, by beginning with:
```html
{% extends "page.html" %}
{% extends "base.html" %}
```
This works, unless you are trying to extend the default template for the same
file name. Starting in version 0.9, you may refer to the base file with a
`templates/` prefix. Thus, if you are writing a custom `page.html`, start the
`templates/` prefix. Thus, if you are writing a custom `base.html`, start the
file with this block:
```html
{% extends "templates/page.html" %}
{% extends "templates/base.html" %}
```
By defining `block`s with same name as in the base template, child templates
@@ -70,7 +70,7 @@ To add announcements to be displayed on a page, you have two options:
### Announcement Configuration Variables
If you set the configuration variable `JupyterHub.template_vars =
{'announcement': 'some_text'}`, the given `some_text` will be placed on
{'announcement': 'some_text}`, the given `some_text` will be placed on
the top of all pages. The more specific variables
`announcement_login`, `announcement_spawn`, `announcement_home`, and
`announcement_logout` are more specific and only show on their

View File

@@ -0,0 +1,98 @@
# Upgrading JupyterHub and its database
From time to time, you may wish to upgrade JupyterHub to take advantage
of new releases. Much of this process is automated using scripts,
such as those generated by alembic for database upgrades. Whether you
are using the default SQLite database or an RDBMS, such as PostgreSQL or
MySQL, the process follows similar steps.
**Before upgrading a JupyterHub deployment**, it's critical to backup your data
and configurations before shutting down the JupyterHub process and server.
## Note about upgrading the SQLite database
When used in production systems, SQLite has some disadvantages when it
comes to upgrading JupyterHub. These are:
- `upgrade-db` may not work, and you may need to start with a fresh database
- `downgrade-db` **will not** work if you want to rollback to an earlier
version, so backup the `jupyterhub.sqlite` file before upgrading
## The upgrade process
Five fundamental process steps are needed when upgrading JupyterHub and its
database:
1. Backup JupyterHub database
2. Backup JupyterHub configuration file
3. Shutdown the Hub
4. Upgrade JupyterHub
5. Upgrade the database using run `jupyterhub upgrade-db`
Let's take a closer look at each step in the upgrade process as well as some
additional information about JupyterHub databases.
### Backup JupyterHub database
To prevent unintended loss of data or configuration information, you should
back up the JupyterHub database (the default SQLite database or a RDBMS
database using PostgreSQL, MySQL, or others supported by SQLAlchemy):
- If using the default SQLite database, back up the `jupyterhub.sqlite`
database.
- If using an RDBMS database such as PostgreSQL, MySQL, or other supported by
SQLAlchemy, back up the JupyterHub database.
Losing the Hub database is often not a big deal. Information that resides only
in the Hub database includes:
- active login tokens (user cookies, service tokens)
- users added via GitHub UI, instead of config files
- info about running servers
If the following conditions are true, you should be fine clearing the Hub
database and starting over:
- users specified in config file
- user servers are stopped during upgrade
- don't mind causing users to login again after upgrade
### Backup JupyterHub configuration file
Additionally, backing up your configuration file, `jupyterhub_config.py`, to
a secure location.
### Shutdown JupyterHub
Prior to shutting down JupyterHub, you should notify the Hub users of the
scheduled downtime. This gives users the opportunity to finish any outstanding
work in process.
Next, shutdown the JupyterHub service.
### Upgrade JupyterHub
Follow directions that correspond to your package manager, `pip` or `conda`,
for the new JupyterHub release. These directions will guide you to the
specific command. In general, `pip install -U jupyterhub` or
`conda upgrade jupyterhub`
### Upgrade JupyterHub databases
To run the upgrade process for JupyterHub databases, enter:
```
jupyterhub upgrade-db
```
## Upgrade checklist
1. Backup JupyterHub database:
- `jupyterhub.sqlite` when using the default sqlite database
- Your JupyterHub database when using an RDBMS
2. Backup JupyterHub configuration file: `jupyterhub_config.py`
3. Shutdown the Hub
4. Upgrade JupyterHub
- `pip install -U jupyterhub` when using `pip`
- `conda upgrade jupyterhub` when using `conda`
5. Upgrade the database using run `jupyterhub upgrade-db`

View File

@@ -1,255 +0,0 @@
# JupyterHub URL scheme
This document describes how JupyterHub routes requests.
This does not include the [REST API](./rest.md) urls.
In general, all URLs can be prefixed with `c.JupyterHub.base_url` to
run the whole JupyterHub application on a prefix.
All authenticated handlers redirect to `/hub/login` to login users
prior to being redirected back to the originating page.
The returned request should preserve all query parameters.
## `/`
The top-level request is always a simple redirect to `/hub/`,
to be handled by the default JupyterHub handler.
In general, all requests to `/anything` that do not start with `/hub/`
but are routed to the Hub, will be redirected to `/hub/anything` before being handled by the Hub.
## `/hub/`
This is an authenticated URL.
This handler redirects users to the default URL of the application,
which defaults to the user's default server.
That is, it redirects to `/hub/spawn` if the user's server is not running,
or the server itself (`/user/:name`) if the server is running.
This default url behavior can be customized in two ways:
To redirect users to the JupyterHub home page (`/hub/home`)
instead of spawning their server,
set `redirect_to_server` to False:
```python
c.JupyterHub.redirect_to_server = False
```
This might be useful if you have a Hub where you expect
users to be managing multiple server configurations
and automatic spawning is not desirable.
Second, you can customise the landing page to any page you like,
such as a custom service you have deployed e.g. with course information:
```python
c.JupyterHub.default_url = '/services/my-landing-service'
```
## `/hub/home`
![The Hub home page with named servers enabled](../images/named-servers-home.png)
By default, the Hub home page has just one or two buttons
for starting and stopping the user's server.
If named servers are enabled, there will be some additional
tools for management of named servers.
*Version added: 1.0* named server UI is new in 1.0.
## `/hub/login`
This is the JupyterHub login page.
If you have a form-based username+password login,
such as the default PAMAuthenticator,
this page will render the login form.
![A login form](../images/login-form.png)
If login is handled by an external service,
e.g. with OAuth, this page will have a button,
declaring "Login with ..." which users can click
to login with the chosen service.
![A login redirect button](../images/login-button.png)
If you want to skip the user-interaction to initiate logging in
via the button, you can set
```python
c.Authenticator.auto_login = True
```
This can be useful when the user is "already logged in" via some mechanism,
but a handshake via redirects is necessary to complete the authentication with JupyterHub.
## `/hub/logout`
Visiting `/hub/logout` clears cookies from the current browser.
Note that **logging out does not stop a user's server(s)** by default.
If you would like to shutdown user servers on logout,
you can enable this behavior with:
```python
c.JupyterHub.shutdown_on_logout = True
```
Be careful with this setting because logging out one browser
does not mean the user is no longer actively using their server from another machine.
## `/user/:username[/:servername]`
If a user's server is running, this URL is handled by the user's given server,
not the Hub.
The username is the first part and, if using named servers,
the server name is the second part.
If the user's server is *not* running, this will be redirected to `/hub/user/:username/...`
## `/hub/user/:username[/:servername]`
This URL indicates a request for a user server that is not running
(because `/user/...` would have been handled by the notebook server
if the specified server were running).
Handling this URL is the most complicated condition in JupyterHub,
because there can be many states:
1. server is not active
a. user matches
b. user doesn't match
2. server is ready
3. server is pending, but not ready
If the server is pending spawn,
the browser will be redirected to `/hub/spawn-pending/:username/:servername`
to see a progress page while waiting for the server to be ready.
If the server is not active at all,
a page will be served with a link to `/hub/spawn/:username/:servername`.
Following that link will launch the requested server.
The HTTP status will be 503 in this case because a request has been made for a server that is not running.
If the server is ready, it is assumed that the proxy has not yet registered the route.
Some checks are performed and a delay is added before redirecting back to `/user/:username/:servername/...`.
If something is really wrong, this can result in a redirect loop.
Visiting this page will never result in triggering the spawn of servers
without additional user action (i.e. clicking the link on the page)
![Visiting a URL for a server that's not running](../images/not-running.png)
*Version changed: 1.0*
Prior to 1.0, this URL itself was responsible for spawning servers,
and served the progress page if it was pending,
redirected to running servers, and
This was useful because it made sure that requested servers were restarted after they stopped,
but could also be harmful because unused servers would continuously be restarted if e.g.
an idle JupyterLab frontend were open pointed at it,
which constantly makes polling requests.
### Special handling of API requests
Requests to `/user/:username[/:servername]/api/...` are assumed to be
from applications connected to stopped servers.
These are failed with 503 and an informative JSON error message
indicating how to spawn the server.
This is meant to help applications such as JupyterLab
that are connected to a server that has stopped.
*Version changed: 1.0*
JupyterHub 0.9 failed these API requests with status 404,
but 1.0 uses 503.
## `/user-redirect/...`
This URL is for sharing a URL that will redirect a user
to a path on their own default server.
This is useful when users have the same file at the same URL on their servers,
and you want a single link to give to any user that will open that file on their server.
e.g. a link to `/user-redirect/notebooks/Index.ipynb`
will send user `hortense` to `/user/hortense/notebooks/Index.ipynb`
**DO NOT** share links to your own server with other users.
This will not work in general,
unless you grant those users access to your server.
**Contributions welcome:** The JupyterLab "shareable link" should share this link
when run with JupyterHub, but it does not.
See [jupyterlab-hub](https://github.com/jupyterhub/jupyterlab-hub)
where this should probably be done and
[this issue in JupyterLab](https://github.com/jupyterlab/jupyterlab/issues/5388)
that is intended to make it possible.
## Spawning
### `/hub/spawn[/:username[/:servername]]`
Requesting `/hub/spawn` will spawn the default server for the current user.
If `username` and optionally `servername` are specified,
then the specified server for the specified user will be spawned.
Once spawn has been requested,
the browser is redirected to `/hub/spawn-pending/...`.
If `Spawner.options_form` is used,
this will render a form,
and a POST request will trigger the actual spawn and redirect.
![The spawn form](../images/spawn-form.png)
*Version added: 1.0*
1.0 adds the ability to specify username and servername.
Prior to 1.0, only `/hub/spawn` was recognized for the default server.
*Version changed: 1.0*
Prior to 1.0, this page redirected back to `/hub/user/:username`,
which was responsible for triggering spawn and rendering progress, etc.
### `/hub/spawn-pending[/:username[/:servername]]`
![The spawn pending page](../images/spawn-pending.png)
*Version added: 1.0* this URL is new in JupyterHub 1.0.
This page renders the progress view for the given spawn request.
Once the server is ready,
the browser is redirected to the running server at `/user/:username/:servername/...`.
If this page is requested at any time after the specified server is ready,
the browser will be redirected to the running server.
Requesting this page will never trigger any side effects.
If the server is not running (e.g. because the spawn has failed),
the spawn failure message (if applicable) will be displayed,
and the page will show a link back to `/hub/spawn/...`.
## `/hub/token`
![The token management page](../images/token-page.png)
On this page, users can manage their JupyterHub API tokens.
They can revoke access and request new tokens for writing scripts
against the [JupyterHub REST API](./rest.md).
## `/hub/admin`
![The admin panel](../images/named-servers-admin.png)
Administrators can take various administrative actions from this page:
1. add/remove users
2. grant admin privileges
3. start/stop user servers
4. shutdown JupyterHub itself

View File

@@ -76,7 +76,7 @@ resolves the cross-site issues.
### Disable user config
If subdomains are not available or not desirable, JupyterHub provides a
If subdomains are not available or not desirable, JupyterHub provides a a
configuration option `Spawner.disable_user_config`, which can be set to prevent
the user-owned configuration files from being loaded. After implementing this
option, PATHs and package installation and PATHs are the other things that the
@@ -99,23 +99,6 @@ single-user server, and not the environment(s) in which the user's kernel(s)
may run. Installing additional packages in the kernel environment does not
pose additional risk to the web application's security.
### Encrypt internal connections with SSL/TLS
By default, all communication on the server, between the proxy, hub, and single
-user notebooks is performed unencrypted. Setting the `internal_ssl` flag in
`jupyterhub_config.py` secures the aforementioned routes. Turning this
feature on does require that the enabled `Spawner` can use the certificates
generated by the `Hub` (the default `LocalProcessSpawner` can, for instance).
It is also important to note that this encryption **does not** (yet) cover the
`zmq tcp` sockets between the Notebook client and kernel. While users cannot
submit arbitrary commands to another user's kernel, they can bind to these
sockets and listen. When serving untrusted users, this eavesdropping can be
mitigated by setting `KernelManager.transport` to `ipc`. This applies standard
Unix permissions to the communication sockets thereby restricting
communication to the socket owner. The `internal_ssl` option will eventually
extend to securing the `tcp` sockets as well.
## Security audits
We recommend that you do periodic reviews of your deployment's security. It's
@@ -127,11 +110,3 @@ A handy website for testing your deployment is
[configurable-http-proxy]: https://github.com/jupyterhub/configurable-http-proxy
## Vulnerability reporting
If you believe youve found a security vulnerability in JupyterHub, or any
Jupyter project, please report it to
[security@ipython.org](mailto:security@iypthon.org). If you prefer to encrypt
your security reports, you can use [this PGP public
key](https://jupyter-notebook.readthedocs.io/en/stable/_downloads/ipython_security.asc).

View File

@@ -7,8 +7,8 @@ problem and how to resolve it.
[*Behavior*](#behavior)
- JupyterHub proxy fails to start
- sudospawner fails to run
- What is the default behavior when none of the lists (admin, allowed,
allowed groups) are set?
- What is the default behavior when none of the lists (admin, whitelist,
group whitelist) are set?
- JupyterHub Docker container not accessible at localhost
[*Errors*](#errors)
@@ -55,14 +55,14 @@ or add:
to the config file, `jupyterhub_config.py`.
### What is the default behavior when none of the lists (admin, allowed, allowed groups) are set?
### What is the default behavior when none of the lists (admin, whitelist, group whitelist) are set?
When nothing is given for these lists, there will be no admins, and all users
who can authenticate on the system (i.e. all the unix users on the server with
a password) will be allowed to start a server. The allowed username set lets you limit
this to a particular set of users, and admin_users lets you specify who
a password) will be allowed to start a server. The whitelist lets you limit
this to a particular set of users, and the admin_users lets you specify who
among them may use the admin interface (not necessary, unless you need to do
things like inspect other users' servers, or modify the user list at runtime).
things like inspect other users' servers, or modify the userlist at runtime).
### JupyterHub Docker container not accessible at localhost
@@ -75,50 +75,6 @@ tell Jupyterhub to start at `0.0.0.0` which is visible to everyone. Try this
command:
`docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub jupyterhub --ip 0.0.0.0 --port 8000`
### How can I kill ports from JupyterHub managed services that have been orphaned?
I started JupyterHub + nbgrader on the same host without containers. When I try to restart JupyterHub + nbgrader with this configuration, errors appear that the service accounts cannot start because the ports are being used.
How can I kill the processes that are using these ports?
Run the following command:
sudo kill -9 $(sudo lsof -t -i:<service_port>)
Where `<service_port>` is the port used by the nbgrader course service. This configuration is specified in `jupyterhub_config.py`.
### Why am I getting a Spawn failed error message?
After successfully logging in to JupyterHub with a compatible authenticators, I get a 'Spawn failed' error message in the browser. The JupyterHub logs have `jupyterhub KeyError: "getpwnam(): name not found: <my_user_name>`.
This issue occurs when the authenticator requires a local system user to exist. In these cases, you need to use a spawner
that does not require an existing system user account, such as `DockerSpawner` or `KubeSpawner`.
### How can I run JupyterHub with sudo but use my current env vars and virtualenv location?
When launching JupyterHub with `sudo jupyterhub` I get import errors and my environment variables don't work.
When launching services with `sudo ...` the shell won't have the same environment variables or `PATH`s in place. The most direct way to solve this issue is to use the full path to your python environment and add environment variables. For example:
```bash
sudo MY_ENV=abc123 \
/home/foo/venv/bin/python3 \
/srv/jupyterhub/jupyterhub
```
### How can I view the logs for JupyterHub or the user's Notebook servers when using the DockerSpawner?
Use `docker logs <container>` where `<container>` is the container name defined within `docker-compose.yml`. For example, to view the logs of the JupyterHub container use:
docker logs hub
By default, the user's notebook server is named `jupyter-<username>` where `username` is the user's username within JupyterHub's db. So if you wanted to see the logs for user `foo` you would use:
docker logs jupyter-foo
You can also tail logs to view them in real time using the `-f` option:
docker logs -f hub
## Errors
@@ -152,7 +108,7 @@ You should see a similar 200 message, as above, in the Hub log when you first
visit your single-user notebook server. If you don't see this message in the log, it
may mean that your single-user notebook server isn't connecting to your Hub.
If you see 403 (forbidden) like this, it's likely a token problem:
If you see 403 (forbidden) like this, it's a token problem:
```
403 GET /hub/api/authorizations/cookie/jupyterhub-token-name/[secret] (@10.0.1.4) 4.14ms
@@ -196,42 +152,6 @@ After this, when you start your server via JupyterHub, it will build a
new container. If this was the underlying cause of the issue, you should see
your server again.
##### Proxy settings (403 GET)
When your whole JupyterHub sits behind a organization proxy (*not* a reverse proxy like NGINX as part of your setup and *not* the configurable-http-proxy) the environment variables `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy` and `https_proxy` might be set. This confuses the jupyterhub-singleuser servers: When connecting to the Hub for authorization they connect via the proxy instead of directly connecting to the Hub on localhost. The proxy might deny the request (403 GET). This results in the singleuser server thinking it has a wrong auth token. To circumvent this you should add `<hub_url>,<hub_ip>,localhost,127.0.0.1` to the environment variables `NO_PROXY` and `no_proxy`.
### Launching Jupyter Notebooks to run as an externally managed JupyterHub service with the `jupyterhub-singleuser` command returns a `JUPYTERHUB_API_TOKEN` error
[JupyterHub services](https://jupyterhub.readthedocs.io/en/stable/reference/services.html) allow processes to interact with JupyterHub's REST API. Example use-cases include:
* **Secure Testing**: provide a canonical Jupyter Notebook for testing production data to reduce the number of entry points into production systems.
* **Grading Assignments**: provide access to shared Jupyter Notebooks that may be used for management tasks such grading assignments.
* **Private Dashboards**: share dashboards with certain group members.
If possible, try to run the Jupyter Notebook as an externally managed service with one of the provided [jupyter/docker-stacks](https://github.com/jupyter/docker-stacks).
Standard JupyterHub installations include a [jupyterhub-singleuser](https://github.com/jupyterhub/jupyterhub/blob/9fdab027daa32c9017845572ad9d5ba1722dbc53/setup.py#L116) command which is built from the `jupyterhub.singleuser:main` method. The `jupyterhub-singleuser` command is the default command when JupyterHub launches single-user Jupyter Notebooks. One of the goals of this command is to make sure the version of JupyterHub installed within the Jupyter Notebook coincides with the version of the JupyterHub server itself.
If you launch a Jupyter Notebook with the `jupyterhub-singleuser` command directly from the command line the Jupyter Notebook won't have access to the `JUPYTERHUB_API_TOKEN` and will return:
```
JUPYTERHUB_API_TOKEN env is required to run jupyterhub-singleuser.
Did you launch it manually?
```
If you plan on testing `jupyterhub-singleuser` independently from JupyterHub, then you can set the api token environment variable. For example, if were to run the single-user Jupyter Notebook on the host, then:
export JUPYTERHUB_API_TOKEN=my_secret_token
jupyterhub-singleuser
With a docker container, pass in the environment variable with the run command:
docker run -d \
-p 8888:8888 \
-e JUPYTERHUB_API_TOKEN=my_secret_token \
jupyter/datascience-notebook:latest
[This example](https://github.com/jupyterhub/jupyterhub/tree/master/examples/service-notebook/external) demonstrates how to combine the use of the `jupyterhub-singleuser` environment variables when launching a Notebook as an externally managed service.
## How do I...?
@@ -273,7 +193,7 @@ where `ssl_cert` is example-chained.crt and ssl_key to your private key.
Then restart JupyterHub.
See also [JupyterHub SSL encryption](./getting-started/security-basics.html#ssl-encryption).
See also [JupyterHub SSL encryption](getting-started.md#ssl-encryption).
### Install JupyterHub without a network connection
@@ -284,7 +204,7 @@ from there instead of the internet.
For instance, you can install JupyterHub with pip and configurable-http-proxy
with npmbox:
python3 -m pip wheel jupyterhub
pip wheel jupyterhub
npmbox configurable-http-proxy
### I want access to the whole filesystem, but still default users to their home directory
@@ -316,7 +236,7 @@ then you can change the default URL to `/lab`.
For instance:
python3 -m pip install jupyterlab
pip install jupyterlab
jupyter serverextension enable --py jupyterlab --sys-prefix
The important thing is that jupyterlab is installed and enabled in the
@@ -332,7 +252,8 @@ notebook servers to default to JupyterLab:
### How do I set up JupyterHub for a workshop (when users are not known ahead of time)?
1. Set up JupyterHub using OAuthenticator for GitHub authentication
2. Configure admin list to have workshop leaders be listed with administrator privileges.
2. Configure whitelist to be an empty list in` jupyterhub_config.py`
3. Configure admin list to have workshop leaders be listed with administrator privileges.
Users will need a GitHub account to login and be authenticated by the Hub.
@@ -360,6 +281,7 @@ Or use syslog:
jupyterhub | logger -t jupyterhub
## Troubleshooting commands
The following commands provide additional detail about installed packages,

Some files were not shown because too many files have changed in this diff Show More