介紹如何在 Ubuntu Linux 中設定以 systemd 啟動 Jupyter Notebook,並透過 Nginx 的反向代理(reverse proxy)讓外部使用者使用 Jupyter Notebook。

這裡我們希望在 Ubuntu Linux 系統上以 systemd 自動啟動 Jupyter Notebook,這個內部 Jupyter Notebook 在啟動後會傾聽 127.0.0.1:8888 這個本機位址,然後我們再透過 Nginx 的反向代理讓外部使用者連線進來使用,另外為了讓 Jupyter Notebook 的網址可以跟原本 Nginx 的網頁有所區隔,我們希望 Jupyter Notebook 可以放在 https://my.domain.com/jupyter/ 這樣的網址之下,不要影響原本網站的內容,以下是設定的流程與步驟。

設定 Jupyter Notebook 啟動參數

使用以下指令,產生一份 Jupyter Notebook 設定檔範本:

# 產生 Jupyter Notebook 設定檔
jupyter-notebook --generate-config
Writing default config to: /home/myuser/.jupyter/jupyter_notebook_config.py

新產生的設定檔預設放在家目錄下的 ~/.jupyter/jupyter_notebook_config.py,編輯此設定檔,依照自己的需求調整參數,以下是一個簡單的範例:

# 允許遠端存取
c.NotebookApp.allow_remote_access = True

# URL 根目錄
c.NotebookApp.base_url = '/jupyter'

# 系統根目錄
c.NotebookApp.notebook_dir = '/mnt/data/work'

# 不開啟瀏覽器
c.NotebookApp.open_browser = False

# 停用密碼與權杖認證
c.NotebookApp.password = ''
c.NotebookApp.token = ''

這裡的 allow_remote_access 參數是設定是否允許 Jupyter Notebook 被遠端存取,由於我們會透過 Nginx 反向代理存取 Jupyter Notebook,所以這裡必須設定為 True。URL 根目錄的設定要與 Nginx 反向代理的內部 Jupyter Notebook 網址對應。其餘選項可依自己的需求修改。

Systemd 啟動 Jupyter Notebook

新增一個 /etc/systemd/system/jupyter-notebook.service 設定檔,內容如下:

[Unit]
Description=Jupyter Notebook
After=syslog.target network.target

[Service]
Type=simple

# PID 檔案位置
PIDFile=/run/jupyter-notebook.pid

# 啟動指令
ExecStart=/home/myuser/myenv/bin/jupyter-notebook --config=/home/myuser/.jupyter/jupyter_notebook_config.py

# 執行 Jupyter notebook 的使用者與群組
User=myuser
Group=mygroup

# 工作目錄
WorkingDirectory=/mnt/data/work

# 自動重新啟動
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

這裡的 ExecStart 參數要指定 Jupyter Notebook 的啟動指令,jupyter-notebook 指令的所在路徑可以使用 which 指令查詢:

# 查詢 jupyter-notebook 指令路徑
which jupyter-notebook
/home/myuser/myenv/bin/jupyter-notebook

jupyter-notebook 指令所附加的 --config 參數要指定為上面我們修改好的 Jupyter Notebook 設定檔。

接著重新載入 systemd 設定檔,設定開機自動啟動 Jupyter Notebook 服務,同時將 Jupyter Notebook 服務啟動:

# 重新載入設定檔
sudo systemctl daemon-reload

# 設定開機自動啟動 Jupyter Notebook 服務
sudo systemctl enable jupyter-notebook.service

# 啟動 Jupyter Notebook 服務
sudo systemctl start jupyter-notebook.service

Nginx 反向代理設定

設定好 systemd 啟動 Jupyter Notebook 服務之後,接著要設定 Nginx 的反向代理,讓外部使用者透過 Nginx 連線至 Jupyter Notebook。

編輯 Nginx 網站的設定檔(例如 /etc/nginx/sites-available/default),先在 server 區塊之前加入一段 WebSocket 標頭的設定,然後在 server 區塊中加入一段 Jupyter Notebook 的反向代理設定,完整的設定範例如下:

# WebSocket 標頭的頂層 http 設定
# If Upgrade is defined, Connection = upgrade
# If Upgrade is empty, Connection = close
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {

    # ...

    # Jupyter Notebook 設定
    location /jupyter/ {
        # 內部 Jupyter Notebook 網址
        proxy_pass http://127.0.0.1:8888/jupyter/;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # WebSocket 標頭
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Scheme $scheme;

        proxy_buffering off;

    }

}

這裡 proxy_pass 所指定的內部 Jupyter Notebook 網址,必須與 Jupyter Notebook URL 根目錄(NotebookApp.base_url)設定相同。proxy_http_version 必須指定為 1.1,如果沒有加上這一行,Jupyter Notebook 在使用時會發生不斷重複連線 kernel 的問題。

修改完成後,測試 Nginx 的設定檔:

# 測試 Nginx 設定檔
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

若沒有出現錯誤,即可重新啟動 Nginx 網頁服務:

# 重新啟動 Nginx 服務
sudo systemctl restart nginx

這時候用瀏覽器開啟 https://my.domain.com/jupyter/ 這樣的外部網址,就可以透過 Nginx 的反向代理存取內部的 Jupyter Notebook 了。

參考資料