
1. 为什么要在局域网里折腾 Jupyter Notebook 远程访问很多人第一次听到内网远程访问 Jupyter Notebook这个需求脑子里冒出来的第一个疑问是我直接在本机跑不就行了吗为什么非要远程这个问题问得对因为如果只是自己写两行 Python 脚本本机跑确实最省事。但真实场景往往不是这样。我遇到这个需求最早是因为一台放在机房的深度学习工作站。那台机器装了两块显卡跑模型训练的时候风扇声音跟吹风机一样坐在旁边根本没法安心写代码。更现实的问题是数据全在那台机器上几十个 G 的数据集不可能每次都拷到笔记本上。于是最自然的想法就是让那台机器当计算服务器我在自己的笔记本上通过浏览器连过去用它的算力、用它的数据但界面在我这边。这就是 Jupyter Notebook 远程访问的核心价值——把计算和交互分离。计算跑在性能强的机器上交互界面在你手边的设备上。Anaconda 在这里扮演的角色是环境管理器它把 Python 解释器、Jupyter 以及一大堆科学计算库打包在一起省去了手动配环境的麻烦。但这里有个关键前提内网局域网。为什么强调内网因为内网环境相对封闭机器之间通过交换机或路由器直连不经过公网配置起来简单、速度快、延迟低而且不涉及任何对外暴露的问题。你不需要考虑域名、证书、端口映射这些让人头大的东西只要两台机器在同一个网段里能互相 ping 通事情就成了一半。这篇文章适合谁看三类人最对口。第一类是有多台机器比如一台台式机加一台笔记本的开发者想把重活丢给性能好的那台。第二类是实验室或小团队里共用一台计算服务器的同学需要多人各自连上去用。第三类是刚接触 Anaconda 和 Jupyter、想搞明白服务端和客户端到底怎么分工的新手。不管你属于哪一类下面的内容都会从最基础的原理讲起一步步带你跑通并且把我踩过的坑都摊开说清楚。需要提前说明的是本文所有操作都限定在局域网内部不涉及任何跨网络访问的配置。你只需要保证两台机器在同一个路由器或交换机下能互相通信即可。2. 搞懂 Jupyter 的服务端与客户端分工再动手2.1 Jupyter Notebook 本质上是一个 Web 服务很多人用了很久 Jupyter 都没意识到一件事你平时在浏览器里打开的那个localhost:8888其实是一个跑在本地的 Web 服务器。Jupyter Notebook 的架构非常清晰它由两部分组成一个是内核Kernel负责真正执行 Python 代码另一个是 Web 服务器负责把代码、输出、Markdown 渲染成网页给你看。你平时双击图标启动 Jupyter它做的事情就是在本地的 8888 端口起一个 HTTP 服务然后自动帮你打开浏览器访问这个地址。浏览器和这个服务之间的通信走的是标准的 HTTP 协议加上 WebSocket用于实时推送执行结果。理解这一点非常关键因为它直接决定了远程访问的思路既然它是个 Web 服务那我只要让这个服务监听在一个别的机器能访问到的地址上不就能远程连了吗答案是对的但默认配置下它只监听localhost也就是只接受本机连接。我们要做的就是把它改成监听所有网络接口再加上一层访问控制。2.2 为什么默认只监听 localhost这是很多人第一次配置时最困惑的地方我明明启动了 Jupyter为什么同事的电脑就是连不上原因在于 Jupyter 的默认安全策略。它默认绑定127.0.0.1这个地址是回环地址只有本机能访问。这样设计是出于安全考虑——如果默认就监听所有接口那同一网络下任何人只要知道你的 IP 和端口就能直接打开你的 Notebook执行任意代码。这在共享网络环境下是相当危险的。所以我们要做的改动本质上是主动打开这扇门同时配上一把锁。打开门的方式是修改绑定地址配锁的方式是设置密码和 token。这两件事必须一起做只做前者不做后者等于把家门敞开还贴个告示说欢迎光临。2.3 Anaconda 环境下的 Jupyter 到底装在哪还有一个容易被忽略的细节Anaconda 里的 Jupyter 和你用 pip 单独装的 Jupyter配置文件位置可能不一样。Anaconda 会把 Jupyter 装在它自己的环境目录下配置文件默认生成在用户主目录的.jupyter文件夹里。在 Windows 上这个路径通常是C:\Users\你的用户名\.jupyter\在 Linux 或 macOS 上是~/.jupyter/。这个目录下的jupyter_notebook_config.py就是我们要改的核心文件。如果你从来没生成过这个文件需要先运行一次生成命令这个后面会讲。搞清楚这三个基础认知后面的操作就不会是照着敲命令但不知道在干嘛了。你知道每一步在改什么、为什么改出问题的时候才能自己排查。3. 服务端配置让 Jupyter 愿意接受外部连接3.1 生成配置文件这一步别跳过假设你的服务端机器已经装好了 Anaconda打开终端Windows 用 Anaconda PromptLinux/macOS 用普通终端先确认 Jupyter 能正常启动。然后执行下面这条命令生成配置文件jupyter notebook --generate-config执行完你会看到类似这样的输出告诉你配置文件生成到了哪个路径Writing default config to: /home/yourname/.jupyter/jupyter_notebook_config.py注意如果你之前已经生成过这个文件这条命令会提示文件已存在问你是否覆盖。这时候一定要选否输入 n否则你之前的配置就全没了。如果确实想重新生成先把旧文件备份一下。这个文件内容很长全是注释默认所有配置项都是被注释掉的。我们不需要全部看懂只改几个关键项就行。3.2 设置访问密码而不是裸奔在改绑定地址之前先把密码设好。Jupyter 提供了一个专门的命令来生成密码哈希jupyter notebook password它会提示你输入两次密码然后自动把加密后的哈希写进配置文件。这个密码就是你之后在浏览器里打开 Notebook 时需要输入的。为什么要用哈希而不是明文因为配置文件是纯文本如果直接写明文密码任何能读到这个文件的人都能看到你的密码。哈希值即使被看到也无法反推出原始密码。设置完之后你可以打开配置文件确认一下会看到类似这样一行c.NotebookApp.password argon2:$argon2id$v19$m10240,t10,p8$...看到这串东西就说明密码设置成功了。这里用的是 argon2 算法比早期的 sha1 安全得多Anaconda 较新版本默认都用这个。3.3 修改绑定地址与端口接下来是核心改动。用任意文本编辑器打开jupyter_notebook_config.py找到下面这几行它们默认都是注释状态改成我们需要的值c.NotebookApp.ip 0.0.0.0 c.NotebookApp.port 8888 c.NotebookApp.open_browser False c.NotebookApp.allow_remote_access True逐条解释一下为什么这么改。c.NotebookApp.ip 0.0.0.0是让 Jupyter 监听所有网络接口。0.0.0.0不是一个真实地址而是一个通配符意思是本机所有网卡上的地址都接受连接。这样无论是通过 127.0.0.1 还是通过局域网 IP都能访问到。c.NotebookApp.port 8888是端口号。8888 是 Jupyter 的默认端口你也可以改成别的比如 8890只要不和其他服务冲突就行。如果 8888 被占用了启动时会报错换个端口即可。c.NotebookApp.open_browser False是让服务端启动时不要自动弹浏览器。因为服务端机器可能根本没有图形界面或者你根本不需要在它上面看关掉能省点资源也避免报错。c.NotebookApp.allow_remote_access True是明确允许远程访问。有些版本即使设了0.0.0.0如果这项是 False仍然会被拦下来。提示不同版本的 Jupyter 配置项名称可能略有差异。较新的版本里NotebookApp可能被ServerApp替代。如果你改了没生效先确认一下你的 Jupyter 版本用jupyter --version查看。如果版本较新把c.NotebookApp.xxx换成c.ServerApp.xxx试试。3.4 启动并验证服务端配置改完保存文件然后在服务端启动 Jupyterjupyter notebook如果配置正确你会看到类似这样的输出[I 10:23:45.123 NotebookApp] Serving notebooks from local directory: /home/yourname [I 10:23:45.123 NotebookApp] Jupyter Notebook 6.4.5 is running at: [I 10:23:45.123 NotebookApp] http://your-hostname:8888/注意看它打印出来的地址如果显示的是0.0.0.0:8888或者你的主机名而不是localhost:8888说明绑定成功了。这时候在服务端本机用浏览器访问http://localhost:8888应该能打开输入密码后进入。但这只证明本机能用还不能证明远程能连。真正的验证要在客户端机器上做这个放到下一节。3.5 防火墙这道坎必须过服务端配置好了客户端却连不上十有八九是防火墙在拦。这是新手最容易卡住的地方而且报错信息往往很模糊浏览器只会显示无法访问此网站不会告诉你具体原因。在 Linux 上如果用的是 ufw需要放行 8888 端口sudo ufw allow 8888/tcp如果用的是 firewalldsudo firewall-cmd --permanent --add-port8888/tcp sudo firewall-cmd --reload在 Windows 上第一次启动 Jupyter 监听外部地址时系统通常会弹出一个防火墙提示框问你是否允许该程序通过防火墙。这时候一定要勾选专用网络并允许否则外部连接会被直接挡掉。如果当时手滑点了取消需要手动去Windows Defender 防火墙的允许应用通过防火墙里把 Python 或 Jupyter 加进去。注意这里只放行局域网需要的端口即可不要图省事把防火墙整个关掉。关防火墙虽然能快速解决问题但会让机器完全暴露在局域网中得不偿失。4. 客户端连接从另一台机器打开 Notebook4.1 先确认两台机器能互相通信在客户端机器上第一步不是打开浏览器而是先确认网络通不通。打开终端或命令行ping 一下服务端的局域网 IPping 192.168.1.100这里的 IP 要换成你服务端的实际局域网地址。怎么查服务端的 IPLinux 上用ip addr或ifconfigWindows 上用ipconfig。找那个以 192.168 或 10 开头的地址那就是局域网 IP。如果 ping 不通说明两台机器根本不在一个可通信的网络里后面的都不用试了。常见原因有两个一是两台机器连的不是同一个路由器或交换机二是服务端开了防火墙把 ICMP 也拦了这种情况少见但存在。先解决网络连通性再谈 Jupyter。4.2 浏览器访问与 token 处理ping 通了之后在客户端浏览器地址栏输入http://192.168.1.100:8888把 IP 换成你的服务端地址。正常情况下你会看到一个登录页面要求输入密码。输入你在服务端设置的密码就能进入 Notebook 界面了。但有时候你会遇到另一种情况页面提示需要 token。这是因为某些版本的 Jupyter 在首次启动时会生成一个一次性 token即使你设了密码它也可能要求先输入 token。token 在哪里找就在服务端启动 Jupyter 时终端打印的那段输出里有一行类似http://your-hostname:8888/?tokenabc123def456...把token后面那串字符复制出来粘贴到客户端的 token 输入框里即可。输入一次之后后续就只需要密码了。如果你觉得每次找 token 太麻烦可以在配置文件里把 token 验证关掉只保留密码验证c.NotebookApp.token 提示关掉 token 之后密码就成了唯一的防线所以密码一定要设得复杂一点。局域网虽然相对封闭但同一网络下可能有其他设备不能假设绝对安全。4.3 用主机名代替 IP 的可行性如果你觉得记 IP 太麻烦也可以尝试用主机名访问比如http://my-workstation:8888。但这需要局域网内有 DNS 解析或者你在客户端的 hosts 文件里手动加了映射。对于临时用用直接记 IP 更省事如果是长期使用配个 hosts 映射会舒服很多。在 Windows 上编辑C:\Windows\System32\drivers\etc\hosts在 Linux/macOS 上编辑/etc/hosts加一行192.168.1.100 my-workstation之后就能用http://my-workstation:8888访问了。这个改动只影响你自己的机器不影响别人。4.4 连接成功后的实际体验连上之后你会发现操作体验和本机几乎没区别。新建 Notebook、写代码、运行、看输出全都正常。唯一的差别是执行速度取决于服务端的性能而不是你客户端机器的性能。如果你的服务端有 GPU那在 Notebook 里用torch.cuda.is_available()检查一下能返回 True 就说明 GPU 可用接下来就能在远程环境里跑训练了。文件管理方面Notebook 里看到的目录是服务端的工作目录不是你客户端的目录。你在 Notebook 里上传文件文件是传到服务端去的你下载文件也是从服务端下载。这一点要心里有数别搞混了。5. 那些让我折腾半天的坑与排查思路5.1 改了配置却不生效这是最让人抓狂的情况明明配置文件改对了重启 Jupyter 后行为却和没改一样。我遇到过好几次后来发现原因通常是这几个。第一个原因是改错了配置文件。Anaconda 环境下可能存在多个 Jupyter 配置文件比如你之前用 pip 装过一个 Jupyter它的配置在另一个位置。Jupyter 启动时会按优先级读取可能读的不是你改的那个。排查方法是启动时加--debug参数看它到底加载了哪个配置文件jupyter notebook --debug输出里会有一行Loading config file: ...那个路径才是真正生效的文件。第二个原因是配置项名称过时。前面提过新版本把NotebookApp改成了ServerApp。如果你用的是 Jupyter Notebook 7 或 JupyterLab配置项名称可能已经变了。这时候要么降级到旧版本要么按新版本的名称改。第三个原因是没重启服务。配置文件是启动时读取的改完必须完全停掉 Jupyter 再重新启动热重载是不存在的。5.2 端口被占用怎么办启动时报Address already in use说明 8888 端口已经被别的程序占了。可能是你之前启动的 Jupyter 没关干净也可能是别的服务在用这个端口。先查是谁占用了端口。Linux 上用lsof -i :8888Windows 上用netstat -ano | findstr :8888找到进程号后要么把它关掉要么给 Jupyter 换个端口。换端口很简单改配置文件里的c.NotebookApp.port或者启动时直接指定jupyter notebook --port 88905.3 能 ping 通但浏览器打不开这种情况最迷惑人网络明明是通的ping 有回应但浏览器就是连不上。可能的原因有几个。一是防火墙只放行了 ICMP 没放行 TCP。ping 用的是 ICMP 协议而浏览器访问用的是 TCP。防火墙可能允许 ping 但拦住了 8888 端口的 TCP 连接。回到服务端检查防火墙规则确认 8888 端口确实放行了。二是Jupyter 实际没监听在 0.0.0.0。虽然你改了配置但可能没生效见上一节。在服务端用netstat -tlnp | grep 8888看一下如果显示的是127.0.0.1:8888而不是0.0.0.0:8888说明绑定没改成功。三是客户端和服务端不在同一网段。比如服务端是 192.168.1.x客户端是 192.168.0.x虽然都能上网但互相之间可能被路由规则隔离。确认两台机器的 IP 前三段是否一致。5.4 多人同时使用时的资源冲突如果是一台服务器多人共用会碰到一个现实问题每个人启动 Jupyter 都想用 8888 端口但端口只能被一个进程占用。解决办法是每个人用不同的端口。比如第一个人用 8888第二个人用 8889第三个人用 8890以此类推。启动时指定端口即可jupyter notebook --port 8889但这样每个人都要记自己的端口容易乱。更好的做法是每个人在自己的用户目录下配置不同的端口写进各自的配置文件里启动时自动生效。另外多人共用时还要注意工作目录的隔离。默认情况下 Jupyter 启动在哪个目录就只能访问那个目录及其子目录。每个人在自己的 home 目录下启动就天然隔离了不会互相看到对方的文件。5.5 长时间运行断开连接的问题远程连接有个常见现象你开着 Notebook 去干别的事过一段时间回来发现连接断了需要重新登录。这是因为浏览器和 Jupyter 之间的 WebSocket 连接在空闲时可能被中断。如果只是偶尔断一下重新连上就行Notebook 里的代码和输出不会丢因为它们是保存在服务端的。但如果频繁断开影响使用可以检查一下是不是网络不稳定或者服务端的 Jupyter 进程被系统休眠策略影响了。对于需要长时间跑的任务建议不要依赖浏览器的连接状态。把训练脚本写成.py文件用nohup或tmux在服务端后台跑Notebook 只用来做交互式开发和调试。这样即使浏览器断了任务照样在跑。6. 让远程访问更顺手的几个进阶配置6.1 配置默认工作目录每次启动 Jupyter 都跳到 home 目录然后手动一层层点进项目文件夹时间长了很烦。可以在配置文件里指定默认目录c.NotebookApp.notebook_dir /home/yourname/projectsWindows 上路径要写成rD:\projects这种形式注意用原始字符串避免反斜杠转义问题。改完之后启动 Jupyter直接就在项目目录里了。注意这个目录必须存在否则 Jupyter 启动会报错。另外要确保运行 Jupyter 的用户对这个目录有读写权限。6.2 用 nohup 让 Jupyter 在后台常驻默认情况下你关掉终端Jupyter 进程就跟着结束了。如果希望它一直在后台跑可以用 nohupnohup jupyter notebook jupyter.log 21 这条命令的意思是把 Jupyter 放到后台运行标准输出和错误输出都重定向到jupyter.log文件表示后台执行。这样即使你退出 SSH 或关掉终端Jupyter 依然在跑。想停掉它的时候先找到进程号ps aux | grep jupyter然后 kill 掉即可。日志文件jupyter.log里会记录启动信息和访问日志出问题的时候可以翻一翻。6.3 用 tmux 管理多个会话如果你经常需要在服务端同时跑多个任务tmux 是个好东西。它能在服务端创建多个独立的终端会话每个会话里可以跑不同的东西而且断开连接后会话依然保留。基本用法很简单tmux new -s jupyter # 新建一个叫 jupyter 的会话 # 在里面启动 jupyter notebook # 按 CtrlB 然后按 D 脱离会话 tmux attach -t jupyter # 重新连接会话这样你可以一个会话跑 Jupyter另一个会话跑训练脚本互不干扰。比起 nohuptmux 的好处是你能随时回去看实时输出交互性更好。6.4 关于安全性的几句实在话虽然本文限定在局域网内但有些话还是得说。局域网不等于绝对安全尤其是在办公室、实验室这种多人共享的网络里。同一网络下的其他设备理论上是可以扫描到你的开放端口的。所以几件事必须做到密码要复杂不要用123456这种不要图省事关掉密码验证如果长期不用把 Jupyter 停掉而不是一直挂着定期看看访问日志有没有陌生的 IP 连过。另外c.NotebookApp.allow_remote_access True这项虽然方便但也意味着任何能访问到你 IP 的人都能尝试连接。如果你的局域网环境比较复杂可以考虑用 SSH 隧道的方式只在本机开一个转发端口这样 Jupyter 根本不需要对外监听。不过 SSH 隧道的配置稍微复杂一些属于另一个话题了这里不展开。7. 我实际用下来的一些体会这套配置我在不同环境下搭过好几次从 Windows 服务端到 Linux 服务端都试过。最大的感受是配置文件那几行改动本身不难难的是排查为什么没生效。新手卡住的地方往往不是不知道怎么改而是改了没用又不知道去哪找原因。我的建议是每改一步就验证一步。改完绑定地址先在服务端本机用局域网 IP 访问一下确认监听生效了再去客户端 ping 一下确认网络通了最后才在客户端浏览器访问。这样出问题的时候你能快速定位是哪一环断了而不是面对一个连不上的结果干瞪眼。还有一个体会是关于版本的。Anaconda 更新挺频繁的不同版本之间 Jupyter 的配置项名称、默认行为都可能有变化。网上搜到的教程如果年份比较早配置项名称可能已经过时了。遇到对不上的情况第一反应应该是去查你当前版本的官方文档而不是硬套旧教程。最后说个小事。远程访问配好之后我习惯在服务端的 Jupyter 里装一个jupyterlab或者nbextensions前者界面更现代后者能加一些实用的小功能比如代码折叠、目录导航。这些都属于锦上添花核心的远程访问跑通了剩下的按自己喜好折腾就行。