资讯动态

服务器上远程使用Jupyter Notebook:虚拟环境配置与SSH端口转发实战指南

发布时间:2026/10/24 8:35:01 来源:尧图企业网站定制
不知道你有没有过这种经历人坐在实验室工位前本地跑一个数据任务眼看着内存一点点被吃光风扇转得像飞机起飞最后直接OOM崩溃。而隔壁服务器明明有128G内存、几十个核、显卡还空着却因为“不会用”、“连不上去”一直闲置。我当时也卡在这一步最想搞清楚的问题就两个第一怎么在自己的浏览器里用上服务器上的Jupyter Notebook第二怎么让Jupyter Notebook跑在指定的虚拟环境里而不是稀里糊涂用错了Python解释器。这篇内容就是围绕这两个问题整理的。不是为了写文档而是把我在实验室服务器平台上从“连不上”到“用得很顺手”的完整过程、关键命令、踩过的坑都放出来。不管你是第一次接触服务器的新手还是已经在用但总感觉哪里不对劲的中间选手都可以把这篇文章当作一份直接能跟着操作的手册。1. 为什么要把Jupyter放到服务器上而不是继续用本地1.1 本地和服务器之间的资源差距是明显且残酷的先看一个我真实经历过的场景。我在本地笔记本上处理一个中等规模的数据矩阵内存32G听着不小但一加载数据、跑特征工程、再来个机器学习训练内存直接见顶。任务跑到一半进程被杀掉前面计算全部作废。同一份代码和数据放到服务器上30秒跑完内存占用不到一半。这不是夸张而是绝大多数实验室服务器的常态。实验室服务器通常就是专门为计算准备的内存、CPU核心数、GPU配置都远强于个人电脑。而这个资源的唯一问题就是“它是一台没有图形界面的Linux机器”你需要通过命令行远程操作。很多人就是被这一步劝退的。所以第一件事先把观念扭转过来服务器不是“机房里的另一台大电脑”而是你随时可以借力的计算资源。用上它第一步是克服“命令行恐惧”第二步才是把Jupyter这种熟悉的交互环境搭到服务器上。1.2 在服务器上用Jupyter的常见方式怎么选我整理了一下目前主流的选择有这么几种方式核心思路优点缺点适合场景终端里直接跑SSH登录后用jupyter lab命令启动再把端口转发到本地轻量、依赖少、最通用需要理解端口和网络转发稍微有点门槛任何场景尤其是服务器没有图形界面的情况VS Code Remote通过VS Code的Remote-SSH插件连接服务器编辑体验好集成调试终端需要本地装VS Code服务器侧也要有相应支持习惯用IDE做开发的人RStudio Server等专用IDE在服务器上架设RStudio Server等面向特定语言的体验更好通用性差Jupyter生态才是主流纯用某个语言跑分析的人对于绝大多数Python数据分析、机器学习、深度学习的人来说直接搭一个Jupyter Lab/Notebook Server然后用浏览器访问是上手最快、问题最少的方式。原因很简单你不需要在服务器上装一个图形化桌面只需要一个Web服务你也完全不需要改变自己已经习惯的Notebook操作习惯浏览器打开就是熟悉的界面。1.3 “虚拟环境”这个概念为什么绕不开真正开始用服务器以后第二个绕不开的问题就是环境混乱。想象一下你的服务器上同时跑着好几个项目。A项目需要Python 3.8加旧版的NumPyB项目需要Python 3.10加新版的NumPy。如果不做隔离要么天天改包版本要么环境被某个项目搞得完全没法用。虚拟环境就是为这个准备的每个项目有自己独立的Python解释器、独立的包目录、互不干扰。这里要特别说明“进入虚拟环境”这件事在Jupyter语境下有两层意思很多人会混在一起第一层是在命令行里先执行conda activate 环境名再启动Jupyter。这样启动的Jupyter主进程跑在指定环境里。第二层是更关键的Jupyter界面里有一个“Kernel”概念新开的Notebook究竟用哪个Python解释器来执行代码取决于你选择的是哪个Kernel。而不取决于你在终端里激活了哪个conda环境。这两层搞不清楚就会出现一个很经典的问题终端里明明激活了conda环境但在Jupyter里import某个包却报错说没有这个包或者版本不对。后文第4章会专门展开说清楚现在只需要记住Jupyter里跑代码用的Python是由Kernel决定的不是由激活状态决定的。2. 服务器端准备SSH、conda虚拟环境与Jupyter安装2.1 先把SSH这条通道打通用上服务器第一个动作是登录。Linux和macOS都自带SSHWindows 10及以上系统也自带OpenSSH客户端基本不用额外安装。基础的登录命令是ssh 用户名服务器地址比如我常用的一个账户是labuser服务器的内网地址是10.20.30.40那就执行ssh labuser10.20.30.40第一次连接会提示确认主机指纹输入yes回车然后输入密码即可。这一步人人都能完成真正的体验差异在于“每次都要输密码”。我强烈建议把密钥配好一劳永逸。生成密钥并发送到服务器的步骤如下# 在本地机器生成密钥如果还没有 ssh-keygen -t ed25519 # 把公钥复制到服务器 ssh-copy-id labuser10.20.30.40配置好之后再登录就不用输密码了。一个细节如果服务器开通了内网之外的其他网络通道或者你所在的环境要求先通过跳板机再登录那就需要额外配置ProxyJump。这个操作稍微进阶建议先掌握基本SSH再按需搜索配置。2.2 创建专属虚拟环境别把base环境当成工作区登录服务器后的第一件事不是装Jupyter而是创建虚拟环境。很多人图省事直接装进base环境刚开始没问题等装的东西多了某个包的依赖冲突能让你抓狂。以conda为例创建一个3.10版本的独立环境conda create -n py310 python3.10 -y conda activate py310这里有个经验环境名里最好带上Python版本或项目缩写。比如py310、py38_torch、data_analysis这类后面Kernel列表里一眼就能认出来。如果服务器上还没有conda那么先装Miniconda安装脚本直接官网上找最新的版本链接wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh装完以后需要重新登录一下shell或者执行source ~/.bashrc让conda命令生效。2.3 在虚拟环境中安装Jupyter相关组件环境创建好后激活环境再安装conda activate py310 pip install jupyterlab ipykernel这里推荐直接装JupyterLab而不是老版的Jupyter Notebook。JupyterLab是Notebook的升级版界面更现代支持多标签、拖拽布局日常的Notebook文件格式.ipynb它也完全兼容。更重要的是JupyterLab现在的生态和后续功能迭代都明显好于老版界面。至于ipykernel这是让虚拟环境被Jupyter识别为Kernel的基础包后面章节会专门讲现在先装上免得到时缺包。有个小经验如果你在服务器上同时有多个conda环境也不想每次手动注册Kernel可以考虑安装nb_conda_kernels。它会在Jupyter里自动列出所有conda环境点一下就能切换。不过这个包偶尔会显示不准确更推荐的做法还是下一节里的手动注册方式最可控。2.4 启动前检查端口、路径、硬件状态在正式启动Jupyter之前先做几项检查能避免很多回来找你的问题。第一检查目标端口是否被占用。Jupyter默认端口是8888如果已经被其他进程占用启动就会失败或者端口被自动换成8889。检查命令ss -tlnp | grep 8888如果有进程占用启动时直接指定一个空闲端口反而更省事比如--port8899。第二确认你要把Notebook工作目录放在哪里提前创建好。通常我会在服务器上建一个专门的目录比如~/notebooks用来存放项目文件避免把东西散落在根目录或家目录各处。第三看一眼磁盘剩余空间df -h数据分析、模型训练过程中会不停写缓存、写检查点磁盘满了的体验非常糟提前确认总能避免意外。3. 打通本地到服务器的访问链路端口转发是关键3.1 为什么启动之后本地浏览器还是打不开有个特别典型的场景你在服务器上执行了jupyter lab日志显示“Jupyter Server is running at http://localhost:8888”但你打开自己电脑的浏览器输入同样的地址根本打不开。原因很简单服务器上的localhost指的是服务器自己不是你的电脑。你本地浏览器的请求根本没有到达服务器。这时候就需要一条“链路”把本地电脑的端口和服务器上的某个端口连起来。最可靠的工具就是SSH本身自带的端口转发功能不需要额外装任何软件。以一条典型的启动命令为例jupyter lab --no-browser --port8888 --ip127.0.0.1参数的含义分别是--no-browser服务器上没有可用的图形浏览器启动后不要尝试打开浏览器只在终端输出访问链接。--port8888指定端口。--ip127.0.0.1让服务只监听本机回环地址。这一条很重要后面讲安全时还会强调。这样启动之后Jupyter就只运行在服务器自己的localhost:8888上。然后你在本地电脑执行端口转发ssh -L 8888:localhost:8888 labuser10.20.30.40这条SSH命令的-L参数就是“本地端口转发”的缩写。它的意思是把所有发到本地8888端口的流量通过SSH安全通道转发到服务器IP的localhost:8888端口。打个比方这就像在本地和服务器之间修了一条只有你两个人能走的专用管道。本地浏览器访问http://localhost:8888时流量进了管道到了服务器上的Jupyter服务。执行端口转发前该注意的坑-L 8888:localhost:8888这里的localhost是在服务器上解释的不是说本地。所以含义就是“本地8888 - 服务器的localhost:8888”。如果我写成了-L 8888:10.20.30.40:8888意思就变成了“本地8888 - 服务器IP的8888”在多数配置下也能用但前提是服务器允许远端访问该端口。为了保守和单纯建议就保持localhost的写法。3.2 Windows和macOS的具体操作逻辑Windows用户的操作稍微特殊一点如果用的是系统自带的PowerShell或CMD命令和上面完全一样。如果习惯用PuTTY需要在连接配置里找到“Connection - SSH - Tunnels”然后Source port填8888Destination填localhost:8888选Local点击Add添加好后再正常连接到服务器。连接成功后你在本地直接访问http://localhost:8888就行。macOS用户就简单了打开“终端”输入和Linux一模一样的命令即可。我平时在macOS上就是用SSH原生命令行最顺手。3.3 一条命令组合启动服务并自动转发经常需要手动敲两条命令服务器上启动Jupyter、本地做端口转发确实有点繁琐。我给自己的流程做了一个简化在本地写一个小脚本里面包含一条带远程命令的SSH转发。核心命令长这样ssh -L 8888:localhost:8888 labuser10.20.30.40 -t source ~/.bashrc conda activate py310 jupyter lab --no-browser --port8888 --ip127.0.0.1解释一下-t参数让SSH在远程服务器上分配一个交互终端这样远程命令里的conda activate才能生效。source ~/.bashrc是为了让远程shell先加载conda环境。连接后Jupyter直接启动同时本地转发也建好两边一次到位。这个方式唯一的麻烦在于SSH会话保持不退Jupyter就一直跑在前台一关终端就断。所以如果你要靠它长期跑任务建议先看一眼第5章的后台化方案结合后再优化这个命令。3.4 访问时需要Token别硬着头皮找“密码”Jupyter Lab默认启用Token认证。第一次启动时终端日志里会显示一行http://localhost:8888/lab?tokenxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx把这串地址整个复制到本地浏览器打开就能进入。如果忘记复制也可以在服务器上查看日志cat ~/.jupyter/jupyter_server_config.json 2/dev/null tail -n 50 nohup.out更推荐的方式是设置一个固定密码免得每次都要翻日志找Token。在已激活环境的前提下执行jupyter server password按提示输入两遍密码之后浏览器访问时直接用这个密码登录。安全方面多说一句Token或密码就相当于Jupyter的钥匙。因为Jupyter可以执行任意Python代码等于是服务器的一个远程代码入口务必保管好不要发到公共频道。4. 进入虚拟环境的正确姿势Kernel机制是重点4.1 那个“激活了环境却用错Python”的经典现场我相信很多人遇到过这样的情况在服务器终端里执行了conda activate py310然后启动Jupyter新建一个Notebook导入一个包结果报错——包不存在。有一种解释是虽然你在终端里激活了py310并从这里启动了Jupyter服务但新开的Notebook默认使用的Kernel可能还是base环境的python或者你上一次启动时选择过的某个Kernel。尤其当你通过“界面上切换Kernel”的方式到处点过之后很容易忘记当前Notebook实际用的是哪个解释器。这就是标题里“并进入虚拟环境”的痛点想在Jupyter里正确进入某个conda环境你得让Jupyter认识它并且主动选择它。4.2 Kernel本质上是“一条解释器路径”不要把Kernel想得太神秘。Kernel的本质就是一组配置文件把Jupyter界面上的一个名字比如py310(3.10)指向服务器上的某个Python解释器路径。启动Notebook时Jupyter会去读这个配置然后用配置里指定的Python解释器去执行代码。所以要让某个conda环境出现在Jupyter左侧的“新建Notebook”列表里核心方法就是到那个conda环境里安装ipykernel并进行注册。4.3 一步步注册你自己的Kernel在目标环境里依次执行# 1. 激活目标环境 conda activate py310 # 2. 安装内核支持包 pip install ipykernel # 3. 注册为Jupyter的一个Kernel python -m ipykernel install --user --name py310 --display-name py310(3.10)逐个拆解参数--user把Kernel配置写到当前用户目录下不需要root权限也不影响其他用户。这是最稳妥的选项。--nameKernel的内部标识最好全小写、不带空格。--display-name在Jupyter界面下拉菜单里显示的名字。这里我写成py310(3.10)一目了然知道Python版本。执行完之后刷新Jupyter页面打开“新建”按钮或者右上角的“选择Kernel”下拉菜单会多出一个py310(3.10)。选中它再新建的Notebook就是在这个虚拟环境里执行代码了。4.4 验证你真正进入了虚拟环境进入Jupyter后新建一个Notebook运行下面这段代码import sys print(sys.executable)如果看到了类似/home/labuser/miniconda3/envs/py310/bin/python的输出说明当前Notebook用的就是py310环境下的解释器。这比任何界面提示都靠谱。此外如果你想确认某个包是不是装在目标环境里可以在终端里做一次对比# 在py310环境里查询torch版本 conda activate py310 pip show torch # 在Notebook里查询torch版本 import torch print(torch.__version__)两者一致就说明环境绑定成功。不一致的情况下八成是因为那个包根本没安装在当前环境里而不是Jupyter选错了Kernel。4.5 多环境共存的命名规范和长期经验当服务器上同时有好几个conda环境时管理Kernel列表会变成一件日常小事。我的推荐做法是环境名统一为项目简称_python版本的格式比如cov19_py38、ner_py310。注册Kernel时--display-name尽量写成“环境名版本用途”比如cov19_py38(3.8, NLP)选择的时候不会犹豫。尽量不要在base环境里做任何项目依赖安装把base当作“裸的系统Python”干净一点对所有人都友好。周期性地清理旧内核因为Jupyter的Kernel列表会随着你注册越来越多而变得混乱。查看现有内核可以用jupyter kernelspec list移除不用的内核是jupyter kernelspec remove 名字。5. 后台长驻、断线保护与高频报错排查5.1 如何让Jupyter在断线后依然运行如果你只是临时开一个Notebook跑一会儿前台运行完全够用。但现实往往是连接服务器的终端窗口一关前台进程就被SIGHUP信号终止Jupyter跟着就断了。所以需要把它放到后台。最简单的方式是nohup加conda activate py310 nohup jupyter lab --no-browser --port8888 --ip127.0.0.1 jupyter.log 21 拆解一下nohup的作用是让进程忽略挂断信号 jupyter.log 21把标准输出和错误输出都写进日志文件最后的让命令在后台执行。这样即便之后关闭了SSH终端Jupyter也会继续运行。想要查看日志直接cat jupyter.log。不过nohup方案有个缺点如果启动时输错了参数或者服务中途崩了你只能靠看日志来判断。更顺手的是tmux方案。5.2 更灵活的tmux断线重连还能看实时日志tmux是一个终端复用工具放在这里最大的价值是它开了一个独立的会话即使SSH断开会话里的进程也不会停。下一次登录时还能重新“接上”那个会话看着日志继续操作。基本流程是# 新建一个tmux会话名字叫jnb tmux new -s jnb # 在会话中激活环境并启动Jupyter conda activate py310 jupyter lab --no-browser --port8888 --ip127.0.0.1 # 离开会话但不关闭会话按下 CtrlB再按 D下次登录后重新进入这个会话tmux attach -t jnb这样做的最大好处是Jupyter的实时日志始终在那个会话里你想看随时可以attach进去不想看了再按CtrlB D分离完全不影响服务运行。5.3 服务器重启后的例行恢复步骤如果服务器某天重启了你不需要慌乱按这个顺序来SSH登录服务器。确认conda可用的基础环境激活目标环境。使用tmux new -s jnb新建会话或者tmux attach -t jnb连接已有会话如果那个会话起不来了就新建。在会话中启动Jupyter确认端口监听ss -tlnp | grep 8888。回到本地执行端口转发命令浏览器访问。这个过程建议写成脚本30秒内恢复。前提是环境的包已经装好了不用重装。5.4 高频报错与排查办法问题常见原因解决办法本地浏览器一直转圈无法打开端口转发没建立或服务没监听在正确端口检查本地SSH转发是否还在检查服务器ss -tlnp确认端口监听Kernel连接失败 / Kernel diedipykernel缺失或内核配置损坏在目标环境重新pip install ipykernel重新注册Kernel500 Internal Server Error多个Kernel配置冲突或版本异常查看jupyter.log删除旧Kernel配置重新注册访问页面要求输入密码但忘了Jupyter有独立密码体系执行jupyter server password重新设置ModuleNotFoundError包没装在当前Kernel对应环境在终端里进入目标环境安装该包并确认sys.executable路径启动提示“Address already in use”端口被占用更换--port或先停止旧进程再启动5.5 安全是一票否决项尤其涉及端口暴露最后一个想强调的问题就是安全。很多人图省事启动Jupyter时直接写--ip0.0.0.0想着“方便局域网访问”。这样做的风险在于只要服务器上其他网络端口是可访问的Jupyter就等于把自己的代码执行能力直接暴露给了整个网络。一旦Token泄露后果很严重。我更推荐的做法是**启动时就用--ip127.0.0.1只监听本机然后通过SSH隧道访问。**隧道是加密的相当于给Jupyter包了一层安全壳。每次访问都要经过SSH认证这样即使Token内容在网络传输过程中被截获明文也暴露不了。如果某些特殊场景必须要开0.0.0.0那至少要做到使用高强度密码不要用默认Token直连。在防火墙或安全组规则中只放行特定来源IP访问这个端口。定期查看jupyter.log关注访问记录和异常尝试。我个人在这些年的使用过程中慢慢形成了固定习惯**tmux开会话跑服务、SSH隧道来访问、注册好每个虚拟环境的Kernel、统一命名到处复用。**这套流程熟练以后再回到实验室服务器上做实验基本不会再出现“环境不对”或“连不上服务”的尴尬。最后再分享一个小技巧把常用的Jupyter启动命令和转发命令分别写成shell脚本放到本地和服务器各一份以后只需要执行两行命令几秒钟就能进入一个已经准备好的一切环境里开始工作。

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

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

免费获取报价 →
↑