Skip to content
64 changes: 64 additions & 0 deletions examples/jupyter-sandbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Jupyter Sandbox

Run a published Jupyter image in OpenShell, expose its server locally, and
execute a local notebook on the sandboxed kernel.

Run these commands from `examples/jupyter-sandbox`. You need a local OpenShell
gateway, the `openshell` CLI, Cargo, and OpenSSL on the host.

## 1. Install the notebook CLI

Install the [Jupyter community notebook CLI](https://github.com/jupyter-ai-contrib/nb-cli):

```shell
cargo install nb-cli --version 0.0.10 --locked
```

OpenShell pulls the published `quay.io/jupyter/base-notebook:2026-04-27` image
when it creates the sandbox. The image includes Jupyter Server and a Python
kernel, so no container build is needed.

## 2. Launch the service

```shell
JUPYTER_TOKEN="$(openssl rand -hex 32)"
openshell sandbox create \
--name jupyter-demo \
--from quay.io/jupyter/base-notebook:2026-04-27 \
--policy policy.yaml \
--expose 8888 \
--detach --no-tty \
-- jupyter server \
--ServerApp.ip=127.0.0.1 \
--ServerApp.port=8888 \
--ServerApp.port_retries=0 \
--ServerApp.open_browser=False \
--ServerApp.root_dir=/home/jovyan \
--ServerApp.terminals_enabled=False \
--ServerApp.allow_remote_access=True \
--IdentityProvider.token="$JUPYTER_TOKEN"
```

The CLI prints the service URL after the sandbox is ready. Jupyter starts as
the sandbox's main process and listens on its loopback port. Keep the token in
this shell for step 3.

## 3. Execute the notebook on the remote kernel

Use the service URL printed in step 2 as the `--gateway` value:

```shell
nb execute demo.ipynb \
--gateway 'http://default--jupyter-demo.openshell.localhost:<gateway-port>/' \
--gateway-token "$JUPYTER_TOKEN"
```

The command writes `285` into `demo.ipynb` on your computer. Its code
runs in a Jupyter kernel inside the sandbox. The `nb` CLI accepts the service
URL as a flag and authenticates its REST and WebSocket connections.

When finished, delete the sandbox and its service:

```shell
openshell sandbox delete jupyter-demo
```
35 changes: 35 additions & 0 deletions examples/jupyter-sandbox/demo.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "intro",
"metadata": {},
"source": [
"# Jupyter in an OpenShell sandbox\n",
"This notebook runs on the sandboxed Jupyter kernel."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "sum-of-squares",
"metadata": {},
"outputs": [],
"source": [
"print(sum(i * i for i in range(10)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
20 changes: 20 additions & 0 deletions examples/jupyter-sandbox/policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

version: 1

filesystem_policy:
include_workdir: true
read_only: [/opt, /usr, /lib, /proc, /dev/urandom, /etc, /var/log]
read_write: [/home/jovyan, /tmp, /dev/null]

landlock:
compatibility: best_effort

process:
run_as_user: jovyan
run_as_group: users

# The Jupyter service is exposed inbound through the gateway. The notebook
# does not need outbound network access for this demonstration.
network_policies: {}
Loading