iPadからVSCodeとJupyter Notebookを使う

# はじめに
iPad上で開発作業ができる環境を整えるために、Visual Studio Codeをブラウザ上で動作させることのできる[code-server](https://github.com/cdr/code-server)とPythonのコードなどをブラウザ上で実行できる[Jupyter Notebook](https://jupyter.org/)をサーバ上に構築します。

# できたもの
最初に本記事で出来るものの紹介です。iPadのWebブラウザ上で、VSCodeとJupyter Notebookを動作させています。
![vscode_jupyter_on_ipad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1423540/955d9702-bb01-e5d6-187f-e07c05a94e97.png)


# 構成
![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1423540/d1500c35-8955-7141-434a-edb5686733cd.png)

- [さくらのVPS](https://vps.sakura.ad.jp/)のCentOS 7マシンにDocker環境を構築しています。
- 今回は、Docker上にcode-serverとJupyter Notebookのコンテナを立てます。
- Docker上のアプリにアクセスするために、Dockerホストサーバ上にインストールしたApacheをリバースプロキシとして使い、Apache側で認証を行っています。認証に関しては、別記事にしているので以下をご参照ください。

https://qiita.com/mochi_yu2/items/239c1b4261bafece42f3

## 環境
- さくらのVPS
- CentOS 7.9
- Apache 2.4

# code-server
まずは、code-serverをDockerコンテナとして導入します。

https://hub.docker.com/r/codercom/code-server

上のDocker Hubの説明にしたがって、以下のコマンドで、設定ファイル用のフォルダを作成し、code-serverを起動します。
ここでは、ホスト側の`8050`ポートを割り当てます。VSCodeで作成するファイル保存用にホームディレクトリの`coder-project/`というディレクトリをマウントします。
また、認証はAuth0を使って行うため、code-server側は、`--auth=none`オプションで無効化します。

```console
mkdir -p ~/.config
mkdir -p ~/coder-project
docker run -d --name code-server -p 127.0.0.1:8500:8080 \
  -v "$HOME/.config:/home/coder/.config" \
  -v "$HOME/coder-project:/home/coder/project" \
  -u "$(id -u):$(id -g)" \
  -e "DOCKER_USER=$USER" \
  codercom/code-server:latest --auth=none
```

後のApacheの設定後に、PCのChromeで表示すると、ブラウザ上でVSCodeの画面が表示されました。
![vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1423540/aa695c70-6a28-f373-95d8-68ce4f1a368a.png)


<!--
認証をかける場合には、以下のようなオプションを指定します。
```console
mkdir -p ~/.config
docker run -i --name code-server -p 127.0.0.1:8601:8080 -v "$HOME/.config:/home/coder/.config" -v "$PWD:/home/coder/project" -u "$(id -u):$(id -g)" -e "DOCKER_USER=$USER" --env PASSWORD="my-strong-password" codercom/code-server:latest --auth=password
```
-->

#Jupyter Notebook
次にJupyter NotebookのDockerコンテナを立ち上げます。

https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html

https://jupyter-notebook.readthedocs.io/en/stable/config.html

上記のページを参考にして、以下のコマンドで起動します。
Jupyter Notebook用には、ホスト側の`8600`ポートを割り当て、作業用のフォルダとして、ホームディレクトリに作成する`jupyter-project`というフォルダをマウントします。
認証トークンを無効化するために、`--NotebookApp.token=''`を指定しておきます。

```console
mkdir -p ~/jupyter-project
docker run -d -v $HOME/jupyter-project:/home/jovyan/work -p 127.0.0.1:8600:8888 --name jupyter \
  --user root -e CHOWN_HOME=yes -e CHOWN_HOME_OPTS='-R' \
  jupyter/base-notebook start-notebook.sh --NotebookApp.token='' --NotebookApp.allow_origin='*'
```

PCのChromeで表示すると、Jupyter Notebookの画面が表示されました。
![jupyter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1423540/8a488be0-567b-0483-5b07-d01ec92b4f2a.png)


<!--
```console
docker run -d -v $(pwd)/work:/home/jovyan/work -p 127.0.0.1:8501:8888 --name jupyter-selenium jupyter-selenium start-notebook.sh --NotebookApp.allow_origin="*"
docker exec -it jupyter-selenium jupyter notebook list

docker run -d -v $(pwd):/home/jovyan/work -p 127.0.0.1:8600:8888 --name jupyter jupyter/base-notebook start-notebook.sh --user root -e CHOWN_HOME=yes -e CHOWN_HOME_OPTS='-R' --NotebookApp.allow_origin="*"
docker exec -it jupyter jupyter notebook list
```
-->

# Apache設定
リバースプロキシとして利用するApache側の設定を編集して、Docker上のcode-serverとJupyter Notebookのコンテナにプロキシするように設定します。

```apache:vhosts.conf
Listen 8443 https
ProxyRequests Off

# code-server用のVirtual Host設定
<VirtualHost *:8443>
    ServerName vscode.example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # Auth0の設定
    OIDCProviderMetadataURL https://dev-xxxxxx.jp.auth0.com/.well-known/openid-configuration
    OIDCClientID 9FIXXXXXXXXXXXXXXXX1HK
    OIDCClientSecret ylPyxxxxxxxxxxxxxxxxxxxxxxxym

    OIDCScope "openid name email"
    OIDCRedirectURI https://vscode.example.com:8443/redirect_uri/
    OIDCCryptoPassphrase xxxxxxxxxx 

    # WebSocketの通信をプロキシするための設定
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) "ws://127.0.0.1:8500/$1" [P,L]

    <Location />
        AuthType openid-connect
        Require valid-user
        LogLevel debug

        ProxyPass http://127.0.0.1:8500/
        ProxyPassReverse http://127.0.0.1:8500/
    </Location>
</VirtualHost>


# Jupyter Notebook用のVirtual Host設定
<VirtualHost *:8443>
    ServerName jupyter.example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # Auth0の設定
    OIDCProviderMetadataURL https://dev-xxxxxx.jp.auth0.com/.well-known/openid-configuration
    OIDCClientID 9FIXXXXXXXXXXXXXXXX1HK
    OIDCClientSecret ylPyxxxxxxxxxxxxxxxxxxxxxxxym

    OIDCScope "openid name email"
    OIDCRedirectURI https://jupyter.example.com:8443/redirect_uri/
    OIDCCryptoPassphrase xxxxxxxxxx

    # WebSocketの通信をプロキシするための設定
    RewriteEngine On
    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://127.0.0.1:8600/$1 [P,L]

    <Location />
        AuthType openid-connect
        Require valid-user
        LogLevel debug

        ProxyPreserveHost on
        ProxyPass  http://127.0.0.1:8600/
        ProxyPassReverse  http://127.0.0.1:8600/
    </Location>

</VirtualHost>
```

- 外部向けには、`8443`ポートを公開しています。
- 名前ベースのバーチャルホストを使って、`vscode.example.com`への通信をローカルホストの`8500`ポートのcode-serverのコンテナに、`jupyter.example.com`への通信をローカルホストの`8600`ポートのJupyter Notebookのコンテナにプロキシしています。
- code-server、Jupyter Notebookともに、WebSocketを利用していたためWebSocketの通信をプロキシするための設定を行っています。
  - 参考: [Apache Module mod_proxy_wstunnel](https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html) 

# 参考
本記事の作成にあたり、以下の記事を参考にさせていただきました。

https://qiita.com/cognitom/items/6d8af8a71552ec9c6212

https://jupyterhub.readthedocs.io/en/stable/reference/config-proxy.html