资讯动态

Linux服务器上稳定后台运行JupyterLab:nohup、tmux与systemd全攻略

发布时间:2026/10/4 17:05:59 来源:尧图企业网站定制
你有没有过这样的经历自己电脑上开着 Jupyter Notebook 跑一个深度学习训练任务笔记本风扇呼呼转了一下午刚合上盖带出门回来发现内核早就断了中间结果全部作废。数据一大光是把训练集传到本地就够折腾更别说内存动不动爆红。后来我干脆把 Jupyter 整套环境放到 Linux 服务器上让它自己在后台跑。这个迁移解决了我的大问题代码和数据都放在服务器上浏览器随时能访问笔记本合盖、断电、换网络都不影响正在跑的进程。这篇文章就围绕如何在 Linux 服务器上稳定后台运行 Jupyter Notebook / JupyterLab这件事把我实际用下来最顺手的一套安装、配置、启动、远程访问和排错方法完整写一遍。无论你是想搭个人实验环境还是要在团队服务器上提供多人开发入口都可以直接照着操作。1. 先把方案想清楚服务器跑 Jupyter 的正确姿势1.1 为什么要把 Jupyter 搬到服务器上我接触过的不少朋友一开始是在自己电脑上装 Anaconda 然后跑 Jupyter数据量和模型小的时候确实方便。但一旦进入真实项目阶段问题会接二连三冒出来第一算力不够尤其跑大模型、处理 CSV 几十 GB 的时候笔记本内存直接打满风扇声音大得像要起飞第二断电、休眠、合盖都会杀掉正在执行的 kernel跑了一半的训练说没就没又得从头来第三数据分散今天在台式机写明天想用笔记本看结果文件同步来同步去版本还容易乱。放到 Linux 服务器上这些问题基本都消失了。服务器 7x24 小时开机你可以随时通过浏览器访问 Jupyter 界面计算资源集中内存、CPU、GPU 都好规划多人协作时各自建目录共用同一套数据和环境关键是你把 SSH 会话一断Jupyter 还在后台活着。整个过程里后台运行这四个字是核心中的核心。很多人第一步就栽在这里直接在终端敲jupyter lab看着能跑一关 SSH 窗口服务就没了。所以方案选型要从一开始就定清楚。1.2 后台运行的三种方式怎么选在 Linux 下让一个程序脱离终端持续运行最常见的手段是这三种方案原理优点缺点适合场景nohup让进程忽略挂断信号SIGHUP配合放后台命令简单、零依赖、一条命令搞定无法重新接回交互界面日志管理糙进程意外退出没人管临时任务、快速验证、一次性脚本tmux终端复用器程序跑在 tmux 会话里可随时 attach/detach能重新回到交互终端适合调试多窗口管理方便需要安装 tmux如果服务器重启会话不会自动恢复日常开发、需要反复查看输出、同时跑多个任务的场景systemd由系统初始化进程托管服务做成 systemd unit开机自启、崩溃自动拉起、统一日志、支持资源限制配置稍复杂需要 root 权限脱离交互式终端调试不够直观生产环境、长期对外服务、团队共用入口我个人的建议很直接如果你只是临时在服务器上跑个数据分析nohup足够了如果你要长期维护一个开发环境别偷懒直接用 systemd 把它变成系统服务。tmux 则适合夹在中间的场景——想保留交互界面又不想用系统服务管理时tmux 是最好用的。后面我会把三种方式的具体操作都写出来你自己按需求抄作业就行。1.3 访问方式也要提前定直接开端口还是走 SSH 隧道后台运行只是第一步接下来你要考虑的是我怎么访问它。这条路径其实有两个方向。方向一直接把 Jupyter 的端口对外暴露比如监听0.0.0.0:8888然后通过http://服务器IP:8888访问。好处是浏览器随便开、手机也能连、团队同事也能用,坏处是服务器暴露在公网扫描器的视野里必须配置强密码和 HTTPS否则风险很高。方向二只让 Jupyter 监听127.0.0.1访问时通过 SSH 隧道把本地端口映射到服务器的 8888 端口。这种方式完全不开放新端口到公网数据走 SSH 加密传输安全性最好缺点是对非技术同事不太友好每个人都要会一点 SSH 命令。除此之外还有第三种进阶玩法用 Nginx 做反向代理把 Jupyter 挂到域名/jupyter路径下外面走 HTTPS背后代理到本机 8888。这个适合团队统一入口稍后我也会给出关键配置。先把访问模式定下来后面安装配置时就不会来回改。2. 环境准备从零到能跑通 Jupyter2.1 装一个干净可用的 Python 环境大多数 Linux 发行版自带的系统 Python 都比较保守版本老不说直接pip install还经常碰到系统保护限制。我的建议是装 Miniconda用独立环境跑 Jupyter这样 Python 版本、依赖包都自己控制不会污染系统环境也不会被别人误改掉。下载安装 Miniconda 的命令如下wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda3-b表示静默安装-p指定安装路径。装在/opt下适合多用户共用这台服务器如果你只是个人使用也可以不指定路径直接装在~/miniconda3。装完之后初始化一下/opt/miniconda3/bin/conda init然后新建一个专门跑 Jupyter 的环境避免和别的项目打架conda create -n jupyter python3.10 -y conda activate jupyter这里我选 Python 3.10兼容性很好不管是新版 JupyterLab 还是主流深度学习框架都能覆盖。如果你有特殊需求要 3.11 或 3.12 也没问题把版本号换掉即可。2.2 安装 Jupyter Notebook 和 JupyterLab环境激活后直接用 pip 安装是最省事的。JupyterLab 是 Notebook 的新一代界面功能更全我建议两个都装着不冲突pip install jupyterlab notebook -i https://pypi.tuna.tsinghua.edu.cn/simple国内服务器用清华 PyPI 镜像速度会快很多。装完验证一下版本jupyter lab --version jupyter notebook --version这里有个容易混淆的点Notebook 7 之后jupyter notebook命令仍然是兼容的但底层的架构已经和旧版不一样了很多老配置文件里的NotebookApp不再生效要改成ServerApp。如果你在网上搜到老的教程看到c.NotebookApp.ip这种写法要注意它只对旧版起作用新版请用c.ServerApp.ip。我下面给的配置都以新版为准。2.3 生成配置文件并设置密码安装完后的第一件事不是急着启动而是先初始化配置文件和密码。很多人第一次跑 Jupyter 会看到一堆 token 输出还得复制到浏览器里非常麻烦。我现在都是先设置一个强密码一劳永逸。# 生成主配置文件 jupyter lab --generate-config # 交互式设置密码 jupyter server passwordjupyter server password会提示你输入两次密码然后自动把加密后的密码写入~/.jupyter/jupyter_server_config.json。这个文件内容大概长这样{ IdentityProvider: { token: ... }, ServerApp: { password: argon2:$argon2id$v19$m65536,t3,p4$... } }之后使用密码登录就不需要再复制 token 了。生成的主配置文件在~/.jupyter/jupyter_lab_config.py里面全是注释模板真正需要手工改的核心配置我用下面这几个就足够c.ServerApp.ip 0.0.0.0 c.ServerApp.port 8888 c.ServerApp.open_browser False c.ServerApp.password argon2:$argon2id$v19$m65536,t3,p4$... c.ServerApp.root_dir /data/workspace c.ServerApp.allow_root False说明一下各字段的作用ip是监听的地址0.0.0.0表示接受所有网卡上的连接port是服务端口默认 8888 可以换open_browser必须设为 False因为服务器上根本没有浏览器可弹root_dir是 Jupyter 打开后默认的工作目录建议单独建一个数据目录allow_root保持 False除非你确实需要用 root 用户来跑强烈不建议。如果你走 SSH 隧道访问ip应该改成127.0.0.1这个我们在第 4 部分细说。3. 核心实操三种后台运行方式手把手复现3.1 最快速的 nohup 启动先看临时场景怎么用。假设你已经配置好了现在想在后台把 JupyterLab 拉起来最简单的是这样cd /data/workspace nohup /opt/miniconda3/envs/jupyter/bin/jupyter-lab \ --config/home/jupyter/.jupyter/jupyter_lab_config.py \ /data/logs/jupyter.log 21 echo $! /data/logs/jupyter.pid拆解一下nohup让进程忽略 SIGHUP 信号也就是即使终端关闭它也不会被挂断是把命令放到后台执行 /data/logs/jupyter.log 21把标准输出和标准错误都写进同一个日志文件echo $!是记录刚启动的后台进程 PID方便之后查看或 kill。验证是否启动成功cat /data/logs/jupyter.pid ps -p $(cat /data/logs/jupyter.pid) -f tail -f /data/logs/jupyter.log看到 PID 为存活状态日志里没有报错就可以浏览器访问了。要停止服务也很简单kill $(cat /data/logs/jupyter.pid)。但说实话nohup 只适合应急。它有几个很尴尬的坑一是如果进程因异常退出没有人会自动把它拉起来二是日志文件会越来越大要注意清理三是你没法直接看到 Jupyter 终端里的交互输出想调试 kernel 得靠日志猜。所以长期使用的话我更推荐下面的 tmux 或 systemd 方案。3.2 最灵活的 tmux 后台驻留tmux 是终端复用器它可以让你在服务器上开一个虚拟终端窗口然后把 Jupyter 跑在里面。关键点是你随时可以再 attach 回这个窗口看到 Jupyter 的实时输出也能执行 CtrlC 之类的快捷键。这在调试 Jupyter 启动参数的时候比 nohup 舒服太多了。先确认有没有装# Ubuntu / Debian sudo apt install tmux # CentOS / RHEL sudo yum install tmux然后建一个专门跑 Jupyter 的会话tmux new -s jupyter进入 tmux 窗口后正常执行启动命令即可cd /data/workspace /opt/miniconda3/envs/jupyter/bin/jupyter-lab --config/home/jupyter/.jupyter/jupyter_lab_config.py看到 Jupyter 启动日志后按Ctrlb然后松开再按d就能从 tmux 会话中脱离detach而不中断里面的进程。之后你的 SSH 终端可以随意关闭Jupyter 依然活着。下次要回去看日志执行tmux attach -t jupyter如果想开多个会话比如一个跑 Jupyter一个用 htop 看负载就在 tmux 里按Ctrlb后按%左右分屏或上下分屏自由切换。查会话列表用tmux ls彻底干掉某会话用tmux kill-session -t jupyter。tmux 明显比 nohup 灵活但服务器重启后 tmux 会话不会自动恢复需要手工重新拉起。这其实也还好因为服务器真重启了里面的服务本来就该由系统层面来管了。3.3 最规范的 systemd 服务化管理如果你和我一样希望 Jupyter 像 Nginx、MySQL 一样作为系统服务存在开机自启、崩溃自动拉起那就用 systemd。它的配置看起来多一点但写完一次能舒服很久。第一步创建服务文件sudo vim /etc/systemd/system/jupyter.service写入以下内容[Unit] DescriptionJupyter Lab Service Afternetwork.target [Service] Typesimple Userjupyter Groupjupyter WorkingDirectory/data/workspace EnvironmentPATH/opt/miniconda3/envs/jupyter/bin:/usr/local/bin:/usr/bin:/bin ExecStart/opt/miniconda3/envs/jupyter/bin/jupyter-lab --config/home/jupyter/.jupyter/jupyter_lab_config.py Restartalways RestartSec10 [Install] WantedBymulti-user.target这里面有几个点值得展开说。User和Group我强烈建议指定普通用户不要用 root。Jupyter 的用户权限如果过高Web 端一旦被攻破整个服务器就裸奔了。我用的是叫jupyter的系统用户给它分配了/data/workspace目录写权限。ExecStart里我写了 Jupyter 二进制文件的绝对路径/opt/miniconda3/envs/jupyter/bin/jupyter-lab。这不是废话而是避坑systemd 启动进程时不会加载你的~/.bashrc如果你写的是裸命令jupyter-lab经常会出现找不到命令或环境变量不对的问题。最稳妥的方式就是用which jupyter-lab查一下完整路径填进去。Restartalways表示进程意外退出后自动重启间隔RestartSec10秒。这样 kernel 崩溃、内存被某些任务打爆导致 Jupyter 退出后它自己能活回来。StandardOutput和StandardError我故意没写让日志默认走 journald。这样查日志一条命令搞定sudo systemctl daemon-reload sudo systemctl enable --now jupyter sudo systemctl status jupyter journalctl -u jupyter -fenable --now表示设置开机自启并立即启动。之后你会看到类似Active: active (running)的状态。如果启动失败journalctl -u jupyter -f能立刻看到报错原因。如果确实想用文件日志也可以加这两行StandardOutputappend:/data/logs/jupyter.log StandardErrorappend:/data/logs/jupyter.log注意append:需要系统版本较新老系统用file:也可以但每次重启会重建日志文件。3.4 一份可复用的启动脚本模板为了省事我把日常启动相关的命令整理成一个简单的脚本模板适合放在/data/scripts/下配合 systemd 或 crontab 使用#!/bin/bash # 启动 Jupyter Lab (systemd 托管) systemctl enable --now jupyter # 查看状态 systemctl status jupyter --no-pager # 查看最近 50 行日志 journalctl -u jupyter -n 50 --no-pager # 跟踪日志 journalctl -u jupyter -f如果你暂时只想用 tmux 方案也可以把 tmux 启动命令写成脚本核心就是先判断有没有同名会话没有就新建#!/bin/bash SESSIONjupyter if ! tmux has-session -t $SESSION 2/dev/null; then tmux new-session -d -s $SESSION bash /data/scripts/start_jupyter.sh fi tmux attach -t $SESSION这些脚本你按自己习惯改造就好重点是搞清楚它们背后的启动逻辑而不是背命令。4. 远程访问与安全加固4.1 绑定地址与端口的选择Jupyter 的监听地址决定了谁能访问它。如果你的场景是我在公司内网用浏览器直接访问服务器 IP那就绑定0.0.0.0。如果你的场景是我只通过 SSH 隧道连过去那就绑定127.0.0.1这样外部网络根本连不到 8888 端口安全性提升一个级别。端口方面默认 8888 很容易被端口扫描器盯上。我一般会换一个高位端口比如 8899 或 18088。配置里改一下c.ServerApp.port就行。端口换了之后团队内部要提前同步不然同事仍然按老地址访问会超时。4.2 密码、Token 与 HTTPS 配置在这件事上我踩过很大一个坑最早在云服务器上部署 Jupyter 图省事密码设得简单端口也直接对外开放结果一个晚上就被扫描器爆破登录第二天上去发现服务器 CPU 狂转被人拿去挖矿了。从那以后我对 Jupyter 的安全配置格外认真。最基本的三条设强密码长度 16 位以上包含大小写、数字和符号。不要依赖 token因为 token 可能随着重启变化容易在多人场景里造成混乱。如果对外提供访问一定配 HTTPS。HTTPS 的配置也不复杂。先用 OpenSSL 生成一个自签名证书sudo mkdir -p /etc/jupyter sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/jupyter/jupyter.key \ -out /etc/jupyter/jupyter.pem然后在配置文件里加上两行c.ServerApp.certfile /etc/jupyter/jupyter.pem c.ServerApp.keyfile /etc/jupyter/jupyter.key重启服务后地址就要用https://而不是http://了。自签名证书浏览器会提示不安全个人使用点继续访问就行。如果团队多人使用正式一点的做法是给服务器域名申请免费证书再配合 Nginx 反向代理浏览器就不会报警了。4.3 局域网与公网访问的两种方案方案 A直接开放端口访问。适用于内网环境或者云服务器且你确认安全组规则可控的情况。操作上要注意三层防火墙系统层ufw或firewalld云控制台云服务器的安全组入站规则Jupyter 自身监听地址Ubuntu 用 ufwsudo ufw allow from 192.168.1.0/24 to any port 8888 proto tcpCentOS 用 firewalldsudo firewall-cmd --add-port8888/tcp --permanent sudo firewall-cmd --reload如果是云服务器还要去控制台安全组里放行同样规则。很多连不上的问题其实就是安全组没配。方案 BSSH 隧道访问。个人最推荐尤其只有你自己使用时。假设 Jupyter 在服务器上监听127.0.0.1:8888本地执行ssh -N -L 8000:127.0.0.1:8888 user服务器IP-N表示只建立隧道不登录远程 shell-L 8000:127.0.0.1:8888表示把本地的 8000 端口映射到服务器上的 127.0.0.1:8888。然后浏览器打开http://127.0.0.1:8000就会进入服务器上的 Jupyter。这样浏览器和 Jupyter 之间的数据走的是 SSH 加密通道密码也不在网络上明文传输。还有个衍生技巧如果你用 VSCode 做远程开发它自身也带端口转发功能可以不手动敲 SSH 命令。接下来细说。4.4 VSCode Remote SSH 的配合玩法VSCode 的 Remote-SSH 插件是我现在在服务器上写代码的主要入口。安装步骤很简单本机 VSCode 装好 Remote - SSH 扩展然后CtrlShiftP输入 Remote-SSH: Connect to Host填user服务器IPVSCode 就会在远端打开一个新的窗口。连上之后你相当于有了一个跑在服务器上的完整 IDE。打开服务器的/data/workspace目录新建或打开一个.ipynb文件VSCode 会提示安装 Python 和 Jupyter 扩展。然后在右上角选择 Kernel选成服务器 conda 环境里那个jupyter内核之后所有代码执行、变量查看、图表展示都发生在服务器上。体验接近本地 IDE数据不用挪来挪去。如果你想把 Jupyter 界面也搬到浏览器又不想手动开 SSH 隧道VSCode 的端口面板可以一键转发打开命令面板输入 Forward a Port输入8888VSCode 会自动在本地开一个可用端口点开就是你服务器上的 JupyterLab。这个功能底层其实就是 SSH 端口转发只是帮你省了敲命令的功夫。如果你要做 Nginx 反向代理关键是 WebSocket 头要配好否则 JupyterLab 会频繁断线location / { proxy_pass http://127.0.0.1:8888; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; }这个细节非常容易踩坑。Jupyter 的 kernel 通信依赖 WebSocket很多教程只写了proxy_pass导致页面能打开但一执行代码就掉线。5. 运维与排查日志、故障与优化5.1 日志与状态怎么查服务跑起来只是开始后面维护才是最花精力的。用 systemd 托管的好处是所有日志都集中在 journald 里。# 查看服务整体状态 systemctl status jupyter # 查看最近 100 行日志并持续跟踪 journalctl -u jupyter -n 100 -f # 查看某段时间的日志 journalctl -u jupyter --since 2025-01-01 00:00:00 # 按进程关键词过滤 journalctl -u jupyter | grep -i error进程和端口查看也不能忘# 查看 8888 端口被谁占用 lsof -i:8888 # 列出所有相关 jupyter 进程 ps -ef | grep jupyter内存和磁盘是 Jupyter 服务器最容易出问题的两处。养成习惯free -h df -h如果 kernel 内存占用过高频繁 OOM日志里能看到Killed process的痕迹这时候光重启 Jupyter 是没用的要检查是不是某个 notebook 把数据全加载进了内存。5.2 常见问题与排查技巧速查表我把这段时间遇到的典型问题整理成一个速查表照着查就行。现象可能原因处理方式浏览器访问超时页面打不开防火墙或云安全组没放行Jupyter 绑定在 127.0.0.1检查 ufw/firewalld/安全组调整 c.ServerApp.ip启动后进程几秒就消失配置语法错误、路径不存在、依赖缺失先手动运行 ExecStart 里的命令看报错再查 journalctl -u jupyter端口被占用8888 起不来其他进程占用了端口lsof -i:8888查看占用进程改端口或杀进程提示 Running as root 无法启动用 root 用户运行且 allow_root 为 False换普通用户运行或配置 c.ServerApp.allow_root True浏览器打开后要 token但不知道 token未设置密码或 token 是随机生成的jupyter server list查看jupyter server password重置密码SSH 一断开服务就没了没用 nohup/tmux/systemd进程收到 HUP 信号改用三种后台运行方式之一JupyterLab 页面能打开执行代码就断线Nginx 反向代理未配置 WebSocket Upgrade加代理头配置详见 4.4kernel 执行很慢或直接卡死内存不足或 CPU 被他人的任务占满free -h和htop查资源考虑限制单 notebook 的 cell 输出大小服务器重启后 Jupyter 没起来没设置开机自启systemctl enable jupyter除了这些问题我特别想提醒的是不要忽视浏览器缓存。改完密码、换完证书之后本地浏览器还留着旧会话经常出现明明配置没问题就是报错的情况。这时候开一个无痕窗口试一下能排除很多假故障。5.3 让服务更稳定资源限制与健康检查很多人部署完 Jupyter 之后就不管了直到某天服务挂了才发现。更稳妥的做法是给 systemd 加资源限制同时做定时健康检查。在jupyter.service的[Service]段落里可以加MemoryMax8G CPUQuota300%MemoryMax限制整个 Jupyter 进程树最多使用 8GB 内存超了会被 cgroup 杀掉并自动重启。CPUQuota300%表示最多用 3 个核。有了这两个限制就算某人写了个死循环把内存吃光也不会拖垮整台服务器上其他服务。资源限制需要系统 cgroup 支持绝大多数现代发行版都没问题。健康检查我写过一个简单的 bash 脚本配合 cron 每 5 分钟跑一次#!/bin/bash URLhttp://127.0.0.1:8888/api/status if ! curl -sf $URL /dev/null 21; then echo $(date) jupyter 未响应尝试重启 /data/logs/check.log systemctl restart jupyter fi然后加入 crontab*/5 * * * * /bin/bash /data/scripts/check_jupyter.sh这个脚本的原理很简单Jupyter 的/api/status接口如果返回成功说明服务正常一旦连续访问失败就触发 systemctl restart。这样即使 kernel 或进程偶尔出问题也能在几分钟内自愈不用你半夜爬起来手动处理。如果你在服务器集群里跑 Jupyter思路类似每台机器用 systemd 管理各自的 Jupyter 实例外层通过统一的入口或负载均衡调度再配合共享存储保证每个人都能访问同一份数据。多节点环境复杂度会上去但单节点能踩的坑其实都差不多先把单机这套玩明白了再扩展也不迟。最后再分享一个我自己养成的习惯把 Jupyter 的配置文件/etc/jupyter/目录纳入版本管理或用脚本备份一份。服务器上配置改来改去时间一长很容易忘记改过什么有备份可以随时对比。我用 systemd 托管这套方案跑了大半年基本上没再为 Jupyter 的稳定性操过心。最大的体会是别图省事只开个 nohup花十分钟把 systemd 服务写好后面能省下你几十个小时的维护时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑