リモートサーバにJupyterLabを導入し、ローカルからhttpsでアクセス

**環境**
ローカルPC: MacBook Air(Monterey)
サーバPC: **Ubuntu Server** 20.04.4
※**オレオレ証明書**を使用
※リモートサーバには**固定IP**を割り当て
(2024/2/8追記)見ての通り古い情報です。暗号方式も安全ではなくなっているでしょう。ご注意ください。

# JupyterLab導入時に思ったこと
JupyterLabの導入をネットで調べると、ブラウザのアドレスバーに`http://`と入力させる記事がほとんどでした。しかし、通信のHTTPS化が進むこのご時世、私はJupyterLabのアクセスもhttpsでセキュアにしたかった…！

# JupyterLabをリモートサーバにインストール
今回はpip3で導入します（他にもcondaなどで導入できます）。
```sh
pip3 install jupyterlab
```
そして`export PATH="$HOME/.local/bin:$PATH"`を.zshrcなどに書き込み、sourceコマンドで適用します。

### Node.jsが必要
ただ、サーバに`Node.js`が導入されていないと**JupyterLabのカーネルが起動しない**ようです。つまり`.ipynb`が実行できません...

Node.jsの導入は少しややこしくなっています。
```sh
sudo apt install -y nodejs npm
sudo npm install n -g
sudo n stable

 # nodejsとnpmの削除。環境の固定（バージョンアップさせない）ため？
sudo apt purge -y nodejs npm
```

# HTTPS化の準備
HTTPS通信には**デジタル証明書**が必要です。
しかし、自分用なので認証局に申請するほどのことでもありませんし、コミュニティ内のローカル認証局（有るのでしょうか？）に申請するのも時間と手間がかかります。

なら、今すぐに解決する道は1つしかありません ――― **オレオレ証明書**です！
### 1.　.cnfファイルを作る
まず、`~~~.cnf`を作る必要があります。

作成後に元の設定に戻す必要があるため作業用ディレクトリを作成し、その中で以下を行います。
※Ubuntuでは元となる`.cnf`が`/etc/ssl/openssl.cnf`の位置にあります。
```sh
mkdir ~/myopenssl
cd ~/myopenssl
sudo cp /etc/ssl/openssl.cnf ./san.cnf
```
この`san.cnf`という名前でコピーしたファイルの一部を編集しなければなりません。
#### .cnfファイルの編集
以下での`有効化`は、コメントアウトを外す(#を消す)か、無い場合に追記することを指します。
1.　<strong>[req]</strong>セクションの`req_extensions = v3_req`を有効化

2.　どこかに有る`copy_extensions = copy`の有効化

3.　<strong>[ v3_req ]</strong>セクションの`keyUsage`の次の行に、`subjectAltName      = IP:192.168.1.2`のように自機のIPv4を追加
　※DNSの場合は、`subjectAltName = DNS:xxx.com`
　※複数(マルチ)で書きたい場合は下のリンクを参照
　※`keyUsage`がない場合は、セクションの最後に`keyUsage = nonRepudiation, digitalSignature, keyEncipherment`を追加

### 2.　オレオレ証明書の生成
打ち間違えると怖いのでシェルスクリプトにしています（途中入力あり）。
```sh
 #!/bin/sh

echo "----- Backup openssl.cnf -----"
cp /etc/ssl/openssl.cnf ./
sudo cp san.cnf /etc/ssl/openssl.cnf

echo ""
echo "----- Generate key -----"
openssl genrsa -out private.key 4096
openssl req -new -x509 -days 365 -key private.key -sha256 -out cert.pem

 #　ここで入力が求められます。
 #　JP、都道府県名、市町村名、所属コミュニティ名、所属部署名、IP　の順で入力。
 #　所属部署名は空欄でもOK。他は有った方が後で証明書を認識するときに楽です。

 #　いじる前に戻します
echo ""
echo "----- Restore openssl.cnf -----"
sudo cp openssl.cnf /etc/ssl/openssl.cnf

echo ""
echo "----- Finished -----"
```
これで`private.key`と`cert.pem`が生成されました（有効期限は365日。意識高いですね！）。
これを後でJupyterLabの設定に使います。

### 3.　ローカルにオレオレ証明書を適用
**3-1.　ローカルPCにオレオレ証明書をコピー**
　　`scp user1@IPv4:~/myopenssl/cert.pem ./`

**3-2.　オレオレ証明書を開く**
　　macでは`open cert.pem`で開いた際に、キーチェーンアクセスというアプリが起動します。そこで表示される一覧の中でオレオレ証明書を見つけ、ダブルクリックで開きます。

**3-3. 常に信頼に設定する**
　信頼タブの中で、`この証明書を使用するとき：`を`常に信頼`にします。

# JupyterLabの設定
### 1.　設定ファイルの生成
`~/.jupyter/jupyter_lab_config.py`が既に存在するなら次へ。
無い場合は`jupyter lab --generate-config`を実行します。
### 2.　パスワード用ハッシュ値の生成
JupyterLabへのログインパスワードと対となるハッシュ値を生成します。
コンソールで`ipython`を起動し、passwd関数を実行。
```python
from IPython.lib import passwd
passwd()
```
入力が要求されるので、ログインパスワードを入力。
`sha1:なんたらかんたら`というハッシュ値が生成されるので、どこかに保存しておきます。

### 3.　JupyterLabの設定ファイルを編集
`~/.jupyter/jupyter_lab_config.py`を編集します。
以下の内容を末尾に追記です。
```
c = get_config()
c.ServerApp.certfile = '/home/user1/myopenssl/cert.pem'
c.ServerApp.keyfile = '/home/user1/myopenssl/private.key'
c.IPKernelApp.pylab = 'inline'
c.ServerApp.ip = '0.0.0.0'
c.ServerApp.open_browser = False
c.ServerApp.port = 9999
c.ServerApp.token = '好きなトークン'
c.ServerApp.password = 'sha1:なんたらかんたら'
```
- `c.ServerApp.certfile`と`c.ServerApp.keyfile`の部分は、`cert.pem`と`private.key`の絶対パス
- 好きなトークンの部分は英数字の羅列 (URLに使われます)
- passwordは先程生成したハッシュ値

### 4.　ローカルPCのブラウザにブクマ
JupyterLabへのURLは `https://IPv4:9999/lab?token=トークン` となります。
- IPv4：上で設定したIPv4（DNSなら~~~.com）
- トークン：上で設定した好きなトークン

### 5.　JupyterLabの起動＆ログイン
- サーバのコンソール：`jupyter lab`
- ローカルPCのブラウザ：ブクマしたリンクを踏み、パスワードを入力

サーバからログアウトしてもJupyterLabを起動しておきたいなら、`screen`コマンド開いた仮想ウィンドウ内で`jupyter lab`を実行します。
JupyterLabを終了するときは`Ctrl + C`した後にyを入力。

# 最後に
「よし、これでセキュアになった！」と満足してから気がつきましたが、そもそも内部サーバにはVPNを使ってアクセスしています。HTTPS化は不要だったのでは...？

いえ、コミュニティのVPN管理者にも通信内容を把握されなくなりますし、VPNもリスクが0な訳ではないので良かったのではないでしょうか、ハイ！

ということで、以上です。
セキュリティも関係していますし、何か間違い等あれば是非ともコメントをください。


__参考__
JupyterLabインストール - https://dev.classmethod.jp/articles/jupyterlab_mat_s3/
証明書の設定1 - https://kaede.jp/2018/06/10191854/
証明書の設定(マルチ) - https://rms.ne.jp/sslserver/csr/openssl-html/
証明書の設定2 - https://qiita.com/rimksky/items/0cb8cf2921d6b7cfe25e
証明書のコマンド - https://moewe-net.com/uncategorized/openssl-create-certificate
証明書・opensslコマンド集 - https://qiita.com/takech9203/items/5206f8e2572e95209bbc
JupyterLabの設定 - https://qiita.com/RayDoe/items/e1ec21c63a15adb1a061