Configuring JupyterLab or JupyterHub with LabNow AI Docker Images: A Complete Guide

LabNow AI Docker images provide pre-configured Ubuntu-based containers with Conda-managed Python 3.12, enabling single-command deployment of JupyterLab or JupyterHub environments through minimal Dockerfile extensions and standard docker run commands.

The labnow-ai/lab-foundation repository supplies a modular stack of container images that eliminate environment configuration overhead when configuring JupyterLab or JupyterHub with LabNow AI Docker images. Each layer—from the base OS to optional CUDA drivers—is engineered to support immediate scientific computing workloads without manual dependency resolution.

Architectural Overview of the LabNow AI Image Stack

The foundation repository organizes containers into four distinct layers. Understanding this hierarchy ensures you select the optimal base for your specific Jupyter deployment.

OS Layer: labnow/atom

Built from docker_atom/Dockerfile, this layer provides the Ubuntu Noble base system with essential OS packages, locale configuration, and sudo setup. It serves as the immutable foundation for all downstream images.

Python and Conda Layer: labnow/base

Constructed via docker_base/Dockerfile, this image inherits from labnow/atom and installs Miniconda alongside Python 3.12. It includes the uv fast installer and optionally replaces the system Python with the Conda-managed version, creating a self-contained runtime for scientific libraries.

GPU Acceleration Layer: labnow/cuda

For workloads requiring NVIDIA GPUs, docker_cuda/nvidia-cuda.Dockerfile extends the base image with proprietary driver libraries and the CUDA toolkit. This layer maintains compatibility with the Conda environment while exposing GPU hardware to containers.

Application Layer: Your Custom Configuration

The final layer is your responsibility. By creating a thin Dockerfile that references one of the LabNow base images, you install Jupyter components, configure networking, and expose service ports without managing OS-level dependencies.

Configure JupyterLab for Single-User Notebooks

To deploy a personal JupyterLab instance, extend labnow/base with the server application and network configuration.

Create a Dockerfile in your project root:


# Use the LabNow base image containing Conda + Python 3.12

FROM labnow/base:latest

LABEL maintainer="postmaster@labnow.ai"

# Install JupyterLab and generate default configuration

RUN pip install --no-cache-dir jupyterlab notebook && \
    jupyter lab --generate-config && \
    echo "c.ServerApp.ip = '0.0.0.0'" >> /root/.jupyter/jupyter_server_config.py && \
    echo "c.ServerApp.open_browser = False" >> /root/.jupyter/jupyter_server_config.py && \
    echo "c.ServerApp.port = 8888" >> /root/.jupyter/jupyter_server_config.py && \
    echo "c.ServerApp.token = 'YOUR_TOKEN_HERE'" >> /root/.jupyter/jupyter_server_config.py

EXPOSE 8888

CMD ["jupyter", "lab"]

Build and run the container:

docker build -t labnow/jupyterlab:latest .
docker run -d --name jlab -p 8888:8888 labnow/jupyterlab:latest

Access the environment at http://localhost:8888 using the token specified in the configuration. Because docker_base/Dockerfile already established the Conda environment, additional packages install via conda install or pip install without compiler errors.

Deploy JupyterHub for Multi-User Environments

For team-based deployments, configure JupyterHub by installing the hub application and proxy on the same base image.

Create a dedicated Dockerfile:

FROM labnow/base:latest

LABEL maintainer="postmaster@labnow.ai"

# Install JupyterHub and configurable HTTP proxy

RUN pip install --no-cache-dir jupyterhub configurable-http-proxy && \
    echo "c.JupyterHub.bind_url = 'http://0.0.0.0:8000'" > /opt/jupyterhub_config.py && \
    echo "c.JupyterHub.logo_file = ''" >> /opt/jupyterhub_config.py

EXPOSE 8000

CMD ["jupyterhub", "-f", "/opt/jupyterhub_config.py"]

Execute the build and deployment:

docker build -t labnow/jupyterhub:latest .
docker run -d --name jhub -p 8000:8000 labnow/jupyterhub:latest

Navigate to http://localhost:8000 to access the multi-user interface. Production deployments should mount a persistent volume containing a full jupyterhub_config.py and database backend; the LabNow image provides the core runtime, leaving orchestration decisions to your infrastructure team.

Enable GPU Support for CUDA Workloads

When configuring JupyterLab for deep learning, inherit from labnow/cuda to leverage NVIDIA GPUs.

FROM labnow/cuda:latest

LABEL maintainer="postmaster@labnow.ai"

# Install JupyterLab and PyTorch with CUDA support

RUN pip install --no-cache-dir jupyterlab \
    torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121 && \
    jupyter lab --generate-config && \
    echo "c.ServerApp.ip = '0.0.0.0'" >> /root/.jupyter/jupyter_server_config.py && \
    echo "c.ServerApp.open_browser = False" >> /root/.jupyter/jupyter_server_config.py && \
    echo "c.ServerApp.port = 8888" >> /root/.jupyter/jupyter_server_config.py

EXPOSE 8888

CMD ["jupyter", "lab"]

Execute with GPU access enabled:

docker run -d --gpus all -p 8888:8888 labnow/jupyterlab-gpu:latest

The --gpus all flag delegates host NVIDIA drivers to the container, while the underlying docker_cuda/nvidia-cuda.Dockerfile ensures compatibility with the CUDA toolkit and Conda-managed Python.

Key Source Files in labnow-ai/lab-foundation

File Purpose Location
docker_atom/Dockerfile Ubuntu Noble base, locale, sudo, and utility scripts in /opt/utils docker_atom/Dockerfile
docker_base/Dockerfile Miniconda installation, Python 3.12, uv installer, Python replacement logic docker_base/Dockerfile
docker_cuda/nvidia-cuda.Dockerfile NVIDIA driver libraries and CUDA toolkit integration docker_cuda/nvidia-cuda.Dockerfile
docker_core/Dockerfile Curated data-science packages (NumPy, pandas, etc.) as alternative heavy-weight base docker_core/Dockerfile

All images publish automatically to Docker Hub and Quay.io under the labnow namespace, supporting reproducible builds across development and production environments.

Summary

  • Select the appropriate base image: Use labnow/base for CPU-only workloads, labnow/cuda for GPU acceleration, and labnow/core for pre-installed data-science stacks.
  • Configure network binding: Always set c.ServerApp.ip = '0.0.0.0' (JupyterLab) or c.JupyterHub.bind_url (JupyterHub) to accept connections outside the container.
  • Expose correct ports: Port 8888 for JupyterLab, port 8000 for JupyterHub.
  • Leverage existing Conda environment: The docker_base/Dockerfile establishes Python 3.12 via Miniconda, eliminating the need for manual Python installation in your extended images.
  • Enable GPU access: Append --gpus all to docker run commands when using labnow/cuda-based images.

Frequently Asked Questions

Which LabNow base image should I choose for CPU versus GPU workloads?

Select labnow/base (built from docker_base/Dockerfile) for standard CPU-based data analysis and labnow/cuda (built from docker_cuda/nvidia-cuda.Dockerfile) when your notebooks require NVIDIA GPU acceleration. The CUDA image inherits all Conda and Python 3.12 capabilities from the base layer while adding proprietary driver support.

How do I configure authentication tokens and passwords in JupyterLab?

During image build, append c.ServerApp.token = 'YOUR_VALUE' to /root/.jupyter/jupyter_server_config.py as demonstrated in the single-user Dockerfile. For password-based authentication, replace the token line with c.ServerApp.password = 'argon2:...' using a hashed password generated via jupyter server password.

Can I extend LabNow images with additional Conda or pip packages?

Yes. Because the images use Conda as the primary Python provider, add RUN conda install -y package_name or RUN pip install package_name instructions to your application-layer Dockerfile. The uv installer included in docker_base/Dockerfile accelerates pip installations, while the isolated Conda environment prevents conflicts with system packages.

What is the difference between configuring JupyterLab on port 8888 versus JupyterHub on port 8000?

JupyterLab operates as a single-user server and traditionally listens on port 8888 with configuration keys prefixed by c.ServerApp. JupyterHub functions as a multi-user proxy and spawner, listening on port 8000 via c.JupyterHub.bind_url. The Hub spawns individual Lab instances for each user, whereas the standalone Lab image serves one user per container instance.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →