文章目录[隐藏]
我在能连接到公网的服务器上开了一个 Jupyter Lab 服务,平时用来看数据和测试一些代码。
考虑到用 Nginx 来管理 Web 服务的 IP 白名单和 HTTPS 证书会比较方便,而且,如果将 Jupyter Lab 绑定到子域名上,URL 中可以省去一个端口号,看起来比较美观。因此,我决定采用 Nginx 反向代理的方式,将服务绑定到子域名上。途中遇到了一些坑,在此记录一下。
相关版本情况
服务器系统:Ubuntu 20.04 LTS
Jupyter Lab 版本:3.2.8
Python 版本:3.10.1
宝塔面板版本:免费版 7.8.0
Nginx 版本:1.20.1
Jupyter Lab 服务器配置
因为 Nginx 和 Jupyter Lab 在同一台服务器上,反向代理就是访问本机 localhost,所以并不用特意设置 ServerApp 的 ip 字段,保持默认即可。
需要设置的字段只有一个,就是 ServerApp
的 allow_origin
字段,需要将其设置为 「协议名+待绑定域名」的格式(如图 1)。例如 https://aaa.bbb.com
。值得注意的是,这里的协议名是必须指明的,如果用的是 https
协议访问,那不写协议名或者写成 http
都是不可以的,仍然会有跨域问题。
Nginx 反向代理配置
我服务器上用的是宝塔面板,一开始我以为直接添加反向代理,将请求转发到 localhost 上的对应端口即可(图 2)。
结果发现添加完成后,一旦访问,Jupyter Lab 就在终端里一直报错,浏览器中也只能加载出 UI,完全打不开文件。
查询资料后发现,报错有两个原因:
- Jupyter Lab 传输数据用的是
Websocket
,它需要HTTP 1.1
长连接的支持,而 Nginx 的反向代理默认采用HTTP 1.0
。 Websocket
连接在请求中需要用Connection
和Upgrade
两个请求头指明使用Websocket
协议,而客户端请求中的这两个请求头在通过 Nginx 反向代理时会被过滤掉,并不会自动转发。因为根据HTTP
协议规范,Upgrade
和Connection
属于hop-by-hop
请求头,Nginx 作为中间的代理,按照规范不能直接转发hop-by-hop header
。
因此,需要在 Nginx 的反向代理配置中,额外加入这 3 行设置(如图 3),将 HTTP 协议版本指定为 1.1,以及添加 Connection
和 Upgrade
两个请求头。
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
参考文献
[1] 遗忘. WebSocket 协议之 NGINX 代理转发无法建立连接问题处理 [G/OL]. CSDN 博客, 2020(20200316)[2020-03-16]. https://blog.csdn.net/yiwangC/article/details/104898519
[2] encoderlee. 使用 Nginx 为 TCP/WebSocket 协议做反向代理和几个易踩的坑 [G/OL]. CSDN 博客, 2019(20190512)[2019-05-12]. https://blog.csdn.net/CharlesSimonyi/article/details/90122916
[3] 虎嗅蔷薇. nginx 代理 WebSocket 及 HTTP[G/OL]. 虎嗅蔷薇, 2021(20210510)[2021-05-10]. https://www.funkit.net/202105/fbc19c2049e7.html
[4] 永夜初晗凝碧天. 配置 Nginx 反向代理 WebSocket[G/OL]. 个人博客, 2020(20200113)[2020-01-13]. https://yongnights.github.io/2020/01/13/%E9%85%8D%E7%BD%AE%20Nginx%20%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%20WebSocket/
[5] Jinzhong Xu. 利用 nginx 反向代理为 jupyterlab 配置二级网址页面 [G/OL]. J Blog, 2020(20201109)[2020-11-09]. https://xujinzh.github.io/2020/11/09/jupyterlab-nginx/
学习了。