Reviewed-on: #4
JupyterHub Configuration with OrbStack on Mac (all in Docker)
Prerequisites
You must have docker running on your computer
- On MacOS, OrbStack is recommanded
Installation Steps
1. Create Directory Structure
git clone https://forge.metabarcoding.org/MetabarcodingSchool/OBIJupyterHub.git
Enter into the OBIJupyterHub
directory
cd OBIJupyterHub
File Structure
Your OBIJupyterHub
directory should contain:
OBIJupyterHub
├── start-jupyterhub.sh - The script used to setup and start the server
├── obijupyterhub - The files describing the docker images and the stack
│ ├── Caddyfile
│ ├── docker-compose.yml
│ ├── Dockerfile
│ ├── Dockerfile.hub
│ ├── jupyterhub_config.py
│ ├── sftpgo_config.json
│ └── start-notebook.sh
├── jupyterhub_volumes - The directory containing the docker volumes
│ ├── caddy
│ ├── course - Read only volume mounted on every student container
│ │ ├── bin
│ │ └── R_packages
│ ├── jupyterhub
│ ├── shared - Read write volume shared in every student container
│ ├── users
│ └── web
│ ├── img
│ │ └── welcome_metabar.webp
│ ├── index.html
│ └── pages
├── Readme.md - This documentation
├── tools
│ ├── generate_pages_json.py
│ └── install_packages.sh
└─── web_src - The quarto document sources used to build the web site
├── _output
├── _quarto.yml
├── 00_home.qmd
├── lectures
│ └── computers
│ └── regex
│ ├── lecture_regex.qmd
│ ├── slides_regex.qmd
│ └── slides.css
└── scripts
└── copy-to-web.sh
2. Start JupyterHub
From the terminal, in the OBIJupyterHub
directory, run the following command:
./start-jupyterhub.sh
3. Access JupyterHub
Open your browser and go to: http://localhost:8888
You can log in as a student with any username and password: metabar2025
Useful Commands
View JupyterHub logs
cd obijupyterhub
docker-compose logs -f jupyterhub
View all containers (hub + students)
docker ps | grep jupyterhub
Stop JupyterHub
cd obijupyterhub
docker-compose down
Restart JupyterHub (after config modification)
cd obijupyterhub
docker-compose restart jupyterhub
View logs for a specific student
docker logs jupyter-<username>
Replace <username>
by the actual username of the student.
Clean up after lab
# Stop and remove all containers
cd obijupyterhub
docker-compose down
# Remove student containers
docker ps -a | grep jupyter- | awk '{print $1}' | xargs docker rm -f
# Remove volumes (WARNING: deletes student data)
docker volume ls | grep jupyterhub-user | awk '{print $2}' | xargs docker volume rm
# Clean everything (containers + volumes + network)
docker-compose down -v
docker ps -a | grep jupyter- | awk '{print $1}' | xargs docker rm -f
docker volume prune -f
Managing Shared Data
Directory Structure for Each Student
Each student will see this directory structure in their JupyterLab (everything under work/
is persistent):
work/ # Personal workspace root (persistent)
├── [student files] # Their own files and notebooks
├── R_packages/ # Personal R packages (writable by student)
├── shared/ # Shared workspace (read/write, shared with all)
└── course/ # Course files (read-only, managed by admin)
├── R_packages/ # Shared R packages (read-only, installed by prof)
├── bin/ # Shared executables (in PATH)
└── [course materials] # Your course files
R Package Priority:
- R checks
work/R_packages/
first (personal, writable) - Then
work/course/R_packages/
(shared, read-only, installed by prof) - Then system libraries
Important: Everything is under work/
, so all student files are automatically saved in their persistent volume.
User Accounts
Admin Account:
- Username:
admin
- Password:
admin2025
(change in docker-compose.yml:JUPYTERHUB_ADMIN_PASSWORD
) - Can write to
course/
directory
Student Accounts:
- Username: any name
- Password:
metabar2025
(change in docker-compose.yml:JUPYTERHUB_PASSWORD
) - Read-only access to
course/
directory
Installing R Packages (Admin Only)
From your Mac (recommended):
# Install packages
tools/install_packages.sh reshape2 plotly knitr
This script: - Installs packages in the course/R_packages/
directory - All students can use them (read-only) - No need to rebuild the image
Students can also install their own packages:
Students can install packages in their personal work/R_packages/
:
# Install in personal library (each student has their own)
install.packages('mypackage') # Will install in work/R_packages/
Using R Packages (Students)
Students simply load packages normally:
library(reshape2) # R checks: 1) work/R_packages/ 2) work/course/R_packages/ 3) system
library(plotly)
R automatically searches in this order:
- Personal packages:
/home/jovyan/work/R_packages/
(R_LIBS_USER) - Prof packages:
/home/jovyan/work/course/R_packages/
(R_LIBS_SITE) - System packages
List Available Packages
# List all available packages (personal + course + system)
installed.packages()[,"Package"]
# Check personal packages
list.files("/home/jovyan/work/R_packages")
# Check course packages (installed by prof)
list.files("/home/jovyan/work/course/R_packages")
Deposit Files for Course
To put files in the course/
directory (accessible read-only):
# Create a temporary directory
mkdir -p ~/jupyterhub-tp/course-files
# Copy your files into it
cp my_notebooks.ipynb ~/jupyterhub-tp/course-files/
cp my_data.csv ~/jupyterhub-tp/course-files/
# Copy into Docker volume
docker run --rm \
-v jupyterhub-course:/target \
-v ~/jupyterhub-tp/course-files:/source \
alpine sh -c "cp -r /source/* /target/"
Retrieve Student Work
# List user volumes
docker volume ls | grep 'obijupyterhub_user-'
# Copy files from a specific student
docker run --rm \
-v obijupyterhub_user-alice:/source \
-v ~/submissions:/target \
alpine sh -c "cp -r /source/* /target/alice/"
# Copy all shared work
docker run --rm \
-v obijupyterhub_shared:/source \
-v ~/submissions/shared:/target \
alpine sh -c "cp -r /source/* /target/"
User Management
Option 1: Predefined User List
In jupyterhub_config.py
, uncomment and modify:
c.Authenticator.allowed_users = {'student1', 'student2', 'student3'}
Option 2: Allow Everyone (for testing)
By default, the configuration allows any user:
c.Authenticator.allow_all = True
⚠️ Warning: DummyAuthenticator is ONLY for local testing!
Kernel Verification
Once logged in, create a new notebook and verify you have access to:
- Python 3 (default kernel)
- R (R kernel)
- Bash (bash kernel)
Customization for Your Labs
Add Additional R Packages
Modify the Dockerfile
(before USER ${NB_UID}
):
RUN R -e "install.packages(c('your_package'), repos='http://cran.rstudio.com/')"
Then restart the server (it rebuilds the images if needed):
./start-jupyterhub.sh
Add Python Packages
Add to the Dockerfile
(before USER ${NB_UID}
):
RUN pip install numpy pandas matplotlib seaborn
Distribute Files to Students
Create a files_lab/
directory and add to the Dockerfile
:
COPY files_lab/ /home/${NB_USER}/lab/
RUN chown -R ${NB_UID}:${NB_GID} /home/${NB_USER}/lab
Change Port (if 8000 is occupied)
Modify in docker-compose.yml
:
ports:
- "8001:8000" # Accessible on localhost:8001
Advantages of This Approach
✅ Everything in Docker: No need to install Python/JupyterHub on your computer
✅ Portable: Easy to deploy on another server
✅ Isolated: No pollution of your system environment
✅ Easy to Clean: A simple docker-compose down
is enough
✅ Reproducible: Students will have exactly the same environment
Troubleshooting
Error "Cannot connect to Docker daemon":
- Check that OrbStack is running
- Verify the socket exists:
ls -la /var/run/docker.sock
Student containers don't start:
- Check logs:
docker-compose logs jupyterhub
- Verify student image exists:
docker images | grep jupyterhub-student
Port 8000 already in use:
- Change port in
docker-compose.yml
I want to start from scratch:
push obijupyterhub
docker-compose down -v
docker rmi jupyterhub-hub jupyterhub-student
popd
# Then rebuild everything
./start-jupyterhub.sh