# JupyterLab Workspace

Deploys a Instance with Python and JupyterLab pre-installed. Accessible through a browser. Useful for data science, ML experimentation, or quick Python development.

#### Architecture:

* 1 Instance (StellarSurge — 4 vCPU, 16 GB RAM)
* 1 private network (10.200.0.0/24)
* 1 floating IP (public access)
* 60 GB boot volume
* Security group allows SSH, port 8888

#### What is automated:

* Instance creation with selected flavor and image
* Private network, subnet, and router
* Floating IP assigned to Instance
* Security group with ports 22, 8888
* Python 3 venv created under dedicated `jupyter` user
* Installed: JupyterLab, NumPy, Pandas, Scikit-learn, Matplotlib, Seaborn, Transformers, PyTorch (CPU)
* JupyterLab configured with random password
* Runs as systemd service (auto-restart on reboot)
* Credentials saved to `/root/.jupyter_credentials`

#### Before you launch:

Update these parameters in the template or at launch time:

| Parameter        | Default                | What to change                                                                 |
| ---------------- | ---------------------- | ------------------------------------------------------------------------------ |
| `key_name`       | `stack-test`           | **Required.** Replace with your SSH keypair name from **Compute - Key Pairs**. |
| `image`          | `Ubuntu 22.04 Updated` | Change only if you need a different OS image.                                  |
| `flavor`         | `StellarSurge`         | **Minimum StellarSurge (4 vCPU, 16 GB).** Do not use smaller flavors.          |
| `volume_size`    | `60`                   | Increase if you plan to work with large datasets (in GB).                      |
| `public_network` | `Public`               | Do not change unless your cloud has a different external network name.         |

{% hint style="info" %}
**key\_name is the only parameter you must change before launching.** Everything else works with defaults.
{% endhint %}

#### JupyterLab Template

Save as `jupyterlab.yaml` and upload via Orchestration or Past Direct.

```
heat_template_version: 2021-04-16
description: >
  NeevCloud: JupyterLab AI Workspace with Python data science stack.
  Flavor minimum: StellarSurge (4 vCPU, 16 GB RAM).
  JupyterLab accessible on port 8888.

parameters:
  image:
    type: string
    default: Ubuntu 22.04 Updated
  flavor:
    type: string
    default: StellarSurge
  volume_size:
    type: number
    description: Boot volume size in GB
    default: 60
  public_network:
    type: string
    default: Public
  key_name:
    type: string
    default: stack-test

resources:
  net:
    type: OS::Neutron::Net
    properties:
      name: jupyter-net

  subnet:
    type: OS::Neutron::Subnet
    properties:
      network: { get_resource: net }
      cidr: 10.200.0.0/24
      dns_nameservers: [8.8.8.8, 8.8.4.4]

  router:
    type: OS::Neutron::Router
    properties:
      external_gateway_info:
        network: { get_param: public_network }

  router_interface:
    type: OS::Neutron::RouterInterface
    properties:
      router: { get_resource: router }
      subnet: { get_resource: subnet }

  sg:
    type: OS::Neutron::SecurityGroup
    properties:
      name: jupyter-sg
      rules:
        - { direction: ingress, protocol: tcp, port_range_min: 22, port_range_max: 22, remote_ip_prefix: 0.0.0.0/0 }
        - { direction: ingress, protocol: tcp, port_range_min: 8888, port_range_max: 8888, remote_ip_prefix: 0.0.0.0/0 }
        - { direction: ingress, protocol: icmp, remote_ip_prefix: 0.0.0.0/0 }

  server:
    type: OS::Nova::Server
    properties:
      name: jupyterlab-server
      flavor: { get_param: flavor }
      key_name: { get_param: key_name }
      networks:
        - network: { get_resource: net }
      security_groups:
        - { get_resource: sg }
      block_device_mapping_v2:
        - boot_index: 0
          delete_on_termination: true
          image: { get_param: image }
          volume_size: { get_param: volume_size }
      user_data_format: RAW
      user_data: |
        #!/bin/bash
        set -e
        export DEBIAN_FRONTEND=noninteractive

        JUPYTER_PASS=$(openssl rand -hex 12)

        apt-get update -y
        apt-get install -y python3 python3-pip python3-venv

        # Create dedicated user and venv
        useradd -m -s /bin/bash jupyter
        su - jupyter -c "python3 -m venv /home/jupyter/venv"
        su - jupyter -c "/home/jupyter/venv/bin/pip install --upgrade pip"
        su - jupyter -c "/home/jupyter/venv/bin/pip install jupyterlab numpy pandas scikit-learn matplotlib seaborn transformers torch --extra-index-url https://download.pytorch.org/whl/cpu"

        # Generate hashed password
        HASH=$(su - jupyter -c "/home/jupyter/venv/bin/python3 -c \"from jupyter_server.auth import passwd; print(passwd('${JUPYTER_PASS}'))\"")

        # JupyterLab config
        mkdir -p /home/jupyter/.jupyter
        cat > /home/jupyter/.jupyter/jupyter_lab_config.py <<JCFG
        c.ServerApp.ip = '0.0.0.0'
        c.ServerApp.port = 8888
        c.ServerApp.open_browser = False
        c.ServerApp.password = '${HASH}'
        c.ServerApp.allow_remote_access = True
        JCFG
        chown -R jupyter:jupyter /home/jupyter/.jupyter

        # Systemd service
        cat > /etc/systemd/system/jupyterlab.service <<SVC
        [Unit]
        Description=JupyterLab
        After=network.target

        [Service]
        User=jupyter
        WorkingDirectory=/home/jupyter
        ExecStart=/home/jupyter/venv/bin/jupyter lab --config=/home/jupyter/.jupyter/jupyter_lab_config.py
        Restart=always

        [Install]
        WantedBy=multi-user.target
        SVC

        systemctl daemon-reload
        systemctl enable jupyterlab && systemctl start jupyterlab

        cat > /root/.jupyter_credentials <<EOF
        JupyterLab Password: ${JUPYTER_PASS}
        URL: http://<FLOATING_IP>:8888
        EOF
        chmod 600 /root/.jupyter_credentials

  fip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: { get_param: public_network }

  fip_assoc:
    type: OS::Neutron::FloatingIPAssociation
    properties:
      floatingip_id: { get_resource: fip }
      port_id: { get_attr: [server, addresses, { get_resource: net }, 0, port] }

outputs:
  jupyterlab_url:
    description: JupyterLab URL
    value:
      str_replace:
        template: http://HOST:8888
        params:
          HOST: { get_attr: [fip, floating_ip_address] }
  floating_ip:
    description: Public IP
    value: { get_attr: [fip, floating_ip_address] }
  credentials_note:
    description: JupyterLab password location
    value: "SSH into server and run: cat /root/.jupyter_credentials"
```

#### Access:

* JupyterLab: <http://floating-ip:8888>
* SSH: ssh ubuntu\@floating-ip
* Password: `sudo cat /root/.jupyter_credentials`

#### Deploy:

1. Go to [Orchestration](/neevcloud-products/orchestration-infrastructure-as-code/web-server-stack-template.md)
2. Upload jupyterlab.yaml
3. Select keypair, flavor, image
4. Launch stack
5. Open `http://floating-ip:8888` and enter the password from credentials file

{% hint style="info" %}
**Note:** First boot takes 5–8 minutes for pip packages to install. If port 8888 is not responding, wait and retry.
{% endhint %}

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.neevcloud.com/neevcloud-guide/stack-automation-library/development-and-tools/jupyterlab-workspace.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
