JupyterLab es el entorno web de Jupyter para trabajar con notebooks, terminales y archivos desde el navegador, muy usado en ciencia de datos y machine learning. Ejecutarlo en un servidor remoto te permite aprovechar su CPU, su memoria o su GPU desde cualquier equipo. En este tutorial instalarás JupyterLab en Ubuntu 24.04 dentro de un entorno virtual, lo protegerás con contraseña, lo ejecutarás como servicio de systemd y lo publicarás con Nginx y un certificado de Let's Encrypt.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios sudo. En esta guía el usuario se llama your_user.
  • Un dominio o subdominio con un registro DNS A apuntando a la IP del servidor. Los ejemplos usan jupyter.your_domain.
  • UFW activo con el acceso SSH permitido.

Paso 1: Instalar JupyterLab en un entorno virtual

Ubuntu 24.04 no permite instalar paquetes con pip en el Python del sistema (PEP 668), y además es buena práctica aislar Jupyter en su propio entorno. Instala las herramientas para crear entornos virtuales:

sudo apt update
sudo apt install python3-venv python3-pip

Crea el entorno en tu directorio personal e instala JupyterLab:

python3 -m venv ~/jupyter/venv
~/jupyter/venv/bin/pip install --upgrade pip
~/jupyter/venv/bin/pip install jupyterlab

Comprueba la versión instalada:

~/jupyter/venv/bin/jupyter lab --version
4.4.9

Crea también el directorio donde guardarás los notebooks:

mkdir -p ~/notebooks

Paso 2: Configurar la contraseña y el servidor

Por defecto Jupyter genera un token aleatorio en cada arranque. Para un servidor permanente es más práctico usar una contraseña. El siguiente comando la pide dos veces y guarda su hash en ~/.jupyter/jupyter_server_config.json:

~/jupyter/venv/bin/jupyter server password
Enter password:
Verify password:
[JupyterPasswordApp] Wrote hashed password to /home/your_user/.jupyter/jupyter_server_config.json

Genera el archivo de configuración del servidor:

~/jupyter/venv/bin/jupyter server --generate-config

El comando crea ~/.jupyter/jupyter_server_config.py con todas las opciones comentadas. Ábrelo:

nano ~/.jupyter/jupyter_server_config.py

Añade al final estas líneas, sustituyendo your_user:

c.ServerApp.ip = "127.0.0.1"
c.ServerApp.port = 8888
c.ServerApp.open_browser = False
c.ServerApp.root_dir = "/home/your_user/notebooks"
c.ServerApp.trust_xheaders = True

Qué hace cada opción:

  • ip = "127.0.0.1": Jupyter solo escucha en local. El acceso desde fuera llegará siempre a través de Nginx, con HTTPS.
  • root_dir: el directorio que se muestra en el explorador de archivos de JupyterLab.
  • trust_xheaders: hace que Jupyter use las cabeceras X-Forwarded-* de Nginx para conocer la IP real del cliente y el esquema https.

Prueba el servidor en primer plano:

~/jupyter/venv/bin/jupyter lab
[I 2026-09-25 11:20:04.311 ServerApp] Jupyter Server 2.17.0 is running at:
[I 2026-09-25 11:20:04.311 ServerApp] http://127.0.0.1:8888/lab

Si ves esas líneas, detén el servidor con Ctrl+C y confirma con y.

Paso 3: Ejecutar JupyterLab como servicio de systemd

Un servicio de systemd arranca Jupyter con el sistema, lo reinicia si falla y centraliza sus logs en el journal. Crea la unidad:

sudo nano /etc/systemd/system/jupyter.service
[Unit]
Description=JupyterLab
After=network.target

[Service]
Type=simple
User=your_user
Group=your_user
WorkingDirectory=/home/your_user/notebooks
ExecStart=/home/your_user/jupyter/venv/bin/jupyter lab
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Al definir User=, systemd establece HOME=/home/your_user, así que Jupyter lee la configuración de ~/.jupyter sin más ajustes. Activa e inicia el servicio:

sudo systemctl daemon-reload
sudo systemctl enable --now jupyter
systemctl status jupyter --no-pager
● jupyter.service - JupyterLab
     Loaded: loaded (/etc/systemd/system/jupyter.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-09-25 11:23:40 UTC; 4s ago

Comprueba que responde en local:

curl -sI http://127.0.0.1:8888/lab | head -n 1
HTTP/1.1 302 Found

La redirección 302 hacia la página de login es la respuesta esperada. Para ver los logs, usa sudo journalctl -u jupyter -f.

Paso 4: Configurar Nginx como proxy inverso

Nginx recibirá las conexiones HTTPS y las reenviará a Jupyter. JupyterLab usa WebSockets para comunicarse con los kernels, así que el proxy debe reenviar las cabeceras Upgrade y Connection.

Instala Nginx y abre los puertos HTTP y HTTPS en el firewall:

sudo apt install nginx
sudo ufw allow 'Nginx Full'

Crea el archivo del sitio:

sudo nano /etc/nginx/sites-available/jupyter
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name jupyter.your_domain;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8888;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 1d;
    }
}

El bloque map envía Connection: upgrade solo cuando el cliente pide un WebSocket. proxy_read_timeout 1d evita que Nginx corte las conexiones de kernels que están un rato sin tráfico, y client_max_body_size permite subir archivos de hasta 100 MB desde el navegador.

Activa el sitio, comprueba la sintaxis y recarga Nginx:

sudo ln -s /etc/nginx/sites-available/jupyter /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Paso 5: Activar HTTPS con Let's Encrypt

Instala Certbot con su plugin de Nginx y solicita el certificado. Certbot añade la configuración TLS al bloque server y una redirección de HTTP a HTTPS:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d jupyter.your_domain --redirect
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/jupyter.your_domain/fullchain.pem
...
Successfully deployed certificate for jupyter.your_domain to /etc/nginx/sites-enabled/jupyter
Congratulations! You have successfully enabled HTTPS on https://jupyter.your_domain

El paquete de Ubuntu instala un timer de systemd que renueva el certificado automáticamente. Comprueba que la renovación funcionará:

sudo certbot renew --dry-run

Abre https://jupyter.your_domain en el navegador. Verás la pantalla de login de Jupyter; introduce la contraseña del paso 2. Crea un notebook con el kernel Python 3 y ejecuta una celda como import sys; sys.version para comprobar que el kernel responde a través del proxy.

Paso 6: Añadir kernels de otros entornos virtuales

El kernel por defecto usa el entorno virtual de Jupyter. Para trabajar con proyectos que tienen sus propias dependencias, crea un entorno por proyecto y regístralo como kernel, sin instalar Jupyter en él. Solo necesita ipykernel:

python3 -m venv ~/venvs/analisis
~/venvs/analisis/bin/pip install ipykernel pandas matplotlib
~/venvs/analisis/bin/python -m ipykernel install --user --name analisis --display-name "Python (analisis)"

Lista los kernels disponibles:

~/jupyter/venv/bin/jupyter kernelspec list
Available kernels:
  analisis    /home/your_user/.local/share/jupyter/kernels/analisis
  python3     /home/your_user/jupyter/venv/share/jupyter/kernels/python3

Recarga JupyterLab en el navegador y el nuevo kernel aparecerá en el lanzador. Para eliminar un kernel que ya no usas, ejecuta ~/jupyter/venv/bin/jupyter kernelspec remove analisis.

Para instalar paquetes desde un notebook, usa %pip install nombre_paquete en una celda: instala en el entorno del kernel activo, no en el de Jupyter.

Alternativa: acceso solo por túnel SSH

Si eres el único usuario y no quieres exponer Jupyter en internet, puedes saltarte los pasos 4 y 5. Como Jupyter escucha en 127.0.0.1, crea un túnel SSH desde tu equipo local:

ssh -N -L 8888:127.0.0.1:8888 your_user@your_server_ip

Mientras el comando esté en ejecución, abre http://localhost:8888 en tu navegador local. El tráfico viaja cifrado dentro de la conexión SSH.

Solución de problemas

El servicio no arranca. Revisa sudo journalctl -u jupyter -n 50 --no-pager. Los errores habituales son una ruta incorrecta en ExecStart, un User= que no coincide con el propietario de ~/jupyter, o que root_dir apunta a un directorio que no existe.

502 Bad Gateway en el navegador. Nginx no puede conectar con Jupyter. Comprueba que el servicio está activo y que curl -I http://127.0.0.1:8888/lab responde en el servidor.

La página carga pero el kernel se queda en "Connecting" o "Disconnected". Los WebSockets no pasan por el proxy. Verifica que la configuración de Nginx incluye proxy_http_version 1.1 y las cabeceras Upgrade y Connection, y revisa /var/log/nginx/error.log.

Blocking Cross Origin API request o errores 403 al abrir notebooks. La cabecera Host no llega a Jupyter. Asegúrate de que el bloque location contiene proxy_set_header Host $host;.

Olvidaste la contraseña. Ejecuta de nuevo ~/jupyter/venv/bin/jupyter server password y reinicia el servicio con sudo systemctl restart jupyter.

Conclusión

JupyterLab está funcionando como servicio en tu servidor Ubuntu 24.04, protegido con contraseña, accesible por HTTPS a través de Nginx y con kernels separados por proyecto. Como siguientes pasos, puedes instalar los drivers de NVIDIA y PyTorch en un kernel dedicado para usar la GPU desde los notebooks, añadir la extensión jupyterlab-git para versionar tu trabajo, o pasar a JupyterHub si varias personas necesitan su propio entorno en el mismo servidor.