一般的に Jupyter Notebook はローカルの環境にインストールして使うことが多い。 ただ、ローカルの環境は計算資源が乏しい場合もある。 そんなとは IaaS などリモートにあるサーバで Jupyter Notebook を使いたい場面が存在する。 ただ、セキュリティのことを考えると Jupyter Notebook の Web UI をインターネットに晒したくはない。
そこで、今回は SSH Port Forwarding を使って Web UI をインターネットに晒すことなく使う方法について書く。 このやり方ならリモートサーバに SSH でログインしたユーザだけが Jupyter Notebook を使えるようになる。 また、Web UI との通信も SSH 経由になるので HTTP over SSL/TLS (HTTPS) を使わなくても盗聴のリスクを下げられる。
Jupyter Notebook をインストールする先の環境は次の通り。 話を単純にするために環境は Vagrant で作ってある。
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS" $ uname -r 4.15.0-29-generic
必要なパッケージをインストールする
ここからは、すでにリモートの Ubuntu マシンに SSH でログインしている前提で話を進める。
まずは必要なパッケージをインストールする。 ログインするたびに Jupyter Notebook を起動するコマンドを入力するのも面倒なので Supervisord でデーモン化することにした。
$ sudo apt-get update $ sudo apt-get -y install jupyter-notebook supervisor
今回は OS のパッケージ管理システム経由でインストールしてるけど pip を使うとかはお好みで。
アクセス制御をかける
リモートサーバを想定しているので、念のため必要なポート以外はファイアウォールを使って閉じておく。
SSH に使うポートだけを残して、それ以外は全て閉じる。 SSH に使うポート番号を 22 以外にしているときは、適宜読み替える感じで。
$ sudo ufw allow 22 $ sudo ufw default DENY $ yes | sudo ufw enable $ sudo ufw status Status: active To Action From -- ------ ---- 22 ALLOW Anywhere 22 (v6) ALLOW Anywhere (v6)
ファイアウォールの設定を変更するときはリモートサーバから追い出されないように注意しよう。
Jupyter Notebook を起動するユーザを追加する
若干好みの問題にも近いけど、念のため Jupyter Notebook を起動する専用のユーザを追加しておく。
$ sudo useradd -m -s $SHELL jupyter
Jupyter Notebook を設定する
ここからは Jupyter Notebook を設定していく。
まずは先ほど作ったユーザにログインする。
$ sudo su - jupyter
続いて、設定ファイルを生成する。
$ jupyter notebook --generate-config Writing default config to: /home/jupyter/.jupyter/jupyter_notebook_config.py
Jupyter Notebook の作業ディレクトリを用意する。
$ mkdir -p /home/$(whoami)/jupyter-working
設定ファイルを編集する。
$ sed -i.back \ -e "s:^#c.NotebookApp.token = .*$:c.NotebookApp.token = u'':" \ -e "s:^#c.NotebookApp.ip = .*$:c.NotebookApp.ip = 'localhost':" \ -e "s:^#c.NotebookApp.open_browser = .*$:c.NotebookApp.open_browser = False:" \ -e "s:^#c.NotebookApp.notebook_dir = .*$:c.NotebookApp.notebook_dir = '/home/$(whoami)/jupyter-working':" \ /home/$(whoami)/.jupyter/jupyter_notebook_config.py $ cat ~/.jupyter/jupyter_notebook_config.py | sed -e "/^#/d" -e "/^$/d" c.NotebookApp.ip = 'localhost' c.NotebookApp.notebook_dir = '/home/jupyter/jupyter-working' c.NotebookApp.open_browser = False c.NotebookApp.token = u''
それぞれの設定の内容や意図としては以下のような感じ。
- c.NotebookApp.ip = 'localhost'
- Jupyter Notebook が Listen するアドレスをループバックアドレスにする
- もしファイアウォールがなくてもインターネットからは Jupyter Notebook の WebUI に疎通がなくなる
- c.NotebookApp.notebook_dir = '/home/jupyter/jupyter-working'
- Jupyter Notebook の作業ディレクトリを専用ユーザのディレクトリにする
- 仮に Web UI が不正アクセスを受けたときにも影響範囲を小さくとどめる (気休め程度)
- c.NotebookApp.open_browser = False
- 起動時にブラウザを開く動作を抑制する
- ローカル環境ではないので起動するときにブラウザを起動する必要はない
- c.NotebookApp.token = u''
- Jupyter Notebook の Web UI にビルトインで備わっている認証を使わない
- 認証は SSH によるログインで担保する場合の設定 (心配なときは後述する共通パスワードなどを設定する)
(オプション) Jupyter Notebook の Web UI に共通パスワードをかける
SSH のログイン以外にも認証をかけたいときは、例えばシンプルなものだと共通パスワードが設定できる。
Jupyter Notebook の Web UI に共通パスワードをかけるには jupyter notebook password
コマンドを実行する。
$ jupyter notebook password Enter password: Verify password: [NotebookPasswordApp] Wrote hashed password to /home/jupyter/.jupyter/jupyter_notebook_config.json
すると、ソルト付きの暗号化されたパスワードが設定ファイルとしてできる。
$ cat ~/.jupyter/jupyter_notebook_config.json { "NotebookApp": { "password": "sha1:217911554b0b:f2fa9cd9f336951c335bdaa06a6c16eb6286c192" } }
上記のやり方だとハッシュのアルゴリズムが SHA1
固定っぽい。
もし、より頑丈なものが使いたいときは次のように Python のインタプリタ経由で生成する。
$ python3 Python 3.6.6 (default, Sep 12 2018, 18:26:19) [GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from notebook.auth import passwd >>> passwd('jupyter-server-password', algorithm='sha512') 'sha512:d197670d2987:19bb2eedfc6fde56f1a9fc04d403999c3f03a99af368e528f45ee9a68f01a7c5f07e375bd34ec176d1c66a0f2e8ef7615ebcf9e524a23ace5ab6dd5a930398d4'
生成した暗号化済みパスワードを、次のような形で Jupyter Notebook の設定ファイルに入力すれば良い。
c.NotebookApp.password = u'sha512:d197670d2987:19bb2eedfc6fde56f1a9fc04d403999c3f03a99af368e528f45ee9a68f01a7c5f07e375bd34ec176d1c66a0f2e8ef7615ebcf9e524a23ace5ab6dd5a930398d4'
上記の共通パスワード方式を含む Jupyter Notebook の認証周りについては以下の公式ドキュメントを参照のこと。
Running a notebook server — Jupyter Notebook 5.7.0 documentation
Jupyter Notebook を Supervisord 経由で起動する
続いては Jupyter Notebook をデーモン化する設定に入る。
一旦、元の管理者権限をもったユーザに戻る。
$ exit logout
Supervisord の設定ファイルを用意する。
$ cat << 'EOF' | sudo tee /etc/supervisor/conf.d/jupyter.conf > /dev/null [program:jupyter] command=jupyter notebook user=jupyter stdout_logfile=/var/log/supervisor/jupyter.log redirect_stderr=true autostart=true autorestart=true EOF
Supervisord を起動する。
$ sudo systemctl enable supervisor
$ sudo systemctl reload supervisor
ちゃんと Jupyter Notebook が起動しているかを確認する。
$ ps auxww | grep [j]upyter jupyter 4689 27.0 5.4 183560 55088 ? S 16:31 0:01 /usr/bin/python3 /usr/bin/jupyter-notebook $ ss -tlnp | grep :8888 LISTEN 0 128 127.0.0.1:8888 0.0.0.0:* LISTEN 0 128 [::1]:8888 [::]:*
もし、上手く立ち上がっていないときはログから原因を調べよう。
$ sudo tail /var/log/supervisor/supervisord.log $ sudo tail /var/log/supervisor/jupyter.log
SSH Port Forwarding 経由で Jupyter Notebook の Web UI にアクセスする
ここまでで、リモートサーバ上の Jupyter Notebook の設定は終わった。
一旦リモートサーバから SSH でログアウトする。
$ exit
改めて SSH Port Forwarding を有効にしてリモートサーバにログインする。
このときリモートサーバの TCP:8888
ポートを、ローカルホストのポートにマッピングする。
ユーザ名やホスト名は適宜読み替える。
$ ssh -L 8888:localhost:8888 <username>@<remotehost>
今回は Vagrant の環境を使っているので、手っ取り早くは以下のようにすると良い。
恒久的に対応するときは Vagrantfile
を編集してポートフォワーディングの設定を入れる。
$ vagrant ssh-config > ssh.config $ ssh -L 8888:localhost:8888 -F ssh.config default
あとは、ローカルマシンのブラウザでローカルホストにマッピングしたポート番号を開く。
$ open http://localhost:8888
すると、見覚えのある Web UI が表示される。
あとは、もしポータビリティとかを考えるのであればお好みで Docker イメージとかにする感じで。
めでたしめでたし。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る