Demand Analysis

目前在实验室需要做大量的数据处理、分析和模型搭建类项目,Jupyter Notebook 就成了工作环境的不二选择。但是时间安排要求大量的远程工作,而 Teamviewer 等工具又不是非常的方便(尤其是身边只有 iPad 的时候),因此 Jupyter 服务器就成为首选。

但是这样以来有几个挑战:

  • 内网穿透:实验室属于内网,不能从公网直接访问。
  • 安全性:Jupyter Notebook 默认在 HTTP 明文协议下运作,极易被监听或劫持,并且默认能够全盘修改文件。

Solution Overview

经过权衡,解决方案如下:

  • 配置 Jupyter Notebook 作为对外安全的 HTTPS 服务
  • 使用 frp 解决内网穿透问题:这是一个传统操作,曾今被用来穿透宿舍内网,ssh 到笔记本上进行调试。
  • 配置 Kiv Zone 服务器的 Nginx 反向代理:Kiv Zone 基于 Nginx 维持站点运作、静态资源获取和 api 接口的对外开放。
  • 将服务挂载到 kivenchen.us/wini/de/pul (示例)路由

在本文中,运行 Jupyter Notebook 的实验室机器被称为 Provider Server,Kiv Zone 服务器被称为 Proxy Server,访问方(比如笔者 iPad 的 Juno App)被称为 Client。所有端口、路径、路由、验证口令等,纯属乌有,并不实际存在。

第一步:从 HTTP 做起

Provider Server

配置 Jupyter Notebook

(资料来源于 Jupyter 官方文档

首先,生成 Jupyter Notebook 的配置文件并修改,即 ~/.jupyter/jupyter_notebook_config.py~是任意系统的用户文件夹)

$ jupyter notebook --generate-config

除了必需的端口外,由于 Provider 被代理到 Proxy 的二级路由以下,需要配置 base_url(默认是 / ,即代理到 kivenchen.us 或者 localhost 的根目录下。

c.NotebookApp.allow_remote_access = True
c.NotebookApp.port = 621
c.NotebookApp.base_url = '/wini/de/pu/'

可以配置的还有 Jupyter Notebook 打开的根目录

c.NotebookApp.notebook_dir = r'/Users/Kiven/Project-Ex'

此外,还需要为 Jupyter Notebook 设置密码。直接运行

$ jupyter notebook password

并且输入、确认密码,就能把密码的 hash 写入配置 json 中

配置 frpc (客户端)

(资料来源于 frp 官方文档

首先,确保在 Proxy Server 和 Provider Server 上的 frp 版本相同。

在 Provider Server 上修改 frp 客户端配置文件 frpc.ini。必须要开启 tls。

[common]
server_addr = 181.192.163.240
server_port = 604
tls_enable = true

[jupyter]
type=http
local_port=621
custom_domains=kivenchen.us
use_compression=true
auth_token=bluewhitestripe

并启动

frpc -c frpc.ini

Proxy Server

配置 frps (服务端)

在配置文件 frps.ini 中写入:

[common]
bind_port = 604  # the same as client's `server_port`
vhost_http_port = 1969
auth_token=bluewhitestripe

并启动。与 Windows 客户端不同,服务器端可以后台运行

nohup ./frps -c frps.ini &

配置 Nginx

Nginx 已经配置了博客系统的代理和 Kiv Zone 的 HTTPS 设置,但是并不影响我们配置多一层路由。这里的路由配置写在 https 配置板块下。

location ^~ /wini/de/pu/ {
    proxy_redirect off;
 
 	# 转发被 frps 反向代理的内容
    proxy_pass http://127.0.0.1:1969;
    
    # 设置 headers
    proxy_set_header Cache-Control no-store;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
}

然后享用

以 Juno 为例。做好配置并输入密码就可以连接。

接着就可以正常操作了。

第二步:向 HTTPS 进发

虽然 HTTP 服务器运行良好,但是不要忘了,只有 Client 和 Proxy Server 间使用 HTTPS 协议,理论上不会受到中间人攻击,但是 Proxy Server 和 Provider Server 之间的通信依旧是明文。

Provider Server

生成证书

为了实现加密连接,我们需要生成 CA 证书。此处以 openssl 为例。

(插曲:作者的 openssl 配置文件路径出了偏差,stackoverflow 之后,用 Listary 直接搜了个本地 Anaconda 环境里的 cnf 文件填进环境变量。不过不怎么影响)

为了方便起见,首先在某个路径生成证书以及相应的公钥,此处有效期一年。

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mykey.key -out mycert.pem

配置 Jupyter

将证书和公钥文件的目录写入 .py 配置文件

c.NotebookApp.certfile = u'/absolute/path/to/your/certificate/mycert.pem'
c.NotebookApp.keyfile = u'/absolute/path/to/your/certificate/mykey.key'

配置 frpc

只需要把类型改为 https

[common]
server_addr = 181.192.163.240
server_port = 604
tls_enable = true

[jupyter]
type=https
local_port=621
custom_domains=kivenchen.us
use_compression=true
auth_token=bluewhitestripe

Proxy Server

0810:遇到问题 – frp 反向代理 https 经过 nginx 会出现 502 错误

Leave a comment

Your email address will not be published. Required fields are marked *