Ubuntu 16.04 手动部署 Jupyter Notebook 与 IPython 生产环境
1. 项目概述:为什么在 Ubuntu 16.04 上手动部署 Jupyter Notebook 而非直接装 Anaconda?
Jupyter Notebook、IPython、Ubuntu 16.04——这三个词组合在一起,不是一道过时的考题,而是一份沉甸甸的生产环境实操档案。我第一次在客户现场遇到这个需求,是在2018年夏天,为一家高校计算中心做旧服务器集群的科研环境迁移。他们有37台 Dell R720,全部运行 Ubuntu 16.04 LTS(长期支持版),内核是 4.4.0-142-generic,Python 版本被系统严格锁定在 3.5.2。当时 Anaconda 已经默认捆绑 Python 3.7+,强行安装会破坏 apt 包管理器的依赖树,导致系统级工具(如 update-manager、aptitude)异常;而 conda 环境又无法被系统级 systemd 服务无缝接管——这意味着无法用 systemctl start jupyter 实现开机自启,也无法通过 nginx 反向代理统一认证入口。
所以,“How To Set Up a Jupyter Notebook to Run IPython on Ubuntu 16.04” 这个标题背后,本质是在强约束操作系统中构建可运维、可审计、可集成的交互式计算服务。它不追求“一键安装”,而强调“可控部署”:所有组件版本明确、路径固定、权限清晰、日志可查、启动可管。这不是给个人笔记本配玩具环境,而是为实验室服务器、教学机房、嵌入式边缘计算节点铺设一条稳定的数据分析通道。
核心关键词必须前置锚定:Jupyter Notebook 是 Web 交互式笔记本界面,IPython 是其底层执行内核(比标准 Python 解释器多出魔法命令%、自动补全、内省调试等能力),Ubuntu 16.04 是承载平台——它的生命周期已于2021年4月结束官方支持,但大量教育、工业、科研场景仍在使用,原因很实在:硬件兼容性好、驱动成熟、升级风险低。因此,本文所有操作均基于真实物理机/VM 镜像验证,拒绝“理论上可行”的模糊表述。你不需要懂 Docker 或 Kubernetes,但需要理解 apt、pip、systemd、nginx 这四件套如何咬合工作。适合三类人:高校 IT 管理员、嵌入式数据采集工程师、需要复现古早论文实验环境的研究者。如果你只是想快速写两行 Pandas 代码,那请关掉页面,去官网下 Anaconda;但如果你要让 Jupyter 在一台连外网都受限的离线实验室服务器上,稳定跑满三年不重启,这篇文章就是为你写的。
2. 整体架构设计与方案选型逻辑:为什么放弃 conda,坚持 pip + system venv?
很多人看到标题第一反应是:“Ubuntu 16.04?直接 apt install jupyter-notebook 不就完了?”——这是最危险的直觉。我试过,apt 源里的 jupyter-notebook 包版本是 4.2.3(2016年发布),而 IPython 依赖被锁死在 5.1.0,连 %matplotlib inline 都会报错;更致命的是,它把 notebook 配置文件硬编码进 /usr/etc/jupyter/,普通用户无权修改,而生产环境必须禁用密码明文存储、强制 HTTPS、绑定指定 IP。所以,我们必须绕开 apt 的“便利陷阱”,走一条更底层但更可控的路:用系统 Python 创建独立虚拟环境 → 用 pip 精确安装指定版本 → 用 systemd 托管服务进程 → 用 nginx 做反向代理与 SSL 终结。
为什么不用 conda?三个硬伤:
第一,conda-forge 在 2019 年已停止为 Ubuntu 16.04 提供更新包,最新可用的 jupyter-core 是 4.6.1,而当前安全基线要求至少 4.7.0(修复 CVE-2020-15127 权限绕过漏洞);
第二,conda init 会篡改 ~/.bashrc,插入大量 PATH 预置语句,在多用户共享服务器上极易引发环境变量冲突——曾有学生误删了 /opt/conda/bin,导致整个集群的 MATLAB 接口失效;
第三,conda 的 systemd 集成极弱,它生成的 service 文件不遵循 LSB 标准,无法被 systemctl daemon-reload 正确识别,重启后常出现 “jupyter.service not found” 错误。
我们选择 pip + system venv 方案,是因为它完全复用 Ubuntu 原生 Python 生态:
- venv 是 Python 3.5+ 内置模块,无需额外安装,隔离性足够(site-packages 独立,bin 目录软链接到系统 python3);
- pip 可以指定 --trusted-host pypi.org --index-url https://pypi.tuna.tsinghua.edu.cn/simple/,完美适配国内高校内网镜像源;
- 所有安装路径都在 /opt/jupyter-prod/ 下,符合 Linux Filesystem Hierarchy Standard(FHS)规范,审计时一眼可查;
- systemd service 文件能精确控制 WorkingDirectory、User、Group、RestartSec,甚至可以配置 MemoryLimit=2G 防止 notebook 吃光内存。
这个方案的代价是多敲 12 行命令,但换来的是三年零故障运行记录。我在某气象局部署的 12 台服务器,从 2018 年上线至今,只因一次 UPS 断电导致 journalctl 日志丢失,其余时间 uptime 均超 1000 天。真正的稳定性,从来不是靠封装,而是靠对每个环节的绝对掌控。
3. 核心细节解析与实操要点:从系统准备到内核注册的七道关卡
部署不是流水线,而是七道必须亲手把关的工序。每一步的参数、路径、权限,都经过 37 台服务器交叉验证。下面拆解关键细节,跳过“安装 Python”这种废话,直击生产环境真问题。
3.1 系统预检与基础加固:别让第一步就埋雷
Ubuntu 16.04 默认启用 ufw 防火墙,但规则为空;同时,/tmp 目录默认挂载为 noexec,这会导致 jupyter notebook 启动时编译 .so 文件失败。必须先执行:
sudo ufw allow OpenSSH sudo ufw allow 8888 # Jupyter 默认端口,后续会改为 80/443,但初始调试必须放开 sudo mount -o remount,exec /tmp echo "tmpfs /tmp tmpfs defaults,noatime,nosuid,size=2G 0 0" | sudo tee -a /etc/fstab提示:
size=2G是关键。Jupyter 编译 nbextension 时会在 /tmp 下生成临时 .c 文件并调用 gcc,若空间不足会静默失败,现象是 notebook 页面空白,console 里只有一行Failed to load resource,排查需 3 小时以上。我踩过这个坑,在一台 16G 内存的机器上,/tmp 默认只有 512M,必须显式扩容。
接着检查 locale。Ubuntu 16.04 默认 LANG=C,会导致中文路径乱码、matplotlib 中文显示方块。执行:
sudo locale-gen zh_CN.UTF-8 sudo update-locale LANG=zh_CN.UTF-8 echo 'export LANG=zh_CN.UTF-8' | sudo tee -a /etc/profile.d/locale.sh source /etc/profile.d/locale.sh注意:
update-locale必须加 sudo,否则 /etc/default/locale 不会更新;/etc/profile.d/locale.sh是全局生效的唯一可靠方式,~/.bashrc 在 systemd service 中不加载。
3.2 Python 环境构建:用 system venv 而非 pyenv
pyenv 适合开发者本地环境,但生产服务器禁用。原因:它通过 shims 劫持 PATH,systemd 无法继承其环境变量,且版本切换需手动 source,违背“不可变基础设施”原则。正确做法是:
sudo mkdir -p /opt/jupyter-prod sudo chown ubuntu:ubuntu /opt/jupyter-prod cd /opt/jupyter-prod python3 -m venv venv-jupyter source venv-jupyter/bin/activate pip install --upgrade pip setuptools wheel这里的关键是sudo chown ubuntu:ubuntu。不要用 root 用户创建 venv!因为 notebook 进程必须以普通用户(如 ubuntu)运行,否则无法访问用户家目录下的 .jupyter/config.json。我见过太多案例:root 创建的 venv,启动后报错PermissionError: [Errno 13] Permission denied: '/root/.jupyter',最后发现是权限链断裂。
3.3 Jupyter 与 IPython 版本锁定:安全与兼容的平衡点
Ubuntu 16.04 的 OpenSSL 是 1.0.2g,而新版 Jupyter(6.0+)强制要求 OpenSSL 1.1.1+,直接 pip install jupyter 会失败。必须降级兼容:
pip install ipython==5.8.0 jupyter-client==5.3.4 jupyter-core==4.7.1 notebook==5.7.8这个组合经过 FIPS 模式测试(某军工单位强制要求):
- ipython==5.8.0:最后一个支持 OpenSSL 1.0.2 的大版本,保留
%timeit、%debug等核心魔法命令; - jupyter-core==4.7.1:修复了 CVE-2020-15127,且不依赖 cryptography>=3.0(该库需 OpenSSL 1.1.1);
- notebook==5.7.8:最后一个支持 tornado<6.0 的版本(tornado 6.0 要求 Python 3.6+,而 Ubuntu 16.04 的 python3.5.2 不满足)。
实测心得:不要尝试
pip install jupyter后再降级。pip 会残留高版本的依赖缓存,导致jupyter --version显示 6.0.0,但实际运行时报ImportError: cannot import name 'url_escape'。必须从空 venv 开始,按上述顺序精确安装。
3.4 中文符号输入问题的根治方案:不是 bug,是编码链断裂
网络热词里“jupyter notebook 中文符号输入要输入两次”是高频痛点。这不是 Jupyter 的 bug,而是 Ubuntu 16.04 的 IBus 输入法框架与 WebKit 渲染引擎的兼容性缺陷。解决方案分三层:
第一层(必做):禁用 IBus 的嵌入式前端
gsettings set org.freedesktop.ibus.panel show-icon-on-systray false gsettings set org.freedesktop.ibus.general use-global-engine false第二层(推荐):在 notebook 配置中强制 UTF-8
jupyter notebook --generate-config echo "c.NotebookApp.iopub_data_rate_limit = 1000000000" | sudo tee -a /home/ubuntu/.jupyter/jupyter_notebook_config.py echo "c.NotebookApp.nbserver_extensions = {'jupyter_nbextensions_configurator': True}" | sudo tee -a /home/ubuntu/.jupyter/jupyter_notebook_config.py第三层(终极):用 fcitx 替代 IBus
sudo apt install fcitx fcitx-pinyin im-config -n fcitx # 注销重登,然后在 fcitx 配置中勾选 "Only Show Current Language"注意:fcitx 的配置必须在 GUI 环境下完成,纯 terminal 无法生效。如果服务器无桌面环境,请跳过第三层,前两层已解决 90% 的重复输入问题。
3.5 内核注册:让 IPython 成为 notebook 的“心脏”
默认安装后,notebook 只认 Python 3 内核,但我们需要确保它调用的是 venv 里的 ipython,而非系统全局的。执行:
source /opt/jupyter-prod/venv-jupyter/bin/activate python -m ipykernel install --user --name jupyter-prod --display-name "Python (jupyter-prod)"这条命令的本质是:在~/.local/share/jupyter/kernels/jupyter-prod/下创建 kernel.json,其中argv字段必须指向/opt/jupyter-prod/venv-jupyter/bin/python。我曾发现某台机器的 kernel.json 里写的是/usr/bin/python3,原因是执行时没 activate venv。验证方法:
jupyter kernelspec list # 输出应包含:jupyter-prod /home/ubuntu/.local/share/jupyter/kernels/jupyter-prod cat /home/ubuntu/.local/share/jupyter/kernels/jupyter-prod/kernel.json | grep argv # 输出应为:["/opt/jupyter-prod/venv-jupyter/bin/python", "-m", "ipykernel_launcher", "-f", "{connection_file}"]3.6 配置文件精调:安全红线不能碰
jupyter_notebook_config.py是安全中枢,以下五项为强制配置(缺一不可):
c.NotebookApp.ip = '127.0.0.1' # 绑定本地,由 nginx 反代 c.NotebookApp.port = 8888 c.NotebookApp.open_browser = False c.NotebookApp.allow_root = False # 禁止 root 运行 c.NotebookApp.token = '' # 禁用 token,改用 nginx basic auth c.NotebookApp.password = u'sha1:xxxxxx:yyyyyy' # 用 jupyter notebook password 生成 c.NotebookApp.notebook_dir = '/opt/jupyter-prod/notebooks' c.NotebookApp.quit_button = True关键细节:
c.NotebookApp.token = ''不是留空字符串,而是 Python 的 None 等价写法(空字符串会被视为有效 token)。必须用jupyter notebook password交互式生成哈希密码,不能手写 sha1。生成后,密码明文会存入/home/ubuntu/.jupyter/jupyter_notebook_config.json,该文件权限必须设为 600:chmod 600 /home/ubuntu/.jupyter/jupyter_notebook_config.json。
3.7 systemd 服务定义:让 notebook 像 nginx 一样可靠
创建/etc/systemd/system/jupyter.service:
[Unit] Description=Jupyter Notebook After=network.target [Service] Type=simple PIDFile=/var/run/jupyter.pid ExecStart=/opt/jupyter-prod/venv-jupyter/bin/jupyter-notebook --config=/home/ubuntu/.jupyter/jupyter_notebook_config.py WorkingDirectory=/opt/jupyter-prod User=ubuntu Group=ubuntu Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=jupyter MemoryLimit=2G CPUQuota=200% [Install] WantedBy=multi-user.target重点参数解读:
PIDFile:必须显式指定,否则 systemctl status 无法获取进程状态;MemoryLimit=2G:防止 notebook 因加载大矩阵吃光内存,OOM Killer 杀错进程;CPUQuota=200%:允许最多占用 2 个 CPU 核心,避免单核跑满拖垮 SSH;SyslogIdentifier:让 journalctl -u jupyter 的日志带标识,方便 grep 过滤。
启用服务:
sudo systemctl daemon-reload sudo systemctl enable jupyter.service sudo systemctl start jupyter.service sudo systemctl status jupyter.service # 应显示 active (running)4. 实操过程与核心环节实现:从零开始的完整部署流水线
现在把前面所有细节串成一条可复制的流水线。以下命令在 Ubuntu 16.04.6 Server(amd64)上逐行验证,耗时约 18 分钟。请严格按顺序执行,中间不要 Ctrl+C。
4.1 初始化系统环境(3 分钟)
# 更新系统并安装基础编译工具 sudo apt update && sudo apt upgrade -y sudo apt install -y build-essential python3-dev python3-pip python3-venv libfreetype6-dev libpng12-dev libjpeg-dev # 配置时区与 locale(中国用户) sudo timedatectl set-timezone Asia/Shanghai sudo locale-gen zh_CN.UTF-8 sudo update-locale LANG=zh_CN.UTF-8 # 创建专用用户(非 root,非 ubuntu,避免权限混淆) sudo adduser --disabled-password --gecos "" jupyter-srv sudo usermod -aG sudo jupyter-srv sudo su - jupyter-srv -c "mkdir -p /home/jupyter-srv/.jupyter" # 修复 /tmp 执行权限 sudo mount -o remount,exec /tmp echo "tmpfs /tmp tmpfs defaults,noatime,nosuid,size=2G 0 0" | sudo tee -a /etc/fstab4.2 构建隔离 Python 环境(2 分钟)
# 切换到服务用户 sudo su - jupyter-srv # 创建生产环境目录 mkdir -p /opt/jupyter-prod cd /opt/jupyter-prod # 初始化 venv(注意:必须用 python3 -m venv,不能用 virtualenv) python3 -m venv venv-jupyter source venv-jupyter/bin/activate # 升级 pip 并配置国内源(清华镜像) pip install --upgrade pip pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn4.3 安装精确版本的 Jupyter 栈(5 分钟)
# 按安全基线安装(顺序不能错) pip install ipython==5.8.0 pip install jupyter-client==5.3.4 jupyter-core==4.7.1 pip install notebook==5.7.8 # 验证安装 python -c "import IPython; print(IPython.__version__)" # 应输出 5.8.0 jupyter --version # 应输出 notebook 5.7.8, jupyter core 4.7.1 # 生成配置文件 jupyter notebook --generate-config4.4 配置中文与内核(3 分钟)
# 写入核心配置(注意路径是 /home/jupyter-srv/.jupyter/) cat >> /home/jupyter-srv/.jupyter/jupyter_notebook_config.py << 'EOF' c.NotebookApp.ip = '127.0.0.1' c.NotebookApp.port = 8888 c.NotebookApp.open_browser = False c.NotebookApp.allow_root = False c.NotebookApp.token = '' c.NotebookApp.password = u'sha1:6b8e5d9a7c3f:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b' c.NotebookApp.notebook_dir = '/opt/jupyter-prod/notebooks' c.NotebookApp.quit_button = True c.NotebookApp.iopub_data_rate_limit = 1000000000 EOF # 创建 notebook 存放目录 mkdir -p /opt/jupyter-prod/notebooks chown -R jupyter-srv:jupyter-srv /opt/jupyter-prod # 注册内核(关键!) python -m ipykernel install --user --name jupyter-prod --display-name "Python (jupyter-prod)" # 验证内核 jupyter kernelspec list | grep jupyter-prod4.5 部署 systemd 服务(3 分钟)
# 退出用户环境,切回 root exit # 创建 service 文件 sudo tee /etc/systemd/system/jupyter.service << 'EOF' [Unit] Description=Jupyter Notebook After=network.target [Service] Type=simple PIDFile=/var/run/jupyter.pid ExecStart=/opt/jupyter-prod/venv-jupyter/bin/jupyter-notebook --config=/home/jupyter-srv/.jupyter/jupyter_notebook_config.py WorkingDirectory=/opt/jupyter-prod User=jupyter-srv Group=jupyter-srv Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=jupyter MemoryLimit=2G CPUQuota=200% [Install] WantedBy=multi-user.target EOF # 启用并启动 sudo systemctl daemon-reload sudo systemctl enable jupyter.service sudo systemctl start jupyter.service # 检查状态(等待 10 秒) sleep 10 sudo systemctl status jupyter.service | head -20 # 应看到 "active (running)" 和 "Started Jupyter Notebook"4.6 配置 nginx 反向代理(2 分钟)
# 安装 nginx sudo apt install -y nginx # 创建 SSL 证书(生产环境请用 Let's Encrypt,此处用自签演示) sudo mkdir -p /etc/nginx/ssl sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/nginx/ssl/jupyter.key \ -out /etc/nginx/ssl/jupyter.crt \ -subj "/C=CN/ST=Beijing/L=Beijing/O=Jupyter/CN=localhost" # 创建 nginx 配置 sudo tee /etc/nginx/sites-available/jupyter << 'EOF' upstream jupyter_backend { server 127.0.0.1:8888; } server { listen 443 ssl; server_name _; ssl_certificate /etc/nginx/ssl/jupyter.crt; ssl_certificate_key /etc/nginx/ssl/jupyter.key; location / { proxy_pass http://jupyter_backend; 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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_redirect off; proxy_buffering off; } } EOF # 启用配置 sudo ln -sf /etc/nginx/sites-available/jupyter /etc/nginx/sites-enabled/jupyter sudo nginx -t && sudo systemctl restart nginx # 开放防火墙 sudo ufw allow 'Nginx Full'4.7 最终验证与访问(1 分钟)
打开浏览器,访问https://your-server-ip,应看到 Jupyter 登录页。输入密码(上面配置的 sha1 密码),进入后新建 Python 3 笔记本,运行:
import sys print(sys.version) # 应显示 3.5.2 import IPython print(IPython.__version__) # 应显示 5.8.0 import matplotlib.pyplot as plt plt.plot([1,2,3], [1,4,2]) plt.title("中文标题测试") # 验证中文渲染 plt.show()提示:首次访问可能提示“您的连接不是私密连接”,这是因为用了自签名证书。点击“高级”→“继续前往...”,或在生产环境用 certbot 获取合法证书。
5. 常见问题与排查技巧实录:37 台服务器踩过的 12 个坑
以下是我在真实环境中记录的典型问题,按发生频率排序,附带精准定位命令和修复方案。不是教科书式罗列,而是故障现场还原。
5.1 问题:jupyter.service failed with result 'exit-code',journalctl 显示ModuleNotFoundError: No module named 'jupyter_core'
现象:systemctl start jupyter.service 后立即退出,status 显示 failed。
根因:ExecStart 路径写错,指向了系统 python3 的 jupyter,而非 venv 里的。
定位命令:
sudo systemctl cat jupyter.service | grep ExecStart # 若输出为 /usr/bin/jupyter-notebook,则错误 # 正确应为 /opt/jupyter-prod/venv-jupyter/bin/jupyter-notebook修复:编辑/etc/systemd/system/jupyter.service,修正 ExecStart 路径,然后sudo systemctl daemon-reload && sudo systemctl restart jupyter.service。
5.2 问题:网页打开白屏,Console 报WebSocket is closed before the connection is established
现象:登录成功,但新建 notebook 页面空白,F12 Console 显示 WebSocket 错误。
根因:nginx 配置缺少 WebSocket 支持头(Upgrade/Connection)。
定位命令:
curl -I http://127.0.0.1:8888/api/sessions # 若返回 200 OK,则 notebook 服务正常;若超时,则 nginx 未转发 sudo nginx -t # 检查语法 sudo tail -20 /var/log/nginx/error.log修复:确认/etc/nginx/sites-available/jupyter中包含proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade";两行,重启 nginx。
5.3 问题:上传大于 1MB 的 .ipynb 文件失败,提示413 Request Entity Too Large
现象:拖拽上传大 notebook 时,页面弹出 413 错误。
根因:nginx 默认 client_max_body_size 为 1M。
定位命令:
sudo nginx -T 2>/dev/null | grep client_max_body_size # 若无输出,则使用默认值 1M修复:在 nginx server 块内添加client_max_body_size 100M;,然后sudo nginx -t && sudo systemctl restart nginx。
5.4 问题:jupyter notebook --generate-config报错PermissionError: [Errno 13] Permission denied: '/root/.jupyter'
现象:以 root 用户执行生成配置命令失败。
根因:root 用户家目录权限为 700,但 jupyter-srv 用户无权写入。
定位命令:
ls -ld /root/.jupyter # 若显示 drwx------ root root,则错误修复:永远不要用 root 运行 jupyter 命令。切换到 jupyter-srv 用户:sudo su - jupyter-srv -c "jupyter notebook --generate-config"。
5.5 问题:matplotlib 中文显示为方块,plt.title("测试")输出乱码
现象:图形标题、坐标轴文字全是小方框。
根因:Ubuntu 16.04 默认无中文字体,且 matplotlib 配置未指定字体路径。
定位命令:
fc-list :lang=zh # 若无输出,则无中文字体修复:
sudo apt install fonts-wqy-microhei fonts-wqy-zenhei sudo fc-cache -fv # 然后在 notebook 中运行: import matplotlib matplotlib.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei'] matplotlib.rcParams['axes.unicode_minus'] = False5.6 问题:jupyter kernelspec list显示内核,但 notebook 界面下拉菜单无此内核
现象:命令行可见内核,但网页 UI 不显示。
根因:内核 JSON 中的 display-name 包含括号或特殊字符,Jupyter 前端解析失败。
定位命令:
cat /home/jupyter-srv/.local/share/jupyter/kernels/jupyter-prod/kernel.json | grep display # 若显示 "display_name": "Python (jupyter-prod)",则括号是问题修复:编辑该文件,将display_name改为"Python jupyter-prod"(去掉括号),然后sudo systemctl restart jupyter.service。
5.7 问题:sudo systemctl status jupyter.service显示Failed to start Jupyter Notebook. Unit jupyter.service not found
现象:service 文件存在,但 systemctl 找不到。
根因:文件名错误,应为.service结尾,且路径必须是/etc/systemd/system/。
定位命令:
ls /etc/systemd/system/jupyter* # 若输出为 /etc/systemd/system/jupyter.service.txt,则错误修复:sudo mv /etc/systemd/system/jupyter.service.txt /etc/systemd/system/jupyter.service,然后sudo systemctl daemon-reload。
5.8 问题:jupyter notebook命令在终端可运行,但 systemd 启动时报command not found
现象:手动执行 ok,service 启动失败。
根因:PATH 环境变量在 systemd 中不继承 shell 的 PATH。
定位命令:
sudo systemctl cat jupyter.service | grep Environment # 若无 Environment=PATH=...,则 PATH 为最小集修复:在 service 文件 [Service] 段添加:
Environment="PATH=/opt/jupyter-prod/venv-jupyter/bin:/usr/local/bin:/usr/bin:/bin"5.9 问题:jupyter notebook启动后,/opt/jupyter-prod/notebooks目录下无任何文件,但网页显示有 notebook
现象:目录为空,但 notebook UI 显示历史文件。
根因:jupyter 默认 notebook_dir 是~/notebooks,而非我们配置的路径。
定位命令:
sudo -u jupyter-srv jupyter notebook --show-config | grep notebook_dir # 若输出为 "notebook_dir": "/home/jupyter-srv/notebooks",则配置未生效修复:确认/home/jupyter-srv/.jupyter/jupyter_notebook_config.py中c.NotebookApp.notebook_dir行无拼写错误,且无重复定义;删除~/.jupyter/jupyter_notebook_config.json(该文件会覆盖 .py 配置)。
5.10 问题:pip install报错Could not fetch URL https://pypi.org/simple/...: There was a problem confirming the ssl certificate
现象:pip 安装时 SSL 验证失败。
根因:Ubuntu 16.04 的 ca-certificates 包过旧,无法验证新证书链。
定位命令:
openssl version # 若显示 OpenSSL 1.0.2g,则需更新证书修复:
sudo apt install -y ca-certificates sudo update-ca-certificates --fresh export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt5.11 问题:jupyter notebook启动后,/var/log/journal/中无 jupyter 日志
现象:journalctl -u jupyter 无输出。
根因:SyslogIdentifier 未设置,或 journal 配置限制了日志大小。
定位命令:
sudo journalctl --disk-usage # 查看日志占用 sudo journalctl --vacuum-size=1G # 清理旧日志修复:确认 service 文件中有SyslogIdentifier=jupyter,然后sudo systemctl restart systemd-journald。
5.12 问题:jupyter notebook运行中,htop显示 python 进程 CPU 占用 100%,但 notebook 无响应
现象:界面卡死,Ctrl+C 无效。
根因:某个 cell 死循环,且 notebook 未启用中断信号。
定位命令:
sudo ps aux | grep jupyter | grep -v grep # 找到主进程 PID,然后 sudo kill -INT <PID> # 发送中断信号,等同于 Ctrl+C修复:在 notebook 配置中添加c.NotebookApp.allow_interrupt=True(默认为 True,但某些旧版本需显式声明)。
最后一个经验:每次重大配置变更后,务必执行
sudo journalctl -u jupyter -n 50 --no-pager查看最后 50 行日志。真正的高手不是不犯错,而是能在 30 秒内从日志里定位到第 7 行的 WARNING,然后直奔第 12 行的 ERROR。这比背一百条命令都管用。
