Installation scripts for SURF ResearchCloud catalog components
View the Project on GitHub UtrechtUniversity/researchcloud-items
This role allows you to installs any arbritrary webapplication on an existing JupyterHub instance. The application can be either:
In both cases, your application will be spawned by JupyterHub, running as the user logged in to the Hub. This means every user can get their own instance of the app.
This role can be involed multiple time (also in multiple playbooks) to add multiple apps to the Hub.
This role expects JupyterHub to be already installed. You need to tell the role where to find JupyterHub using the jupyterhub_app_venv
variable.
This role:
jupyter-server-proxy
extension for JupyterHub.pip
.
jupyterhub_app_pip
variable (see below) is set, the config file will be ommitted.Unless you are using jupyterhub_app_pip
, you need to set the jupyterhub_app_command
variable. Based on this variable, this role will generate a default configuration for both a JupyterLab server extension for your app, and a standalone version of your app.
In most cases, jupyterhub_app_pip
is the only variable you absolutely need to set: the role will take care of the rest. See an example here.
However, you can also further customize the configuration that wraps your app. See:
By default, this role will generate a default traitlets configuration file for a jupyter-server-proxy
app, based on a number of variables (see below):
jupyterhub_app_command
(required) For a minimal configuration, this variable is all you need to configure – the role will take care of the rest.jupyterhub_app_name
(optional, but recommended)jupyterhub_app_icon_path
(optional)jupyterhub_app_category
(optional)However, if you want to override the default configuration, you have two choices:
jupyterhub_app_server
variable. This is a dict that corresponds to the one illustrated here.jupyterhub_app_server_config
variable. This is a string of python code that you can use to completely control the traitlets config (see here for an example).The generated config file will be placed in jupyter_server_config.py
in jupyterhub_app_config_dir
, where it will be auto-loaded by JupyterLab.
By default, this role will generate a default traitlets configuration file for a [jupyter-standaloneproxy
]((https://jupyter-server-proxy.readthedocs.io/en/latest/standalone.html/) app, based on the jupyterhub_app_command
variable. For a minimal configuration, that variable is all you need to configure – the role will take care of the rest.
However, you can override this default using the jupyterhub_app_standalone_config
variable. See here for what a standalone config should look like.
This generated config will be placed into the directory standalone
inside the directory specified by the jupyterhub_app_config_dir
variable.
jupyterhub_app_venv
: String. Path to the JupyterHub instance’s venv
. Default: /usr/local/jupyterhub
. You can set this to the value system
to not use a virtual environment.jupyterhub_app_config_dir
: String. Path to the JupyterHub’s instance config dir. Default: /usr/local/etc/jupyter
.jupyterhub_app_pip_executable
: String. Which command to use to install packages into the venv (can be set to uv
when it is available). Default: pip
.jupyterhub_app_pip
: String. Optional. Which package to install into the hub’s venv (if set). Default: ""
. If this is set, no traitles config file will be placed.jupyterhub_app_name
: String. Name of the application, used to generate a filename for the standalone config file (if specified). Default: app
.jupyterhub_app_command
: List. Optional, but required when not setting jupyterhub_app_pip
. Specifies the command that will launch your application. Each item in the list after the first one will be an argument to your command. Default: ""
. See example.jupyterhub_app_icon_path
: String. Optional. Path to a .svg
icon file that will be used in JupyterLab to represnt your application (when not in standalone mode).jupyterhub_app_category
: String. Optional. JuypyterLab category this app wil be displayed under (when not in standalone mode). Default: ""
(this means the app will be placed in the Notebook
category).jupyterhub_app_server
: Dict. Settings for juypyter-server-proxy
, as specified here. See example. By default, this dictionary will be generated by the role based on the variables jupyterhub_app_command
, jupyterhub_app_icon_path
, jupyterhub_app_category
and jupyterhub_app_name
.jupyterhub_app_standalone_config
: String. Optional. Trailets configuration for a standalone app. See example. Default: ""
.jupyterhub_app_server_config
: String. Optional. Trailets configuration for a non-standalone proxy server app. See example. Will be added to jupyter_server_config.py
, automatically loaded jupyter-serverproxy
extension. Note: to allow multiple invocations of this role to add traitlets configuration in this way, see the example.The three examples in this section effectively accomplish the same thing, wrapping a simple Python http server as a JupyterHub app.
For more complicated applications, you may need to do some additional work in the config files. See e.g. the openvscodeserver playbook.
- role: jupyterhub_app
vars:
jupyterhub_app_name: Example
jupyterhub_app_venv: /path/to/jupyterhub/venv # Optional. Can also be set to 'system'
jupyterhub_app_config_dir: /usr/local/etc/jupyter # Optional. Can be any path in which JupyterHub looks for config files.
jupyterhub_app_pip_executable: pip # Optional. Can also set to uv if it's available, for better performance.
jupyterhub_app_icon_path: /path/to/my/icon.svg # Optional
jupyterhub_app_category: 'Other' # Optional. Category under which the app will be displayed in JupyterLab
jupyterhub_app_command:
- /usr/bin/python3
- -m
- http.server
- -p
- "{port}" # magic variable that will be replaced by `jupyter-server-proxy` with the port on which the Hub will spawn the instance. See: https://jupyter-server-proxy.readthedocs.io/en/latest/server-process.html#server-process-options
The resulting config for a JupyterLab server extension will look as follows:
settings = { "Example":
{'command': ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}'], 'launcher_entry': {'icon_path': '/path/to/my/icon.svg', 'category': 'Other'}
}
c.ServerProxy.servers.update({
}) # use update instead of assignment so multiple apps can be added to the config.
The resulting config for a standalone app will look as follows:
c.StandaloneProxyServer.command = ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']
jupyterhub_app_server
- role: jupyterhub_app
vars:
jupyterhub_app_server:
command: ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']
launcher_entry:
title: MyExample
icon_path: /path/to/icon.svg
category: Notebook
jupyterhub_app_server_config
and jupyterhub_app_standalone_config
- role: jupyterhub_app
vars:
jupyterhub_app_server_config: |
# 'c' is a traitles object that is automatically available in the config file
c.ServerProxy.servers.update({'command': ['/usr/bin/python3', '-m' 'http.server', '-p', '{port}']})
# ... some more Python code here, do whatever you like
jupyterhub_app_standalone_config: |
# 'c' is a traitlets object that is automatically available in the config file
c.StandaloneProxyServer.command = ['/usr/bin/python3', '-m' 'http.server', '-p', '{unix_socket}']
c.StandaloneProxyServer.unix_socket = True
# ... some more Python code here, do whatever you like
# you can also use the provided convenience functions from `utils.py` here, see the docs for the jupyterhub_standalone_proxy role.
2025 Written by Dawa Ometto (Utrecht University)