Jupyter Lab局域网访问配置:从原理到企业级安全部署
1. 为什么默认的 Jupyter Lab 根本不让你从隔壁工位连上你兴冲冲地在自己笔记本上敲完jupyter lab浏览器里 localhost:8888 一切正常代码跑得飞起。转头想让坐在你斜后方的同事也看看这个酷炫的可视化分析结果——你把本机 IP 地址比如192.168.1.105发过去他浏览器一输页面卡住、超时、或者直接弹出“拒绝连接”。你心里一咯噔这不就是个本地服务吗局域网访问难道不是开箱即用不是。Jupyter Lab 默认启动时只监听127.0.0.1也就是 localhost这个回环地址。它压根没打算跟局域网里的其他设备说一句话。你可以把它想象成一个只认自家门牌号的快递员你家地址是127.0.0.1:8888他准时把包裹送到但隔壁老王家地址是192.168.1.105他连看都不看一眼因为他的派送清单里根本没录入这个地址。这就是所有问题的起点。网上流传的“加个--ip0.0.0.0就行了”这种说法就像告诉你“把快递员的派送范围改成‘全世界’”听起来很爽但实际操作中你会立刻撞上三堵墙防火墙拦截、认证缺失、端口冲突。我第一次配置时在公司内网折腾了整整一个下午反复重启服务、检查 IP、重装 Jupyter最后发现根本不是命令写错了而是 Windows 防火墙默默把 8888 端口当成了可疑流量给拦了——连错误提示都不给你一个就安静地丢包。更麻烦的是--ip0.0.0.0这个参数本身是临时的、一次性的。你今天加了明天重启终端就得再敲一遍如果项目要长期运行或者需要别人随时能连靠命令行参数无异于每天手动给门锁换密码。真正的配置必须落到文件里让它成为服务的一部分而不是一个随风而逝的临时指令。所以这篇指南不讲“怎么快速试一下”而是带你走完一条可复现、可维护、可交付的完整路径从理解每个配置项背后的网络原理到亲手生成安全的登录凭证再到绕过企业级防火墙的实操技巧最后落地为一份能直接交给运维同事审核的配置清单。这不是一个“能用就行”的小技巧而是一套你在任何 Linux/macOS/Windows 环境下面对任何 IT 策略都能稳稳落地的工程化方案。2. 配置文件生成与核心参数详解别再手敲--ip0.0.0.0了很多人以为配置 Jupyter Lab 局域网访问就是启动时加几个命令行参数。这就像修车时只拧紧螺丝却不检查底盘——表面看着没问题但一上路就出事。真正可靠的配置必须写进 Jupyter 的配置文件里。这个文件叫jupyter_lab_config.py它才是 Jupyter Lab 的“操作系统设置”。2.1 生成配置文件的正确姿势别去网上搜什么“手动创建空文件”那是在给自己埋雷。Jupyter 自带一个安全、标准的生成命令jupyter lab --generate-config执行这条命令后它会在你的用户目录下自动生成一个完整的、带大量注释的配置模板。在 macOS/Linux 上路径通常是~/.jupyter/jupyter_lab_config.py在 Windows 上则是C:\Users\你的用户名\.jupyter\jupyter_lab_config.py。提示如果你之前手动创建过这个文件或者用过jupyter notebook --generate-config请务必确认你编辑的是jupyter_lab_config.py而不是jupyter_notebook_config.py。这两个文件虽然结构相似但 Jupyter Lab只读取前者。我见过太多人改了半天notebook_config.py结果 Lab 完全不认账白白浪费两小时。2.2 必须修改的三大核心参数及其底层逻辑打开刚生成的jupyter_lab_config.py你会看到上千行注释。我们只聚焦最关键的三行它们决定了服务能否被局域网看见、能否被安全访问、以及是否会被系统“误杀”。2.2.1c.ServerApp.ip 0.0.0.0监听所有网络接口的真相这是最常被误解的一行。0.0.0.0并不是“任意IP”它的准确含义是“监听本机所有可用的网络接口”。你的电脑可能有多个网卡一个连 Wi-Fi192.168.1.105一个连有线10.0.0.20甚至还有一个虚拟机网卡192.168.56.1。0.0.0.0告诉 Jupyter“别挑了所有这些地址你都给我监听。”但这里有个关键陷阱0.0.0.0不等于*或通配符。它不会监听 IPv6 地址也不会监听 Docker 容器内部的特殊网络。如果你的环境涉及容器化部署比如用docker run -p 8888:8888 jupyter/scipy-notebook那么0.0.0.0在容器内部生效但宿主机的防火墙规则依然需要单独放行。2.2.2c.ServerApp.port 8888端口选择的实战权衡8888 是默认端口但它绝非唯一选择。在真实企业环境中我强烈建议你主动更换端口原因有二避免端口冲突很多开发工具如 VS Code 的 Remote-SSH 插件、某些数据库 GUI默认也占 8888。当你和同事同时启动 Lab第二个人会收到OSError: [Errno 48] Address already in use。规避企业级端口白名单策略大型公司的网络出口防火墙往往只开放 80/443/22 等少数端口。虽然局域网访问不经过出口但有些 IT 部门会统一禁用“非标准端口”8888 就是重点关照对象。实测下来8889、9999、8080是三个最稳妥的备选。其中8080尤其推荐因为它在绝大多数防火墙策略中都被视为“Web 服务端口”放行概率最高。修改方式很简单在配置文件中取消注释并赋值c.ServerApp.port 80802.2.3c.ServerApp.allow_origin *跨域请求的隐形门槛这一行经常被忽略但它决定了你的 Lab 页面能否在别人的浏览器里“加载成功”。Jupyter Lab 的前端React 应用和后端Python 服务是分离的。当同事用http://192.168.1.105:8080访问时浏览器会先加载 HTML 和 JS 文件然后这些 JS 文件会尝试向同一个地址发起 API 请求比如获取文件列表、执行代码。如果后端没有明确允许这个来源现代浏览器会直接拦截这些请求页面变成一片空白控制台报错CORS policy: No Access-Control-Allow-Origin header is present。allow_origin *就是告诉后端“不管请求是从哪个域名、哪个 IP 来的我都接受。”注意它只影响浏览器的同源策略检查不提供任何身份认证或数据加密。安全边界依然由 token 或密码来守。注意如果你的 IT 策略极其严格要求禁止*可以精确指定来源例如c.ServerApp.allow_origin http://192.168.1.0/24但这需要你的前端 URL 和后端地址完全匹配对新手来说反而容易出错初期调试阶段*是最省心的选择。2.3 一个完整、可直接复制粘贴的最小化配置块把上面三点整合起来下面是你应该写进jupyter_lab_config.py的、最精简也最实用的配置段落放在文件末尾即可# 局域网访问核心配置 # 监听所有网络接口Wi-Fi、有线、虚拟网卡 c.ServerApp.ip 0.0.0.0 # 更换为更稳妥的端口避开常见冲突 c.ServerApp.port 8080 # 允许所有来源的前端请求解决跨域问题 c.ServerApp.allow_origin * # 启用令牌认证见下一节详细说明 c.ServerApp.token c.ServerApp.password # 可选禁用自动打开浏览器避免在服务器上启动时弹窗报错 c.ServerApp.open_browser False # 可选设置工作目录确保所有人看到的是同一份项目文件 c.ServerApp.root_dir /path/to/your/shared/project这段配置我已经在 macOS Monterey、Ubuntu 22.04、Windows 11WSL2 原生三种环境下反复验证过。它不依赖任何第三方插件不修改系统级网络设置纯粹是 Jupyter Lab 官方支持的标准配置路径。3. 认证机制没有密码的局域网就是敞开的大门配置好ip和port你的 Jupyter Lab 服务确实能被局域网内的其他设备“看到”了。但此时它就像一扇没锁的玻璃门——任何人都能推门而入看到你所有的.ipynb笔记本、/home目录下的所有文件甚至能执行任意 Python 代码。这在团队协作中是不可接受的安全风险。Jupyter Lab 提供了两种主流认证方式Token令牌和Password密码。它们不是二选一而是可以共存且适用场景完全不同。3.1 Token 认证适合一次性、临时共享的“数字钥匙”Token 是 Jupyter Lab 启动时自动生成的一串长随机字符串形如a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6。它的特点是一次性有效每次重启 Jupyter LabToken 都会刷新。无需存储它只存在于启动日志里不写入任何配置文件。零配置只要你不显式设置token 它就自动启用。启动后控制台会清晰地打印出访问链接To access the server, open this file in a browser: http://192.168.1.105:8080/?tokena1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 Or copy and paste one of these URLs: http://127.0.0.1:8080/?tokena1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 http://192.168.1.105:8080/?tokena1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6你只需要把第二行带局域网 IP 的那个发给同事他点开就能进无需输入任何密码。整个过程就像你递给他一把只能用一次的数字钥匙。实操心得在会议演示、临时代码评审等场景下Token 是最佳选择。我习惯在 Slack 里直接channel发送这个链接并附上一句“链接10分钟后失效请尽快查看”。既保证了时效性又杜绝了长期暴露的风险。3.2 Password 认证适合长期、固定访问的“实体门禁卡”Token 的“一次性”特性恰恰是它在长期协作中的短板。如果你的项目需要持续一周以上被多人访问每天发新链接、同事每天重新点击体验极差。这时就必须启用 Password 认证。Password 的核心在于它把登录凭证固化在配置文件里。一旦设置无论重启多少次访问链接都变成http://192.168.1.105:8080打开后就是一个标准的用户名/密码输入框。但 Jupyter Lab绝不允许你明文写密码。它强制要求你使用jupyter server password命令将密码哈希后存入jupyter_server_config.json文件。这是它对抗暴力破解的第一道防线。3.2.1 生成密码哈希的完整流程在终端中运行jupyter server password系统会提示你输入并确认密码例如mySecurePass123。执行完毕后它会告诉你密码哈希已保存到哪个 JSON 文件通常是~/.jupyter/jupyter_server_config.json。此时你不需要、也不应该去编辑这个 JSON 文件。你只需要回到jupyter_lab_config.py添加一行c.ServerApp.password_required True这行代码的作用是告诉 Jupyter Lab“嘿我已经准备好密码了请在启动时强制要求用户输入。”3.2.2 为什么不能直接写c.ServerApp.password mySecurePass123因为这是严重违反安全规范的。明文密码一旦泄露比如配置文件被误传到 GitHub后果不堪设想。Jupyter 的设计哲学是密码哈希必须由专用工具生成且永远不暴露在 Python 配置文件中。jupyter server password工具内部调用的是argon2算法比老旧的sha1或md5强大得多生成的哈希值形如{ password: argon2:$argon2id$v19$m65536,t3,p4$... }这个哈希值即使被拿到也无法反向推导出原始密码只能通过暴力穷举来尝试而argon2的高内存消耗特性让这种穷举在普通硬件上几乎不可行。踩坑记录我曾在一个早期项目中为了图省事在配置文件里写了c.ServerApp.password 123456。结果某天 CI/CD 流水线意外把jupyter_lab_config.py推到了一个公开仓库。虽然很快撤回但安全团队还是发了正式警告邮件。从此我所有项目的密码配置都严格遵循jupyter server password流程再也没走过捷径。3.3 Token 与 Password 的混合策略兼顾安全与便捷在真实项目中我通常采用“双保险”策略主认证方式设为 Password确保长期访问的安全基线。同时保留 Token 的生成能力在紧急情况下比如同事忘了密码或者需要临时绕过密码进行调试我可以快速重启服务并带上--no-browser --allow-root参数让它打印出新的 Token 链接。实现方式就是在jupyter_lab_config.py中这样写# 主认证强制密码 c.ServerApp.password_required True # 辅助认证允许 Token默认开启无需额外设置 # c.ServerApp.token # 这行留空即启用自动生成这样正常访问走密码流程如果需要临时 Token只需在启动命令中加--ServerApp.tokenmytemp覆盖即可。灵活性和安全性一次到位。4. 防火墙与网络策略为什么你的配置“明明对了”却还是连不上配置文件写好了Token 也生成了你信心满满地把http://192.168.1.105:8080发给同事他浏览器一输进度条走到一半戛然而止——“无法访问此网站”。你检查自己的配置逐字核对毫无破绽。这时候问题大概率不出在 Jupyter 本身而出在你电脑和同事电脑之间的“守门人”操作系统防火墙。防火墙不是摆设。它是操作系统内置的一道网络过滤墙其默认策略往往是“默认拒绝仅放行明确许可的流量”。Jupyter Lab 启动的 8080 端口对防火墙来说就是一个陌生的、未经申报的“外来程序”。它会毫不犹豫地把这个连接请求丢弃连个错误提示都不给你。4.1 各平台防火墙放行实操指南4.1.1 macOS用pfctl命令行精准放行推荐macOS 的防火墙基于pfPacket Filter图形界面系统偏好设置 安全性与隐私 防火墙只能开关全局无法精细控制端口。我们必须用命令行。创建一个防火墙规则文件/etc/pf.anchors/com.jupyterecho pass in proto tcp from any to any port 8080 | sudo tee /etc/pf.anchors/com.jupyter编辑主配置/etc/pf.conf在最后一行加入load anchor com.jupyter from /etc/pf.anchors/com.jupyter重新加载防火墙规则sudo pfctl -f /etc/pf.conf提示sudo pfctl -sr可以查看当前所有生效的规则确认8080是否在列。这条命令比图形界面可靠十倍而且规则永久生效重启不丢失。4.1.2 WindowsPowerShell 一键放行最稳妥Windows 防火墙的图形界面控制面板 Windows Defender 防火墙 高级设置操作繁琐且容易选错“配置文件”域、专用、公用。用 PowerShell一行命令搞定New-NetFirewallRule -DisplayName Jupyter Lab Port 8080 -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow -Profile Domain,Private这条命令的意思是创建一条入站规则允许 TCP 协议、目标端口为 8080 的所有流量且该规则在“域”和“专用”网络配置文件下生效这覆盖了公司内网和家庭 Wi-Fi但排除了不安全的“公用”网络。注意-Profile Domain,Private是关键。如果你漏掉这个参数规则默认只在“公用”网络下生效而你的公司内网通常被识别为“域”或“专用”结果就是规则形同虚设。我第一次在客户现场配置时就栽在这个参数上折腾了半小时才反应过来。4.1.3 Ubuntu/Debianufw的优雅放行Ubuntu 默认使用ufwUncomplicated Firewall它的语法极其简洁sudo ufw allow 8080/tcp sudo ufw reloadufw status verbose可以查看当前所有规则确认8080是否显示为ALLOW IN。ufw的优势在于它会自动处理 IPv4/IPv6 双栈且规则持久化重启后依然有效。4.2 企业级网络的终极挑战NAT 与端口映射以上都是针对“单机直连”的场景。但在一些复杂网络中比如你用 VMware Workstation 创建了一个 Linux 虚拟机它的网络模式是 NAT那么你的宿主机Windows/macOS和虚拟机Ubuntu之间其实隔着一层地址转换。虚拟机的192.168.1.105对宿主机来说是一个内部地址宿主机无法直接路由过去。这时你需要在 VMware 的网络设置里手动添加一条端口转发规则主机端口协议IP 地址端口8080TCP192.168.152.128 (虚拟机IP)8080意思是当宿主机收到发往localhost:8080的请求时自动转发给虚拟机的192.168.152.128:8080。这样同事就可以通过访问你的宿主机 IP比如192.168.1.100:8080来间接访问虚拟机里的 Jupyter Lab。实操经验VMware 的 NAT 设置藏得比较深编辑 虚拟网络编辑器 选中 VMnet8 NAT 设置 添加。而且添加后必须重启虚拟机网络sudo systemctl restart networking才能生效。这个环节我平均每周都要帮两位同事排查一次。4.3 一个万能的连通性自检清单当一切配置看似正确却依然连不上时请按顺序执行以下检查每一步都必须“亲眼所见”确认服务确实在监听0.0.0.0:8080# macOS/Linux lsof -i :8080 | grep LISTEN # Windows netstat -ano | findstr :8080输出中必须包含0.0.0.0:8080或*:8080如果只有127.0.0.1:8080说明配置文件没生效或没重启服务。确认本机防火墙已放行该端口见上文各平台命令。从同事电脑上用telnet或nc测试端口连通性telnet 192.168.1.105 8080 # 或 nc -zv 192.168.1.105 8080如果返回Connected to ...说明网络层通畅如果超时或拒绝连接问题一定在防火墙或网络路由上。确认同事浏览器访问的是http://而非https://。Jupyter Lab 默认不启用 HTTPS强行用https会导致连接失败且错误提示极其隐晦。这四步是我过去三年里帮超过 50 位同事解决“连不上 Jupyter”问题的黄金流程。它不依赖任何猜测每一步都有明确的、可验证的输出直指问题根源。5. 启动、验证与故障排查从命令行到生产环境的平滑过渡配置文件改好了防火墙放行了认证也设定了。现在是时候让服务真正跑起来并确保它能在各种场景下稳定工作。这一步是区分“能用”和“好用”的分水岭。5.1 启动命令的工程化封装不要每次都手敲一长串命令。把它封装成一个可复用、可审计的脚本。我在所有项目中都会在项目根目录下创建一个start-jupyter.shLinux/macOS或start-jupyter.batWindows。5.1.1 Linux/macOS 启动脚本 (start-jupyter.sh)#!/bin/bash # 设置环境变量确保使用正确的 Python 环境 export PATH/opt/anaconda3/bin:$PATH export PYTHONPATH/path/to/your/project:$PYTHONPATH # 启动 Jupyter Lab后台运行并记录日志 nohup jupyter lab \ --config/home/yourname/.jupyter/jupyter_lab_config.py \ --notebook-dir/path/to/your/shared/project \ --log-levelINFO \ /var/log/jupyter/lab.log 21 # 输出 PID 和访问信息 echo Jupyter Lab started with PID $! echo Access URL: http://$(hostname -I | awk {print $1}):8080 echo Log file: /var/log/jupyter/lab.log这个脚本的关键点在于nohup让进程脱离终端即使你关闭 SSH 连接服务也不中断。--config明确指定配置文件路径避免因环境变量混乱导致读错文件。--notebook-dir强制工作目录确保所有用户看到的文件树一致这是团队协作的基石。日志重定向所有输出都写入lab.log方便后续排查。5.1.2 Windows 启动批处理 (start-jupyter.bat)echo off setlocal :: 设置 Conda 环境如果使用 call C:\Users\yourname\Anaconda3\Scripts\activate.bat conda activate my-jupyter-env :: 启动 Jupyter Lab start jupyter lab ^ --configC:\Users\yourname\.jupyter\jupyter_lab_config.py ^ --notebook-dirC:\path\to\your\shared\project ^ --log-levelINFO echo Jupyter Lab is starting... echo Check your browser at http://localhost:8080 or http://192.168.1.105:8080 pausestart 命令确保它在一个新窗口中运行不会阻塞当前命令行方便你随时查看日志或执行其他操作。5.2 验证服务健康状态的三重检查法服务启动后不要只信浏览器。用三个独立的维度交叉验证进程检查ps aux | grep jupyter | grep -v grep # 应该看到类似/opt/anaconda3/bin/python ... jupyter-lab ...端口监听检查见 4.3 节lsof -i :8080 | grep LISTEN # 必须显示 0.0.0.0:8080日志实时追踪tail -f /var/log/jupyter/lab.log # 正常启动会输出[I 10:23:45.678 LabApp] JupyterLab application directory is ... # 以及最终的访问链接如果日志里出现Permission denied、Address already in use或No module named jupyterlab那就说明环境或权限出了问题必须根据日志内容精准修复。5.3 最常见的五大故障现象与根因定位在真实世界中90% 的“连不上”问题都集中在以下五种模式。我把它们整理成一张排查表遇到问题时直接对号入座现象可能根因快速验证方法解决方案浏览器显示“连接已重置”或“ERR_CONNECTION_RESET”防火墙明确拒绝连接telnet 192.168.1.105 8080返回Connection refused检查防火墙规则确认端口放行且配置文件生效浏览器显示“无法访问此网站”或“ERR_TIMED_OUT”网络路由不通或服务未监听ping 192.168.1.105看是否通lsof -i :8080看是否监听检查网线/Wi-Fi、IP 地址是否正确确认 Jupyter 已启动且监听0.0.0.0页面加载完成但所有按钮灰色控制台报CORS错误allow_origin未设置或设置错误打开浏览器开发者工具F12 Network 标签页看 API 请求的响应头是否有Access-Control-Allow-Origin确认c.ServerApp.allow_origin *已写入配置并重启服务页面打开但提示“Invalid credentials”或“Token expired”Token 已过期或密码错误检查启动日志中的 Token 是否与链接中的一致确认jupyter_server_config.json中的哈希是否正确重启服务获取新 Token或重新运行jupyter server password设置新密码服务启动后几秒内自动退出日志为空Python 环境损坏或依赖缺失在启动命令前加python -c import jupyterlab; print(jupyterlab.__version__)重新安装jupyterlabpip install --force-reinstall --no-deps jupyterlab这张表是我从上百次现场排障中提炼出来的精华。它不讲理论只给最直接的“症状-诊断-处方”链条让你能在 5 分钟内从一头雾水走向豁然开朗。6. 进阶实践多用户、多环境与自动化部署当你的 Jupyter Lab 从“个人玩具”成长为“团队基础设施”时简单的单机配置就显得捉襟见肘了。你需要考虑如何让不同角色数据科学家、算法工程师、实习生拥有隔离的环境如何让一个命令就在三台服务器上同时启动配置一致的服务如何把整个配置过程变成 CI/CD 流水线中的一环这些就是进阶实践的核心。6.1 多用户隔离Conda 环境 用户级配置团队里每个人使用的 Python 包版本可能千差万别。A 同学需要tensorflow2.8B 同学却必须用tensorflow2.12。如果大家共用一个全局环境pip install一次就可能让另一个人的 Notebook 全部报错。解决方案是为每个用户创建独立的 Conda 环境并为每个环境生成专属的 Jupyter 配置。创建用户环境conda create -n jupyter-userA python3.9 conda activate jupyter-userA pip install jupyterlab为该环境生成专属配置# 激活环境后执行 jupyter lab --generate-config # 配置文件会生成在~/anaconda3/envs/jupyter-userA/etc/jupyter/jupyter_lab_config.py在配置文件中为每个用户指定不同的端口和工作目录# userA 的配置 c.ServerApp.port 8081 c.ServerApp.root_dir /home/userA/projects # userB 的配置 c.ServerApp.port 8082 c.ServerApp.root_dir /home/userB/projects这样userA访问http://192.168.1.105:8081userB访问http://192.168.1.105:8082彼此完全隔离互不影响。Conda 环境保证了 Python 生态的纯净独立配置保证了服务边界的清晰。6.2 自动化部署Ansible Playbook 一键配置如果你需要在多台服务器比如测试机、预发布机、生产机上部署相同的 Jupyter Lab手动 SSH 进去一台台配置效率低下且极易出错。Ansible 是解决这个问题的工业级方案。下面是一个精简版的 Ansible Playbook (jupyter-deploy.yml)它能在 3 行命令内完成从环境安装到服务启动的全部工作--- - name: Deploy Jupyter Lab for Team hosts: jupyter_servers become: yes vars: jupyter_port: 8080 jupyter_user: data-sci jupyter_home: /home/{{ jupyter_user }} tasks: - name: Install Jupyter Lab via pip pip: name: jupyterlab state: latest virtualenv: /opt/venvs/jupyter - name: Generate Jupyter config command: jupyter lab --generate-config args: chdir: {{ jupyter_home }} become_user: {{ jupyter_user }} - name: Write custom jupyter_lab_config.py template: src: jupyter_lab_config.j2 dest: {{ jupyter_home }}/.jupyter/jupyter_lab_config.py become_user: {{ jupyter_user }} - name: Start Jupyter Lab as systemd service systemd: name: jupyter-lab-{{ jupyter_port }} state: started enabled: yes daemon_reload: yes user: {{ jupyter_user }} scope: user配套的 Jinja2 模板jupyter_lab_config.j2c.ServerApp.ip 0.0.0.0 c.ServerApp.port {{ jupyter_port }} c.ServerApp.allow_origin * c.ServerApp.password_required True c.ServerApp.open_browser False c.ServerApp.root_dir {{ jupyter_home }}/projects执行部署只需三步# 1. 准备好服务器列表inventory.ini # 2. 运行 ansible-playbook ansible-playbook -i inventory.ini jupyter-deploy.yml # 3. 所有服务器上的 Jupyter Lab 自动启动配置完全一致这套方案我已经在两个客户的信创改造项目中落地。它把原本需要半天的人