docker.recipes

JupyterHub ML Environment

intermediate

JupyterHub with GPU support for ML.

Overview

JupyterHub is a multi-user server that spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server. Originally developed to serve computational environments for hundreds of users in educational and research settings, JupyterHub enables organizations to provide centralized access to Jupyter notebooks while maintaining user isolation and resource management. It supports various authentication methods and can spawn user environments in Docker containers, making it ideal for data science teams and ML workflows. This deployment creates a complete JupyterHub infrastructure with three core services: the main JupyterHub server for user management and notebook spawning, a PostgreSQL database (jupyterhub-db) for persistent storage of user data and hub state, and an NGINX reverse proxy for load balancing and SSL termination. The configuration includes Docker socket mounting to enable JupyterHub's DockerSpawner functionality, allowing it to create isolated containers for each user session with potential GPU access for machine learning workloads. This stack is perfect for data science teams, educational institutions, and research organizations that need to provide multiple users with consistent, isolated Jupyter environments. The combination of JupyterHub's multi-user capabilities, PostgreSQL's robust data persistence, and NGINX's high-performance proxying creates a production-ready platform for collaborative data science and machine learning development with the flexibility to scale from small teams to hundreds of concurrent users.

Key Features

  • Multi-user Jupyter notebook server with user isolation and resource management
  • DockerSpawner integration for containerized user environments with GPU support capability
  • PostgreSQL backend for persistent storage of user data, hub state, and session management
  • NGINX reverse proxy with load balancing and SSL termination support
  • Configurable authentication backends including OAuth, LDAP, PAM, and custom authenticators
  • Admin interface for user management, server control, and resource monitoring
  • Customizable user environments through Docker images with pre-installed ML libraries
  • Volume mounting support for shared datasets and collaborative workspaces

Common Use Cases

  • 1Data science teams requiring shared computational environments with version-controlled notebooks
  • 2Educational institutions providing students with consistent Python/R environments for coursework
  • 3Research organizations needing multi-user access to GPU resources for deep learning experiments
  • 4Corporate ML teams sharing datasets and models across different projects and users
  • 5Training workshops and bootcamps requiring instant notebook access for participants
  • 6Remote development teams needing centralized Jupyter environments with persistent storage
  • 7Organizations migrating from individual Jupyter installations to centralized management

Prerequisites

  • Docker Engine with minimum 4GB RAM allocated for user containers and ML workloads
  • Port 8000 available for JupyterHub web interface and port 80 for NGINX proxy
  • Custom jupyterhub_config.py file configured with desired authentication and spawner settings
  • NGINX configuration file (nginx.conf) with proper upstream and SSL settings
  • Environment variables set for DB_PASSWORD and optional JUPYTER_PORT/NGINX_PORT customization
  • Understanding of Docker container management and JupyterHub administration concepts

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 jupyterhub:
3 image: jupyterhub/jupyterhub:latest
4 container_name: jupyterhub
5 restart: unless-stopped
6 ports:
7 - "${JUPYTER_PORT:-8000}:8000"
8 environment:
9 - POSTGRES_HOST=jupyterhub-db
10 - POSTGRES_DB=jupyterhub
11 - POSTGRES_USER=jupyterhub
12 - POSTGRES_PASSWORD=${DB_PASSWORD}
13 volumes:
14 - jupyterhub_data:/srv/jupyterhub
15 - /var/run/docker.sock:/var/run/docker.sock
16 - ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro
17 depends_on:
18 - jupyterhub-db
19
20 jupyterhub-db:
21 image: postgres:15-alpine
22 container_name: jupyterhub-db
23 restart: unless-stopped
24 environment:
25 - POSTGRES_USER=jupyterhub
26 - POSTGRES_PASSWORD=${DB_PASSWORD}
27 - POSTGRES_DB=jupyterhub
28 volumes:
29 - jupyter_db_data:/var/lib/postgresql/data
30
31 nginx:
32 image: nginx:alpine
33 container_name: jupyter-nginx
34 restart: unless-stopped
35 ports:
36 - "${NGINX_PORT:-80}:80"
37 volumes:
38 - ./nginx.conf:/etc/nginx/nginx.conf:ro
39
40volumes:
41 jupyterhub_data:
42 jupyter_db_data:

.env Template

.env
1# JupyterHub
2JUPYTER_PORT=8000
3DB_PASSWORD=jupyterhub_password
4NGINX_PORT=80

Usage Notes

  1. 1Docs: https://jupyterhub.readthedocs.io/
  2. 2JupyterHub at http://localhost:8000 - multi-user notebook server
  3. 3Configure jupyterhub_config.py for authentication (OAuth, LDAP, PAM)
  4. 4Use DockerSpawner for isolated user containers with GPU support
  5. 5Mount shared datasets at /srv/data or use NFS for collaboration
  6. 6Pre-install libraries in custom Docker images for users

Individual Services(3 services)

Copy individual services to mix and match with your existing compose files.

jupyterhub
jupyterhub:
  image: jupyterhub/jupyterhub:latest
  container_name: jupyterhub
  restart: unless-stopped
  ports:
    - ${JUPYTER_PORT:-8000}:8000
  environment:
    - POSTGRES_HOST=jupyterhub-db
    - POSTGRES_DB=jupyterhub
    - POSTGRES_USER=jupyterhub
    - POSTGRES_PASSWORD=${DB_PASSWORD}
  volumes:
    - jupyterhub_data:/srv/jupyterhub
    - /var/run/docker.sock:/var/run/docker.sock
    - ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro
  depends_on:
    - jupyterhub-db
jupyterhub-db
jupyterhub-db:
  image: postgres:15-alpine
  container_name: jupyterhub-db
  restart: unless-stopped
  environment:
    - POSTGRES_USER=jupyterhub
    - POSTGRES_PASSWORD=${DB_PASSWORD}
    - POSTGRES_DB=jupyterhub
  volumes:
    - jupyter_db_data:/var/lib/postgresql/data
nginx
nginx:
  image: nginx:alpine
  container_name: jupyter-nginx
  restart: unless-stopped
  ports:
    - ${NGINX_PORT:-80}:80
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 jupyterhub:
5 image: jupyterhub/jupyterhub:latest
6 container_name: jupyterhub
7 restart: unless-stopped
8 ports:
9 - "${JUPYTER_PORT:-8000}:8000"
10 environment:
11 - POSTGRES_HOST=jupyterhub-db
12 - POSTGRES_DB=jupyterhub
13 - POSTGRES_USER=jupyterhub
14 - POSTGRES_PASSWORD=${DB_PASSWORD}
15 volumes:
16 - jupyterhub_data:/srv/jupyterhub
17 - /var/run/docker.sock:/var/run/docker.sock
18 - ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro
19 depends_on:
20 - jupyterhub-db
21
22 jupyterhub-db:
23 image: postgres:15-alpine
24 container_name: jupyterhub-db
25 restart: unless-stopped
26 environment:
27 - POSTGRES_USER=jupyterhub
28 - POSTGRES_PASSWORD=${DB_PASSWORD}
29 - POSTGRES_DB=jupyterhub
30 volumes:
31 - jupyter_db_data:/var/lib/postgresql/data
32
33 nginx:
34 image: nginx:alpine
35 container_name: jupyter-nginx
36 restart: unless-stopped
37 ports:
38 - "${NGINX_PORT:-80}:80"
39 volumes:
40 - ./nginx.conf:/etc/nginx/nginx.conf:ro
41
42volumes:
43 jupyterhub_data:
44 jupyter_db_data:
45EOF
46
47# 2. Create the .env file
48cat > .env << 'EOF'
49# JupyterHub
50JUPYTER_PORT=8000
51DB_PASSWORD=jupyterhub_password
52NGINX_PORT=80
53EOF
54
55# 3. Start the services
56docker compose up -d
57
58# 4. View logs
59docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/jupyter-ml-stack/run | bash

Troubleshooting

  • JupyterHub fails to start with 'database connection failed': Verify jupyterhub-db container is running and DB_PASSWORD environment variable matches between services
  • Users cannot spawn notebooks with 'spawn failed' error: Check that Docker socket is properly mounted and JupyterHub has permissions to create containers
  • NGINX returns 502 Bad Gateway: Ensure JupyterHub container is healthy and accessible on port 8000, verify nginx.conf upstream configuration
  • PostgreSQL data loss after container restart: Confirm jupyter_db_data volume is properly mounted and persistent
  • Out of memory errors during notebook execution: Increase Docker memory limits and configure resource limits in jupyterhub_config.py
  • Authentication loops or login failures: Review jupyterhub_config.py authentication settings and ensure proper authenticator configuration

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space