2025-11-25 11:59:28 +01:00
# OBIJupyterHub - the DNA Metabarcoding Learning Server
2025-10-14 17:40:41 +02:00
2025-11-25 10:51:23 +01:00
## Intended use
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
This project packages the MetabarcodingSchool training lab into one reproducible bundle. You get Python, R, and Bash kernels, a Quarto-built course website, and preconfigured admin/student accounts, so onboarding a class is a single command instead of a day of setup. Everything runs locally on a single machine, student work persists between sessions, and `./start-jupyterhub.sh` takes care of pulling images, rendering the site, preparing volumes, and bringing JupyterHub up at `http://localhost:8888` .
2025-10-14 17:40:41 +02:00
2025-11-25 10:51:23 +01:00
## Prerequisites (with quick checks)
2025-10-15 15:04:00 +02:00
2025-12-17 10:44:58 +01:00
You only need **Docker and Docker Compose ** on the machine that will host the lab. All other tools (Quarto, Hugo, Python, R) are provided via a builder Docker image and do not need to be installed on your system.
2025-10-14 17:40:41 +02:00
2025-11-25 10:51:23 +01:00
- macOS: install [OrbStack ](https://orbstack.dev/ ) (recommended) or Docker Desktop; both ship Docker Engine and Compose.
2026-04-30 19:34:49 +02:00
- Linux: install Docker Engine and the Compose plugin (`sudo apt install docker.io docker-compose-plugin` ) or from Docker's official packages.
2025-11-25 10:51:23 +01:00
- Windows: install Docker Desktop with the WSL2 backend enabled.
2025-11-17 14:22:19 +01:00
2025-12-17 10:44:58 +01:00
Verify from a terminal:
2025-10-14 17:40:41 +02:00
2025-10-16 01:07:07 +02:00
``` bash
2025-11-25 10:51:23 +01:00
docker --version
docker compose version # or: docker-compose --version
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
## Three operating modes
2025-11-25 10:51:23 +01:00
2026-04-30 19:34:49 +02:00
`./start-jupyterhub.sh` has three modes that control how Docker images are obtained:
2025-11-25 10:51:23 +01:00
2026-04-30 19:34:49 +02:00
| Mode | Flag | Description |
|------|------|-------------|
| **Pull ** (default) | * (none) * | Pull pre-built images from the registry and start |
| **Local build ** | `--local-build` | Build images locally on your machine and start (no push) |
| **Publish ** | `--publish` | Build multi-arch images (amd64 + arm64), push to registry, then start |
2025-11-25 10:51:23 +01:00
2026-04-30 19:34:49 +02:00
### Pull mode — default, fastest
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh
```
Downloads the three pre-built images from `registry.metabarcoding.org/metabarschool/` :
- `obijupyterhub-builder:latest`
- `obijupyterhub-hub:latest`
- `obijupyterhub-student:latest`
This is what instructors should use in class. No compilation, no wait.
### Local build mode — for development
``` bash
./start-jupyterhub.sh --local-build
```
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
Builds all three images locally using the Dockerfiles in `obijupyterhub/` . Rebuilt images stay on your machine and are not pushed to the registry. Additional flags apply only in this mode:
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
| Flag | Effect |
|------|--------|
| `--no-build` / `--offline` | Skip all image operations, use whatever is already local |
| `--force-rebuild` | Rebuild all images without Docker cache |
| `--rebuild-builder` | Force rebuild the builder image only |
| `--rebuild-student` | Force rebuild the student image only |
| `--rebuild-hub` | Force rebuild the JupyterHub image only |
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
`--rebuild-*` and `--force-rebuild` imply `--local-build` automatically.
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
### Publish mode — for maintainers
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh --publish
```
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
Builds all three images for both `linux/amd64` and `linux/arm64` using `docker buildx` , then pushes them to the registry tagged with both `:latest` and the version from `version.txt` . Requires write access to the registry and `docker buildx` with a `docker-container` driver.
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
**Before publishing a new version ** , bump `version.txt` at the project root:
```
0.2.0
```
2025-11-25 11:59:28 +01:00
2026-04-30 19:34:49 +02:00
## Actions (all modes)
These flags work alongside any mode:
| Flag | Effect |
|------|--------|
| `--stop-server` | Stop the stack and remove student containers, then exit |
| `--update-lectures` | Rebuild the course website only (no Docker stop/start) |
| `--build-obidoc` | Force rebuild of the obidoc documentation |
2025-11-25 11:59:28 +01:00
2025-11-25 10:51:23 +01:00
## Installation and first run
2026-04-30 19:34:49 +02:00
1. Clone the project:
2025-10-16 01:07:07 +02:00
``` bash
2025-11-25 10:51:23 +01:00
git clone https://forge.metabarcoding.org/MetabarcodingSchool/OBIJupyterHub.git
2025-10-16 01:07:07 +02:00
cd OBIJupyterHub
```
2026-04-30 19:34:49 +02:00
2. Repository structure:
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
```
OBIJupyterHub/
├── start-jupyterhub.sh single entry point
├── version.txt current image version number
├── obijupyterhub/
│ ├── docker-compose.yml
│ ├── Dockerfile student image
│ ├── Dockerfile.hub JupyterHub image
│ ├── Dockerfile.builder builder image (Quarto, Hugo, R, Python)
│ └── jupyterhub_config.py
├── jupyterhub_volumes/ data persisted on the host
│ ├── builder/R_packages/ R package cache for building lectures
│ ├── course/ read-only for students (notebooks, data, bin)
│ ├── shared/ shared read/write space for everyone
│ ├── users/ per-user persistent data
│ └── web/ rendered course website
├── tools/
│ ├── install_quarto_deps.R automatic R dependency detection and install
│ └── install_packages.sh install shared R packages into course/
└── web_src/ Quarto sources for the course website
```
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
3. (Optional) place course materials in `jupyterhub_volumes/course/` before first run.
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
4. Start everything:
2025-10-16 01:07:07 +02:00
2025-11-25 10:51:23 +01:00
``` bash
2026-04-30 19:34:49 +02:00
./start-jupyterhub.sh # pulls images from registry (recommended)
# or
./start-jupyterhub.sh --local-build # builds locally
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
5. Access JupyterHub at `http://localhost:8888` .
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
6. Stop when done:
2025-10-15 15:04:00 +02:00
2025-11-25 10:51:23 +01:00
``` bash
2026-04-30 19:34:49 +02:00
./start-jupyterhub.sh --stop-server
# or from obijupyterhub/
2025-10-14 17:40:41 +02:00
docker-compose down
```
2026-04-30 19:34:49 +02:00
## How the builder image works
2025-10-15 14:08:52 +02:00
2026-04-30 19:34:49 +02:00
The `obijupyterhub-builder` image contains Quarto, Hugo, R, and Python — you do not need any of these on your host. The script runs this image as a temporary container to:
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
- detect R package dependencies from your `.qmd` files (scans `library()` , `require()` , and `remotes::install_git/github()` calls using base R — no external package required)
- install missing R packages into `jupyterhub_volumes/builder/R_packages/` (cached between runs)
- render the Quarto website from `web_src/`
- generate PDF galleries and `pages.json`
- (optionally) build the obidoc documentation with Hugo
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
### R package caching
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
Packages are cached in `jupyterhub_volumes/builder/R_packages/` :
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
- **First build**: all packages used in your `.qmd` files are detected and installed (may take a while).
- **Subsequent builds**: only new packages are installed, making builds much faster.
- **Non-CRAN packages**: packages installed via `remotes::install_git()` or `remotes::install_github()` in your `.qmd` files are detected and pre-installed automatically before rendering.
- **Clear the cache**: delete `jupyterhub_volumes/builder/R_packages/` to force a full reinstall.
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
## Managing course and student data
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
Each student lands in `/home/jovyan/work/` with three areas:
2025-10-15 14:08:52 +02:00
2026-04-30 19:34:49 +02:00
```
work/
├── [student files] personal workspace (persistent)
├── R_packages/ personal R packages (writable by student)
├── shared/ shared space (read/write, all students)
└── course/ course files (read-only)
├── R_packages/ shared R packages installed by the instructor
├── bin/ shared executables (added to PATH)
└── [course materials]
2025-10-15 14:08:52 +02:00
```
2026-04-30 19:34:49 +02:00
On the host, place course files in `jupyterhub_volumes/course/` , collaborative files in `jupyterhub_volumes/shared/` , and collect student work from `jupyterhub_volumes/users/` .
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
### Installing shared R packages (instructor)
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
``` bash
tools/install_packages.sh reshape2 plotly knitr
2025-10-15 07:15:05 +02:00
```
2026-04-30 19:34:49 +02:00
### Installing personal R packages (students)
2025-10-16 01:07:07 +02:00
2026-04-30 19:34:49 +02:00
``` r
install.packages ( ' mypackage' ) # installs into work/R_packages/
```
2025-10-15 07:15:05 +02:00
2026-04-30 19:34:49 +02:00
### Loading packages (students)
2025-10-15 14:08:52 +02:00
2026-04-30 19:34:49 +02:00
``` r
library ( reshape2 ) # searches: work/R_packages/ → work/course/R_packages/ → system
2025-10-15 07:15:05 +02:00
```
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
## User accounts
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
Defaults are set in `obijupyterhub/docker-compose.yml` :
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
| Account | Username | Password |
|---------|----------|----------|
| Admin | `admin` | `admin2025` |
| Students | any | `metabar2025` |
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
Change `JUPYTERHUB_ADMIN_PASSWORD` and `JUPYTERHUB_PASSWORD` in the compose file, then rerun `./start-jupyterhub.sh` .
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
To restrict access to a predefined list, edit `jupyterhub_config.py` :
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
``` python
2025-10-15 07:10:44 +02:00
c . Authenticator . allowed_users = { ' student1 ' , ' student2 ' , ' student3 ' }
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
## Customising the images
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
All image customisations require a rebuild. Use `--local-build` (or the targeted `--rebuild-*` flag) to apply changes locally, or `--publish` to push them to the registry.
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
### Add R packages baked into the student image
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
Edit `obijupyterhub/Dockerfile` (before `USER ${NB_UID}` ):
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
``` dockerfile
RUN R -e "install.packages(c('your_package'), repos='http://cran.rstudio.com/')"
```
2025-10-16 01:07:07 +02:00
2026-04-30 19:34:49 +02:00
Then rebuild:
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh --rebuild-student
```
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
### Add Python packages
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
Edit `obijupyterhub/Dockerfile` (before `USER ${NB_UID}` ):
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
``` dockerfile
RUN pip install numpy pandas matplotlib seaborn
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
Then rebuild:
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh --rebuild-student
```
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
### Change the listening port
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
In `obijupyterhub/docker-compose.yml` :
``` yaml
ports :
- "8001:80" # accessible at http://localhost:8001
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
## Troubleshooting
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
**Docker daemon unavailable ** : make sure OrbStack / Docker Desktop / the daemon is running.
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
**Student containers do not start ** : run `docker-compose logs jupyterhub` from `obijupyterhub/` and confirm the student image is present:
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
``` bash
docker images | grep obijupyterhub-student
2025-10-14 17:40:41 +02:00
```
2026-04-30 19:34:49 +02:00
**Port conflict ** : change the published port in `docker-compose.yml` .
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
**Registry pull fails ** : check your network, or fall back to a local build:
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh --local-build
```
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
**Start from scratch ** :
2025-10-14 17:40:41 +02:00
2026-04-30 19:34:49 +02:00
``` bash
./start-jupyterhub.sh --stop-server
2025-10-15 15:04:00 +02:00
2026-04-30 19:34:49 +02:00
cd obijupyterhub
2025-10-14 17:40:41 +02:00
docker-compose down -v
2026-04-30 19:34:49 +02:00
docker rmi jupyterhub-hub jupyterhub-student obijupyterhub-builder 2>/dev/null || true
docker rmi registry.metabarcoding.org/metabarschool/obijupyterhub-hub:latest \
registry.metabarcoding.org/metabarschool/obijupyterhub-student:latest \
registry.metabarcoding.org/metabarschool/obijupyterhub-builder:latest 2>/dev/null || true
cd ..
2025-10-16 01:07:07 +02:00
2026-04-30 19:34:49 +02:00
rm -rf jupyterhub_volumes/builder/R_packages # clear R package cache
2025-12-17 10:44:58 +01:00
2026-04-30 19:34:49 +02:00
./start-jupyterhub.sh # pull fresh images and start
2025-11-17 14:22:19 +01:00
```