|
1 | 1 | # Jupyter Server Proxy for Panel |
2 | 2 |
|
3 | | -When jupyter-panel-proxy is installed and you launch a Jupyter server (Notebook, JupyterLab or JupyterHub), a Panel server will be launched when you visit the `/panel` endpoint of the server. This will show an index of all applications being served, to launch a particular application visit the corresponding endpoint `/panel/<name_of_file>`. |
| 3 | +<table> |
| 4 | +<tbody> |
| 5 | +<tr> |
| 6 | +<td>Downloads</td> |
| 7 | +<td><a href="https://pypistats.org/packages/jupyter-panel-proxy"><img src="https://img.shields.io/pypi/dm/jupyter-panel-proxy?label=pypi" alt="PyPi Downloads" /></a></td> |
| 8 | +</tr> |
| 9 | +<tr> |
| 10 | +<td>Build Status</td> |
| 11 | +<td><a href="https://github.com/holoviz/jupyter-panel-proxy/actions/workflows/test.yaml?query=branch%3Amain"><img src="https://github.com/holoviz/jupyter-panel-proxy/workflows/tests/badge.svg?query=branch%3Amain" alt="Linux/MacOS Build Status"></a></td> |
| 12 | +</tr> |
| 13 | +<tr> |
| 14 | +<td>Latest dev release</td> |
| 15 | +<td><a href="https://github.com/holoviz/jupyter-panel-proxy/tags"><img src="https://img.shields.io/github/v/tag/holoviz/jupyter-panel-proxy.svg?label=tag&colorB=11ccbb" alt="Github tag"></a></td> |
| 16 | +</tr> |
| 17 | +<tr> |
| 18 | +<td>Latest release</td> |
| 19 | +<td><a href="https://github.com/holoviz/jupyter-panel-proxy/releases"><img src="https://img.shields.io/github/release/holoviz/jupyter-panel-proxy.svg?label=tag&colorB=11ccbb" alt="Github release"></a> <a href="https://pypi.python.org/pypi/jupyter-panel-proxy"><img src="https://img.shields.io/pypi/v/jupyter-panel-proxy.svg?colorB=cc77dd" alt="PyPI version"></a> <a href="https://anaconda.org/pyviz/jupyter-panel-proxy"><img src="https://img.shields.io/conda/v/pyviz/jupyter-panel-proxy.svg?colorB=4488ff&style=flat" alt="panel version"></a> <a href="https://anaconda.org/conda-forge/jupyter-panel-proxy"><img src="https://img.shields.io/conda/v/conda-forge/jupyter-panel-proxy.svg?label=conda%7Cconda-forge&colorB=4488ff" alt="conda-forge version"></a></td> |
| 20 | +</tr> |
| 21 | +<td>Support</td> |
| 22 | +<td><a href="https://discourse.holoviz.org/"><img src="https://img.shields.io/discourse/status?server=https%3A%2F%2Fdiscourse.holoviz.org" alt="Discourse"></a> <a href="https://discord.gg/rb6gPXbdAr"><img alt="Discord" src="https://img.shields.io/discord/1075331058024861767"></a> |
| 23 | +</td> |
| 24 | +</tr> |
| 25 | +</tbody> |
| 26 | +</table> |
| 27 | + |
| 28 | +`jupyter-panel-proxy` integrates [HoloViz Panel](https://panel.holoviz.org) seamlessly with Jupyter environments (Notebook, JupyterLab, and JupyterHub). |
| 29 | +When installed, it launches a Panel server automatically at the `/panel` endpoint of your running Jupyter server. |
| 30 | + |
| 31 | +Visiting `/panel` will display an index of all available applications, and each application can be accessed at `/panel/<name_of_file>`. |
| 32 | + |
| 33 | +## When to use this project |
| 34 | + |
| 35 | +Use `jupyter-panel-proxy` when you want to: |
| 36 | + |
| 37 | +- *Serve Panel apps* alongside Jupyter notebooks or JupyterHub — without managing a separate web server. |
| 38 | +- *Reuse existing authentication* from JupyterHub and optionally integrate OAuth2 for finer-grained control. |
| 39 | +- *Automatically discover and serve multiple Panel apps* in a directory structure (no manual `panel serve` required). |
| 40 | +- *Deploy lightweight dashboards and interactive apps* close to your notebooks or lab environment. |
| 41 | +- *Run Panel behind a reverse proxy* with clean URL prefixing (`/panel`), and modern server features. |
4 | 42 |
|
5 | 43 | ## Installation |
6 | 44 |
|
7 | | -The `jupyter-panel-proxy` is available from `pip`: |
| 45 | +You can install `jupyter-panel-proxy` from PyPI: |
| 46 | + |
| 47 | +```bash |
| 48 | +pip install jupyter-panel-proxy |
| 49 | +```` |
8 | 50 |
|
9 | | - pip install jupyter-panel-proxy |
| 51 | +or from conda: |
10 | 52 |
|
11 | | -and conda: |
| 53 | +```bash |
| 54 | +conda install conda-forge::jupyter-panel-proxy |
| 55 | +``` |
12 | 56 |
|
13 | | - conda install -c pyviz jupyter-panel-proxy |
| 57 | +Once installed, a Panel server will be available at: |
| 58 | + |
| 59 | +``` |
| 60 | +https://<your-jupyter-server>/panel |
| 61 | +``` |
14 | 62 |
|
15 | 63 | ## Configuration |
16 | 64 |
|
17 | | -The jupyter-panel-proxy provides the ability to configure the proxy server by declaring a `jupyter-panel-proxy.yml` in the directory the Jupyter server is being launched from. The `yaml` file may declare the following keys: |
18 | | - |
19 | | -- `apps` (`list`): A list of applications or glob patterns to serve |
20 | | -- `launcher_entry` (`dict`): A [jupyter-server-proxy launcher entry specification](https://jupyter-server-proxy.readthedocs.io/en/latest/server-process.html#launcher-entry) |
21 | | -- `file_types` (`list(str)`): A list of file types to serve if no explicit apps list is provided |
22 | | -- `exclude_patterns` (`list(str)`): A list of glob/(fnmatch) patterns to exclude specific applications |
23 | | -- `index` (`str`): The path to a Bokeh index template |
24 | | -- `autoreload` (`bool`): Whether to automatically reload user sessions when the application or any of its imports change. |
25 | | -- `admin` (`bool`): Whether to load panel's admin module. |
26 | | -- `static_dirs` (`list`): A list of dicts mapping from server route to the static directory to be served |
27 | | -- `warm` (`bool`): Whether to execute scripts on startup to warm up the server. |
28 | | -- `num_procs` (`int`): Number of worker processes for an app. Using 0 will autodetect number of cores (defaults to 1) |
29 | | -- `oauth_provider` (`str`): The OAuth2 provider to use. |
30 | | -- `oauth-key` (`str`): The OAuth2 key to use |
31 | | -- `oauth-secret` (`str`): The OAuth2 secret to use |
32 | | -- `oauth-redirect-uri` (`str`): The OAuth2 redirect URI |
33 | | -- `oauth_extra_params` (`dict`): Additional parameters to the OAuth provider. |
34 | | -- `oauth_jwt_user` (`str`): The key in the ID JWT token to consider the user. |
| 65 | +You can configure the behavior of the proxy server by creating a `jupyter-panel-proxy.yml` file in the directory from which your Jupyter server is launched. |
| 66 | +
|
| 67 | +### Available configuration keys |
| 68 | +
|
| 69 | +| Key | Type | Description | |
| 70 | +| ---------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------- | |
| 71 | +| `apps` | `list` | List of apps or glob patterns to serve. If not set, apps are discovered automatically by file type. | |
| 72 | +| `file_types` | `list(str)` | File extensions to auto-discover apps (default: `ipynb`, `py`). | |
| 73 | +| `exclude_patterns` | `list(str)` | Glob/fnmatch patterns to exclude apps. | |
| 74 | +| `launcher_entry` | `dict` | A [jupyter-server-proxy launcher entry](https://jupyter-server-proxy.readthedocs.io/en/latest/server-process.html#launcher-entry). | |
| 75 | +| `index` | `str` | Path to a custom Bokeh index template. | |
| 76 | +| `autoreload` | `bool` | Automatically reload sessions when code changes. It is recommended to use `dev` instead. | |
| 77 | +| `dev ` | `bool` | Automatically reload sessions when code changes. | |
| 78 | +| `admin` | `bool` | Enable Panel's admin module. | |
| 79 | +| `warm` | `bool` | Execute apps on startup to warm up the server. | |
| 80 | +| `num_procs` | `int` | Number of worker processes (0 = auto). | |
| 81 | +| `num_threads` | `int` | Number of threads in the thread pool. | |
| 82 | +| `static_dirs` | `list` | Key=value routes for serving static files. | |
| 83 | +| `reuse_sessions` | `bool` | Reuse existing sessions (recommended for JupyterHub). | |
| 84 | +| `keep_alive` | `int` (ms) | Interval for keep-alive pings to clients. | |
| 85 | +| `check_unused_sessions` | `int` (ms) | How often to check for unused sessions. | |
| 86 | +| `unused_session_lifetime` | `int` (ms) | How long unused sessions last. | |
| 87 | +| `websocket_max_message_size` | `int` | Max message size for WebSocket in bytes. | |
| 88 | +| `root_path` | `str` | Root path can be used to handle cases where Panel is served behind a proxy. | |
| 89 | +| `cookie_path` | `str` | Path to apply cookies to. | |
| 90 | +| `log_level` | `str` | Log level (`info`, `debug`, etc.). | |
| 91 | +| `liveness` | `bool` | Enable a liveness endpoint. | |
| 92 | +| `liveness_endpoint` | `str` | Path of the liveness endpoint (default: `/liveness`). | |
| 93 | +| `profiler` | `str` | Profiler to use (e.g. `pyinstrument`). | |
| 94 | +| `global_loading_spinner` | `bool` | Add a global loading spinner to the UI. | |
| 95 | +| `oauth_provider` | `str` | OAuth2 provider name. | |
| 96 | +| `oauth_key` | `str` | OAuth2 key. | |
| 97 | +| `oauth_secret` | `str` | OAuth2 secret. | |
| 98 | +| `oauth_redirect_uri` | `str` | OAuth2 redirect URI. | |
| 99 | +| `oauth_extra_params` | `dict` | Additional parameters for the OAuth provider. | |
| 100 | +| `oauth_jwt_user` | `str` | JWT key to identify the user. | |
| 101 | +| `oauth_optional` | `bool` | Allow guest access to all endpoints. | |
| 102 | +| `oauth_guest_endpoints` | `list(str)` | List of endpoints accessible without authentication. | |
| 103 | +| `cookie_secret` | `str` | Secret key for secure cookies (can also be set via `PANEL_COOKIE_SECRET`). | |
| 104 | +| `oauth_encryption_key` | `str` | Encryption key for OAuth user info (can also be set via `OAUTH_ENCRYPTION_KEY`). | |
| 105 | +
|
| 106 | +## Launcher |
| 107 | +
|
| 108 | +When you install `jupyter-panel-proxy`, it automatically adds a Panel Launcher card to the JupyterLab and Notebook launcher interface: |
| 109 | +
|
| 110 | + |
| 111 | +
|
| 112 | +Clicking this Panel tile opens a new browser tab at `/panel` where your Panel apps are served. This behavior is controlled by the `launcher_entry` field in the configuration. |
| 113 | +
|
| 114 | +## Application discovery |
| 115 | +
|
| 116 | +By default, `jupyter-panel-proxy` automatically discovers Panel applications in the current working directory (or in an `examples/` subdirectory if present). |
| 117 | +
|
| 118 | +The discovery logic works like this: |
| 119 | +
|
| 120 | +1. If `apps` is defined in `jupyter-panel-proxy.yml`: |
| 121 | +
|
| 122 | + * Each entry is interpreted as a file path or glob pattern. |
| 123 | + * All matching files are included. |
| 124 | +
|
| 125 | +2. If `apps` is not defined: |
| 126 | +
|
| 127 | + * The proxy scans the base directory (or `./examples` if it exists) recursively. |
| 128 | + * It includes files that match any extension listed in `file_types` (default: `ipynb`, `py`). |
| 129 | + * It excludes any paths that match `exclude_patterns` (by default, this includes common patterns like `*setup.py` or `*.ipynb_checkpoints*`). |
| 130 | +
|
| 131 | +3. The discovered list of applications is then passed to `panel serve`. |
| 132 | +
|
| 133 | +## Example YAML configuration |
| 134 | +
|
| 135 | +```yaml |
| 136 | +# jupyter-panel-proxy.yml |
| 137 | +
|
| 138 | +log_level: info |
| 139 | +liveness: true |
| 140 | +liveness_endpoint: /health |
| 141 | +global_loading_spinner: true |
| 142 | +``` |
| 143 | + |
| 144 | +## How it works |
| 145 | + |
| 146 | +* When the Jupyter server starts, this proxy registers `/panel` as a route. |
| 147 | +* When a user navigates to `/panel`, the proxy launches `panel serve` internally with the configured options. |
| 148 | +* Apps are discovered automatically or defined explicitly. |
| 149 | +* The Panel server runs under the same authentication/session as Jupyter, and can optionally integrate OAuth for additional controls. |
| 150 | + |
| 151 | +## Further reading |
| 152 | + |
| 153 | +* [Panel Documentation](https://panel.holoviz.org) |
| 154 | +* [Jupyter Server Proxy](https://jupyter-server-proxy.readthedocs.io) |
| 155 | +* [HoloViz](https://holoviz.org) |
| 156 | + |
| 157 | +## License |
| 158 | + |
| 159 | +BSD-3-Clause |
0 commit comments