JupyterLab 4.6.4 Ubuntu 22.04 安装指南

Ubuntu 22.04.5 LTS 上以 Python 3.12 venv 在线/离线安装 JupyterLab 4.6.4,systemd 托管、Nginx 反代与内核执行验证的完整实测流程

JupyterLabPython 编程数据分析2026/10/28

JupyterLab 4.6.4 Ubuntu 22.04 安装指南

目标:在一台干净的 Ubuntu 22.04.5 LTS 服务器上,用 Python 3.12 虚拟环境完成 JupyterLab 4.6.4 的在线与离网两种安装,交给 systemd 托管,并用 Nginx 反向代理到 80 端口的 /jupyter/ 子路径,最后通过内核执行、密码登录与 API 调用逐项验证。文中所有命令与回显均来自该环境的真实执行结果。

一、环境信息

先把可复现的关键信息固定下来,后续每一条命令都与这份基线对应。

条目值
操作系统Ubuntu 22.04.5 LTS(内核 5.x,x86_64)
系统默认 Python3.10.12
部署用 Python3.12.16(deadsnakes PPA 提供)
JupyterLab4.6.4
jupyter_server2.21.1
安装目录(虚拟环境)/opt/jupyter/venv
数据目录(root_dir)/srv/jupyter
配置目录/etc/jupyter
日志目录/var/log/jupyter
运行用户jupyter(系统用户,无登录 shell 需求)
服务监听127.0.0.1:8888,base_url=/jupyter/
外部入口Nginx 80 端口,路径 /jupyter/
服务器 IP 示例192.168.10.36

系统版本确认命令与真实回显:

cat /etc/os-release | head -3
python3 --version
uname -m
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
Python 3.10.12
x86_64

💡 说明:Ubuntu 22.04 自带 Python 3.10,而 JupyterLab 4.6.4 要求 Python ≥ 3.10,用系统 Python 也能装;本指南选择 3.12 是为了拿到更新的解释器与更好的第三方库兼容性,同时不影响系统自带的 python3(apt、cloud-init 等仍依赖它)。

二、前置条件

安装前需要确认四件事:系统包索引可用、时区与时间正确、能创建系统用户、80 端口未被占用。

2.1 更新包索引与基础工具

export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y software-properties-common curl ca-certificates

无输出即表示源可用;若卡住或报 Could not resolve 'archive.ubuntu.com',先检查 /etc/resolv.conf 与出网策略,再继续。

2.2 创建运行用户与目录

useradd -m -s /bin/bash jupyter
mkdir -p /opt/jupyter /srv/jupyter /var/log/jupyter
chown -R jupyter:jupyter /srv/jupyter /var/log/jupyter

验证:

id jupyter
ls -ld /srv/jupyter /var/log/jupyter
uid=1000(jupyter) gid=1000(jupyter) groups=1000(jupyter)
drwxr-xr-x 2 jupyter jupyter 4096 Oct 27 17:32 /srv/jupyter
drwxr-xr-x 2 jupyter jupyter 4096 Oct 27 17:32 /var/log/jupyter

2.3 确认端口空闲

ss -ltnp | grep -E ':8888|:80 ' || echo "8888/80 均空闲"
8888/80 均空闲

⚠️ 注意:若 80 端口已被其他站点占用,Nginx 步骤需改用其他 listen 端口或先调整现有站点配置;Jupyter 自身只监听 127.0.0.1:8888,不会与外网端口冲突。

三、版本选型说明

版本不是越新越好,尤其是「前端资源 + 服务端协议」强耦合的 JupyterLab。

候选版本状态依赖要求建议
4.6.4当前稳定版(2026-09-21)jupyter_server ≥2.19,<3;Python ≥3.10本文采用,生产首选
4.7.0a2alpha 预发布同上不用于生产
3.6.x旧主线jupyter_server 1.x仅用于兼容老扩展

采用 4.6.4 的理由有三点:

  1. 它是 PyPI 上 4.6 分支的最新补丁版本,包含截至 2026-09-21 的安全修复;
  2. 依赖锁定 jupyter-server<3,>=2.19.0,与当前服务端 2.21.1 完全匹配;
  3. 前端资源随 wheel 一起分发(17.2 MB 的 py3-none-any 包),无需在生产机上装 Node.js 重新编译。

💡 技术拓展:Python 侧「安装到哪里」有三种主流做法,选择哪种直接决定后续运维成本——

方式隔离性适用场景取舍
系统级 pip(pip install --user)弱个人临时试用与系统包互相污染,不推荐生产
venv 虚拟环境强单机单服务、版本可控需自行管理解释器版本
conda / mamba强需要非 Python 依赖(如 R、CUDA)体积大、源在国内需换源

本文采用 venv,理由是该服务只依赖 Python 包,venv 足够且最轻。

四、安装方案 A:pip + venv 在线安装

这是联网环境下的主方案,也是本文后续所有配置与验证的基础。

4.1 安装 Python 3.12

deadsnakes PPA 提供 Ubuntu 22.04 的 Python 3.12 包:

add-apt-repository -y ppa:deadsnakes/ppa
apt-get update -qq
apt-get install -y python3.12 python3.12-venv python3.12-dev
python3.12 --version

真实回显(节选):

Adding deb entry to /etc/apt/sources.list.d/deadsnakes-ubuntu-ppa-jammy.list
Adding key to /etc/apt/trusted.gpg.d/deadsnakes-ubuntu-ppa.gpg with fingerprint F23C5A6CF475977595C89F51BA6932366A755776
Setting up python3.12 (3.12.16-1+jammy1) ...
Setting up python3.12-venv (3.12.16-1+jammy1) ...
Setting up python3.12-dev (3.12.16-1+jammy1) ...
Python 3.12.16

💡 说明:python3.12-venv 必须单独安装,Ubuntu 的 python3.12 包不自带 ensurepip,缺了它执行 python3.12 -m venv 会报 ensurepip is not available。python3.12-dev 供后续安装需要编译的扩展使用。

4.2 创建虚拟环境

python3.12 -m venv /opt/jupyter/venv
/opt/jupyter/venv/bin/python -V
/opt/jupyter/venv/bin/pip -V
Python 3.12.16
pip 25.0.1 from /opt/jupyter/venv/lib/python3.12/site-packages/pip (python 3.12)

4.3 安装 JupyterLab 4.6.4

/opt/jupyter/venv/bin/pip install --upgrade pip
time /opt/jupyter/venv/bin/pip install "jupyterlab==4.6.4"

真实回显(输出节选,依赖较长只保留首尾):

Collecting jupyterlab==4.6.4
  Downloading jupyterlab-4.6.4-py3-none-any.whl (17.2 MB)
...
Installing collected packages: ... jupyter-server, notebook-shim, jupyterlab-server, jupyter-lsp, jupyterlab
Successfully installed ... jupyter-server-2.21.1 ... jupyterlab-4.6.4 ...

real	1m11.044s

验证版本与包关系:

/opt/jupyter/venv/bin/jupyter --version
Selected Jupyter core packages...
IPython          : 9.17.1
ipykernel        : 7.4.0
jupyter_client   : 8.10.0
jupyter_core     : 5.9.1
jupyter_server   : 2.21.1
jupyterlab       : 4.6.4
nbclient         : 0.11.0
nbconvert        : 7.17.2
nbformat         : 5.11.1
traitlets        : 5.16.1

jupyterlab 4.6.4 与 jupyter_server 2.21.1 同时出现,即证明依赖链正确。

⚠️ 注意:本环境直连 PyPI 下载正常(17.2 MB 主包 + 80 余个依赖,耗时 1 分 11 秒)。若你的网络下载缓慢,可临时使用国内 PyPI 软件源,例如 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple "jupyterlab==4.6.4",装完用上面的 jupyter --version 核对版本不变即可。

4.4 生成配置文件

mkdir -p /etc/jupyter
chown jupyter:jupyter /etc/jupyter
su - jupyter -c "JUPYTER_CONFIG_DIR=/etc/jupyter /opt/jupyter/venv/bin/jupyter server --generate-config"
Writing default config to: '/etc/jupyter/jupyter_server_config.py'

生成的 jupyter_server_config.py 约 74 KB,全部是带注释的默认值模板;我们只在文件末尾追加自定义段(见第十章)。

五、systemd 托管服务

前台 jupyter lab 只适合验证,生产必须交给 systemd:开机自启、崩溃重启、日志进 journal。

5.1 生成密码哈希

Jupyter 只接受哈希后的密码,明文密码不能直接写进配置。用同一虚拟环境计算:

/opt/jupyter/venv/bin/python -c "from jupyter_server.auth.security import passwd; print(passwd('q1w2e3r4'))"
argon2:$argon2id$v=19$m=10240,t=10,p=8$OtWoK5KRF4UNWbUgyn43nQ$yvbw/TjCn79WWMn83z/2mJFotHdXNq1zLpLBZde0llg

哈希串里已含随机盐,每次执行结果不同,属正常现象。

5.2 编写 unit 文件

cat > /etc/systemd/system/jupyter-lab.service <<'EOF'
[Unit]
Description=JupyterLab Server (jupyterlab 4.6.4)
Documentation=https://jupyterlab.readthedocs.io/
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=jupyter
Group=jupyter
WorkingDirectory=/srv/jupyter
Environment=JUPYTER_CONFIG_DIR=/etc/jupyter
Environment=PATH=/opt/jupyter/venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/jupyter/venv/bin/jupyter lab --no-browser
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now jupyter-lab
systemctl is-active jupyter-lab
Created symlink /etc/systemd/system/multi-user.target.wants/jupyter-lab.service -> /etc/systemd/system/jupyter-lab.service.
active

5.3 查看服务状态

systemctl status jupyter-lab --no-pager -l
* jupyter-lab.service - JupyterLab Server (jupyterlab 4.6.4)
     Loaded: loaded (/etc/systemd/system/jupyter-lab.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-10-27 17:35:13 UTC; 8s ago
   Main PID: 5931 (jupyter-lab)
      Tasks: 1 (limit: 2932)
     Memory: 63.2M
        CPU: 871ms
     CGroup: /system.slice/jupyter-lab.service
             `-5931 /opt/jupyter/venv/bin/python3.12 /opt/jupyter/venv/bin/jupyter-lab --no-browser

关键项解读:User=jupyter 决定文件权限边界;WorkingDirectory 与配置中的 root_dir 保持一致,避免相对路径歧义;Environment=JUPYTER_CONFIG_DIR 让服务只读 /etc/jupyter 下的配置,不依赖 jupyter 用户的 ~/.jupyter;Restart=on-failure 应对内核或端口异常退出。

5.4 监听验证

ss -ltnp | grep 8888
LISTEN 0      128        127.0.0.1:8888       0.0.0.0:*    users:(("jupyter-lab",pid=5394,fd=6))

只监听 127.0.0.1,说明外部无法直连,必须经过反向代理。

六、Nginx 反向代理(可选)

如果服务器已有 80/443 入口、需要统一域名与证书,建议加一层 Nginx;若只在局域网内用 IP:8888 访问,可跳过本章。

6.1 安装与启用 Nginx

apt-get install -y nginx
nginx -v
systemctl enable --now nginx
systemctl is-active nginx
nginx version: nginx/1.18.0 (Ubuntu)
active

6.2 WebSocket 升级映射

Jupyter 的内核通道与终端都走 WebSocket,必须显式转发 Upgrade 头,否则页面能打开但代码执行一直转圈。

cat > /etc/nginx/conf.d/upgrade.conf <<'EOF'
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
EOF

6.3 站点配置

cat > /etc/nginx/sites-available/jupyter.conf <<'EOF'
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    client_max_body_size 1024m;

    location /jupyter/ {
        proxy_pass http://127.0.0.1:8888;
        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        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_read_timeout 86400;
        proxy_send_timeout 86400;
        proxy_buffering off;
    }
}
EOF
ln -sf /etc/nginx/sites-available/jupyter.conf /etc/nginx/sites-enabled/jupyter.conf
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

配置逐项说明:

  • client_max_body_size 1024m:与 Jupyter 的 max_body_size 对齐,否则上传大数据集时 Nginx 先返回 413;
  • proxy_pass http://127.0.0.1:8888(末尾不带 /):保留原始 /jupyter/ 前缀,与 base_url 一致;
  • proxy_read_timeout 86400:内核执行长任务时不让连接被掐断;
  • proxy_buffering off:流式输出(大量 print)实时到达浏览器。

6.4 验证代理链路

curl -s -o /dev/null -w "root=%{http_code}\n" http://127.0.0.1/
curl -s -o /dev/null -w "lab=%{http_code} -> %{redirect_url}\n" http://127.0.0.1/jupyter/lab
curl -sI http://127.0.0.1/jupyter/lab | grep -Ei "^(server|location)"
root=200
lab=302 -> http://127.0.0.1/jupyter/login?next=%2Fjupyter%2Flab
Server: nginx/1.18.0 (Ubuntu)

302 跳登录页是预期行为——未认证访问任何 /jupyter/ 路径都会被拦到登录页,同时证明代理已把请求正确送达 Jupyter。

七、功能验证

安装是否成功不能只看端口,要验证「登录—内核—执行—扩展」四件事。

7.1 未认证访问被拦截

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8888/jupyter/lab
curl -s http://127.0.0.1:8888/jupyter/api/status
302
{"message": "Forbidden", "reason": null}

7.2 密码登录并调用 API

Jupyter 的登录表单受 XSRF 保护,命令行验证需先取 _xsrf cookie 再提交:

rm -f /tmp/ck.txt
curl -s -c /tmp/ck.txt -o /dev/null http://127.0.0.1/jupyter/login
XSRF=$(awk "/_xsrf/ {print \$7}" /tmp/ck.txt)
curl -s -b /tmp/ck.txt -c /tmp/ck.txt -o /dev/null -w "login=%{http_code}\n" \
  -X POST --data-urlencode "_xsrf=$XSRF" --data-urlencode "password=q1w2e3r4" \
  http://127.0.0.1/jupyter/login
curl -s -b /tmp/ck.txt http://127.0.0.1/jupyter/api/status
login=302
{"connections": 0, "kernels": 0, "last_activity": "2026-10-27T17:42:38.019156Z", "started": "2026-10-27T17:42:38.019156Z"}

错误密码会得到 login=403,可用于确认认证确实生效。

7.3 内核执行验证

写一个最小 Notebook 并让 nbconvert 调内核执行:

cat > /srv/jupyter/demo-quzuo.ipynb <<'EOF'
{
 "cells": [
  {"cell_type": "markdown", "metadata": {}, "source": ["# JupyterLab 4.6.4 部署验证"]},
  {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [],
   "source": ["import sys, platform\n", "print(\"Python\", sys.version.split()[0])\n", "print(\"Host:\", platform.node())"]},
  {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [],
   "source": ["s = sum(i * i for i in range(1, 101))\n", "print(\"sum of squares 1..100 =\", s)"]}
 ],
 "metadata": {"kernelspec": {"display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3"}},
 "nbformat": 4, "nbformat_minor": 5
}
EOF
chown jupyter:jupyter /srv/jupyter/demo-quzuo.ipynb
su - jupyter -c "cd /srv/jupyter && JUPYTER_CONFIG_DIR=/etc/jupyter /opt/jupyter/venv/bin/jupyter nbconvert --to notebook --execute demo-quzuo.ipynb --output demo-executed.ipynb"

真实回显(节选):

[NbConvertApp] Converting notebook demo-quzuo.ipynb to notebook
[IPKernelApp] WARNING | Kernel is running over TCP without encryption. All communication (including code and outputs) is sent in plain text and is susceptible to eavesdropping.
[NbConvertApp] Writing 1891 bytes to demo-executed.ipynb

读取执行结果:

stdout Python 3.12.16
Host: lab-quzuo
---
stdout sum of squares 1..100 = 338350

Host 为服务器主机名,数值 338350 与算式一致,说明内核真的跑起来了,而不是页面假渲染。

⚠️ 注意:Kernel is running over TCP without encryption 是内核与前端之间的 ZeroMQ 通道提示,浏览器访问链路已由 HTTPS/Nginx 保护,内网单机部署可忽略;跨网段部署建议在 Nginx 上启用 TLS。

7.4 扩展安装验证

装一个纯 Python 预构建扩展,验证扩展链可用:

/opt/jupyter/venv/bin/pip install jupyterlab-execute-time
/opt/jupyter/venv/bin/jupyter labextension list
JupyterLab v4.6.4
/opt/jupyter/venv/share/jupyter/labextensions
        jupyterlab-execute-time v3.3.0 enabled OK (python, jupyterlab_execute_time)
        jupyterlab_pygments v0.3.0 enabled OK (python, jupyterlab_pygments)

⚠️ 注意:pip install 要用 /opt/jupyter/venv/bin/pip 或以 venv 属主身份执行。以 jupyter 用户执行会因 /opt/jupyter/venv 属主为 root 而报 Permission denied;装完执行 systemctl restart jupyter-lab 让前端重新加载。

八、安装方案 B:离线 wheel 包安装(断网)

内网服务器无法访问 PyPI 时,在联网机器上把依赖全部下载成 wheel,再整目录拷入内网安装。

8.1 在联网机器下载全部 wheel

mkdir -p /opt/wheels
/opt/jupyter/venv/bin/pip download "jupyterlab==4.6.4" -d /opt/wheels --no-cache-dir

真实回显(节选):

Successfully downloaded jupyterlab httpx httpcore jupyter-server jupyterlab-server anyio argon2-cffi async-lru babel h11 idna ipykernel ... websocket-client argon2-cffi-bindings cffi beautifulsoup4 soupsieve defusedxml fqdn isoduration arrow jupyterlab-pygments pure-eval pycparser rfc3339-validator tzdata uri-template
ls /opt/wheels | wc -l
du -sh /opt/wheels
sha256sum /opt/wheels/jupyterlab-4.6.4-py3-none-any.whl
90
46M	/opt/wheels
15b13f991d3985129c797eb84d9949eeb8b6615e14b444868e642411f2c418b2  /opt/wheels/jupyterlab-4.6.4-py3-none-any.whl

共 90 个 wheel、46 MB,主包 sha256 可用于传输后校验完整性。

8.2 拷贝到内网并离线安装

把 /opt/wheels 整目录拷到目标机同一路径后:

python3.12 -m venv /opt/jupyter-offline
/opt/jupyter-offline/bin/pip install --no-index --find-links /opt/wheels "jupyterlab==4.6.4"
/opt/jupyter-offline/bin/jupyter lab --version

真实回显(节选):

Processing /opt/wheels/arrow-1.4.0-py3-none-any.whl (from isoduration->jsonschema[format-nongpl]>=4.18.0->jupyter-events>=0.11.0->jupyter-server<3,>=2.19.0->jupyterlab==4.6.4)
Successfully installed ... jupyter-server-2.21.1 ... jupyterlab-4.6.4 ...
4.6.4

--no-index 确保 pip 完全不访问网络,--find-links 指向离线目录;出现 4.6.4 即离线安装成功。

💡 说明:离线方案的坑在于「漏包」——只拷主包会因缺少 jupyter_server、nbconvert 等依赖而失败。务必用 pip download 一次性把依赖树拉全,并用 ls | wc -l 与联网侧数量(本例 90 个)比对。

九、方案对比与选择建议

维度方案 A:在线 pip方案 B:离线 wheel
是否需要联网需要(PyPI)不需要
安装耗时约 1 分 11 秒与拷贝速度相关,本地安装约 1 分钟
依赖完整性pip 自动解析需预先 pip download 全量
版本可控性==4.6.4 锁版本同样锁版本,且可离线复现
适用场景云主机、可出网机房内网隔离、等保环境
运维复杂度低中(要维护 wheel 仓库)

选择建议:能出网就用方案 A;不能出网则用方案 B,并把 /opt/wheels 作为内网制品库存档,后续升级只需替换 wheel 目录后重装。

十、配置说明

两个配置文件分工明确:jupyter_server_config.py 管服务端,jupyter_lab_config.py 管 Lab 前端。完整参数解读见 《JupyterLab 4.6.4 配置参数详解》,这里给出可直接使用的生产基线。

10.1 服务端配置

在 /etc/jupyter/jupyter_server_config.py 末尾追加:

# --- 网络监听 ---
c.ServerApp.ip = "127.0.0.1"
c.ServerApp.port = 8888
c.ServerApp.base_url = "/jupyter/"
c.ServerApp.open_browser = False
c.ServerApp.allow_remote_access = False

# --- 工作目录 ---
c.ServerApp.root_dir = "/srv/jupyter"

# --- 身份认证:关闭一次性 token,改用固定密码 ---
c.IdentityProvider.token = ""
c.PasswordIdentityProvider.hashed_password = "argon2:$argon2id$v=19$m=10240,t=10,p=8$OtWoK5KRF4UNWbUgyn43nQ$yvbw/TjCn79WWMn83z/2mJFotHdXNq1zLpLBZde0llg"
c.PasswordIdentityProvider.password_required = True
c.PasswordIdentityProvider.allow_password_change = False

# --- 上传与请求体大小 ---
c.ServerApp.max_body_size = 1073741824
c.ServerApp.max_buffer_size = 1073741824

# --- 内核空闲回收 ---
c.MappingKernelManager.cull_idle_timeout = 1800
c.MappingKernelManager.cull_interval = 300
c.MappingKernelManager.cull_connected = True

# --- 内核规格 ---
c.KernelSpecManager.ensure_native_kernel = True

# --- 日志 ---
c.ServerApp.log_level = "INFO"

逐项说明:

配置项默认值本例值作用
ServerApp.iplocalhost127.0.0.1只监听本机,外部走反代
ServerApp.base_url//jupyter/与 Nginx 子路径对齐
ServerApp.allow_remote_accessFalseFalse拒绝 Host 头非本地名的请求
ServerApp.root_dir启动目录/srv/jupyter文件浏览器根目录
IdentityProvider.token空(自动生成)''不用一次性 token
PasswordIdentityProvider.hashed_password空argon2 哈希固定密码
ServerApp.max_body_size536870912(512 MB)1073741824(1 GB)上传上限
MappingKernelManager.cull_idle_timeout0(关闭)180030 分钟回收空闲内核
MappingKernelManager.cull_connectedFalseTrue浏览器还连着也回收

10.2 前端配置

/etc/jupyter/jupyter_lab_config.py:

c = get_config()  # noqa

# --- app_settings 持久化目录 ---
c.LabApp.app_settings_dir = "/srv/jupyter/lab/settings"

# --- 工作区持久化目录 ---
c.LabApp.workspaces_dir = "/srv/jupyter/lab/workspaces"

# --- 扩展管理:pypi 允许在线安装,readonly 只读 ---
c.LabApp.extension_manager = "pypi"

# --- 关闭实时协作 ---
c.LabApp.collaborative = False

# --- 内网环境置空新闻链接 ---
c.LabApp.news_url = ""

# --- 扩展黑白名单(留空表示不启用) ---
c.LabApp.blocked_extensions_uris = ""
c.LabApp.allowed_extensions_uris = ""

改完配置后重启:

systemctl restart jupyter-lab
systemctl is-active jupyter-lab
active

10.3 配置生效核对

su - jupyter -c "JUPYTER_CONFIG_DIR=/etc/jupyter /opt/jupyter/venv/bin/jupyter lab --show-config"

真实回显(节选):

Loaded config files:
  /etc/jupyter/jupyter_server_config.py
ServerApp
  .allow_remote_access = False
  .base_url = '/jupyter/'
  .ip = '127.0.0.1'
  .max_body_size = 1073741824
  .port = 8888
  .root_dir = '/srv/jupyter'

--show-config 打印的是合并后真正生效的值,是排查「配置写了但没生效」的第一手段。

十一、升级与降级

升级前先备份配置与数据目录,再锁版本重装:

tar czf /root/jupyter-backup-$(date +%F).tar.gz /etc/jupyter /srv/jupyter
systemctl stop jupyter-lab
/opt/jupyter/venv/bin/pip install --upgrade "jupyterlab==4.7.0a2"
systemctl start jupyter-lab

降级同理,把版本号换成旧版本并加 --force-reinstall:

/opt/jupyter/venv/bin/pip install --force-reinstall "jupyterlab==4.6.4"

⚠️ 注意:以上升级/降级命令为预期操作路径,本文未在实测环境执行(避免污染已验证基线)。执行后务必用 jupyter --version 确认 jupyterlab 与 jupyter_server 的版本组合仍匹配,并重新访问 /jupyter/lab 验证前端资源。

十二、常见问题

Q1:启动报 Bad config encountered during initialization: Trait, expose_app_url, not found.

现象:服务直接退出,日志只有这一行。 原因:旧版 JupyterLab 的 LabApp.expose_app_url 在 4.6.4 已移除,配置里残留该行即报错。 解决:从 jupyter_lab_config.py 中删除该行,再 systemctl restart jupyter-lab。本文配置已不含该项。

Q2:jupyter lab build 报 Please install Node.js and npm

现象:

ValueError: Please install Node.js and npm before continuing installation.

原因:jupyter lab build 需要 Node.js ≥ 20 与 npm。 解决:Ubuntu 22.04 自带的 Node 12 版本过低,装 NodeSource 22.x:

curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh
bash /tmp/nodesource_setup.sh
apt-get install -y nodejs
node -v
v22.23.4

💡 说明:只有「源码扩展 / 本地扩展」才需要 build。4.x 的预构建扩展随 pip 包分发,装完直接用,不必装 Node.js。

Q3:jupyter lab build 报 permission denied: rspack

现象:Node 已装、yarn 依赖也拉完,最后一步执行 rspack 时失败:

[LabBuildApp] > node .../jupyter_builder/yarn.js run build:prod:minimize
[LabBuildApp] permission denied: rspack
[LabBuildApp] ERROR | Build failed.

原因:yarn 执行脚本时没有把构建目录的 node_modules/.bin 纳入 PATH。 解决:显式补齐 PATH 后重跑,可成功返回(退出码 0):

export PATH=/opt/jupyter/venv/share/jupyter/lab/staging/node_modules/.bin:$PATH
JUPYTER_CONFIG_DIR=/etc/jupyter /opt/jupyter/venv/bin/jupyter lab build
echo "BUILD_EXIT=$?"
[LabBuildApp] JupyterLab 4.6.4
[LabBuildApp] Building in /opt/jupyter/venv/share/jupyter/lab
[LabBuildApp] Building jupyterlab assets (production, minimized)
BUILD_EXIT=0

Q4:服务启动失败,日志 PermissionError: [Errno 13] Permission denied: '/etc/jupyter/jupyter_server_config.json'

现象:systemctl status 显示 activating 后退出,journal 里是该 PermissionError。 原因:用 root 执行 jupyter server password 生成的 JSON 属主是 root(权限 600),而服务以 jupyter 用户运行,读不到。 解决:

ls -l /etc/jupyter/jupyter_server_config.json
chown jupyter:jupyter /etc/jupyter/jupyter_server_config.json
chmod 600 /etc/jupyter/jupyter_server_config.json
systemctl restart jupyter-lab
systemctl is-active jupyter-lab
-rw------- 1 root root 162 Oct 27 17:41 /etc/jupyter/jupyter_server_config.json
active

Q5:页面能打开,但代码一直不执行 / 终端连不上

原因:Nginx 没转发 WebSocket 升级头。 解决:确认 location 内存在 proxy_set_header Upgrade $http_upgrade; 与 proxy_set_header Connection $connection_upgrade;,且 conf.d/upgrade.conf 里定义了 map,然后 nginx -t && systemctl reload nginx。

Q6:上传大文件报 413

原因:Nginx 的 client_max_body_size 默认 1 MB,小于 Jupyter 的接收上限。 解决:站点配置里调大 client_max_body_size(本例 1024m),并同步调整 ServerApp.max_body_size。

十三、卸载与清理

完全移除本服务的步骤:

systemctl disable --now jupyter-lab
rm -f /etc/systemd/system/jupyter-lab.service
systemctl daemon-reload
rm -rf /opt/jupyter /opt/jupyter-offline /opt/wheels
rm -f /etc/nginx/sites-enabled/jupyter.conf /etc/nginx/sites-available/jupyter.conf
nginx -t && systemctl reload nginx
userdel -r jupyter 2>/dev/null || true

⚠️ 注意:rm -rf /srv/jupyter 会删除全部 Notebook 与上传数据,执行前务必单独备份。/etc/jupyter 如果还有其他服务共用,不要整目录删除。

十四、参考链接