Nginx のリバースプロキシ設定

このノートでは、JupyterHub などのアプリを使うときに、Nginx でリバースプロキシ設定を行う方法をまとめています。

対象アプリは、JupyterHub、Streamlit、Code-Server、MyST、WebMO。

Nginx の設定項目

まず、Nginx の設定項目について。

server ブロック

server ブロックは、特定のドメイン名や IP アドレスに対してリクエストを処理するために使用。例えば、以下のように example.com の HTTP リクエストを処理する設定ができます。

server {
    listen 80;
    server_name example.com;

    location / {
        # リクエストをどのように処理するか指定
    }
}
  • listen 80;
    • サーバーが HTTP(ポート 80)でリクエストを受け付けることを示します。
      • 80: HTTP の標準ポート。
      • 443: HTTPS の標準ポート。SSL 設定を有効にする場合はポート 443 を使用。
  • server_name example.com;
    • このサーバーブロックが処理するドメインやサブドメインを指定。この例では、example.com というサブドメインにアクセスしたときにこのサーバーブロックを適用。
      • 複数のドメインを指定する場合は、スペースで区切って追加できます(例:server_name example.com www.example.com;)。

location ブロック

location ブロックは、特定のパス(URI)に対するリクエストをどのように処理するかを定義。

location / {
    # 指定されたパスに対するリクエストを処理
}
  • location / {}
    • ルートパス(/ から始まる全てのリクエスト)を処理。サブディレクトリや他のパス(例: /streamlit)を指定する場合、location /streamlit/ {} のように記述。

proxy_pass

proxy_pass は、リクエストを別のサーバー(バックエンド)に転送するために使用。リバースプロキシとして Nginx が機能する場合、この設定を使って、リクエストをバックエンドアプリケーション(例: Streamlit や JupyterHub)に転送します。

proxy_pass http://127.0.0.1:8501;
  • http://127.0.0.1:8501;
    • 127.0.0.1 はローカルホスト(自分自身)を指し、Streamlit アプリがポート 8501 で動作している場合に使用されます。
    • この設定により、外部のクライアントは example.com にアクセスし、実際には 127.0.0.1:8501 で動作している Streamlit アプリが応答。

proxy_set_header

proxy_set_header では、バックエンドサーバーに対して追加の HTTP ヘッダーを送信。これにより、元のクライアント情報などが保持されます。

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

    • クライアントの元々の IP アドレスをバックエンドサーバーに伝えるために使用。リバースプロキシを経由すると、バックエンドは Nginx の IP アドレスしか見えなくなりますが、この設定でクライアントの本当の IP を保持できます。
  • proxy_set_header Host $http_host;

    • クライアントがリクエストした元のホスト名(この例では example.com)をバックエンドサーバーに伝えます。これにより、バックエンドでホスト名に基づいた処理が正しく行われます。
  • proxy_http_version 1.1;

    • HTTP/1.1 プロトコルを使用してリクエストを転送することを指定。1.1 を指定することで、WebSocket のサポートなど、HTTP/1.0 では利用できない機能を使用できます。
  • proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";

    • WebSocket のサポートを有効に。これにより、HTTP プロトコルのアップグレードが可能になり、リアルタイム通信が必要なアプリ(例えば Streamlit や他の WebSocket を使用するアプリケーション)が正しく機能します。

rewrite(サブディレクトリの場合)

サブディレクトリを使用している場合、パスの書き換えを行うために rewrite を使用します。バックエンドアプリケーションがルートパス(/)で動作している場合、サブディレクトリパス(例: /streamlit/)を正しく処理するためにこの書き換えが必要。

rewrite ^/streamlit/(.*) /$1 break;
  • rewrite

    • location /streamlit/ のようなサブディレクトリでプロキシを使用する場合、Streamlit がパスに /stream/ が含まれることを想定していないため、リクエストパスを書き換える必要があります。
    • この書き換えでは、/streamlit/ 以下のパスを /$1(つまり / から始まる新しいパス)に変更し、サーバーが正しくリクエストを処理できるようにします。
  • 正規表現

    • ^/streamlit/(.*)^ はリクエストの先頭を示し、(.*)/stream/ 以下のすべてのパスをキャプチャ。
  • break

    • 書き換えが行われた後にそれ以上の処理を行わないことを指定。

return

return ディレクティブは、Nginx がクライアントに対して即座にレスポンスを返す場合に使用します。

return 301 https://$host$request_uri;
  • return 301
    • クライアントに対してリダイレクトを指示。301 は「恒久的なリダイレクト」を示し、SEO などの観点からも推奨されます。
    • https://$host$request_uri にリダイレクトすることで、HTTP でのリクエストを HTTPS にリダイレクト。
      • $host はリクエストのホスト名、$request_uri はリクエストされた URI(パス)。

その他の重要なディレクティブ

  • access_logerror_log
    • Nginx がアクセスログとエラーログを記録するファイルを指定。トラブルシューティングや分析に役立ちます。
access_log /var/log/nginx/streamlit.access.log;
error_log /var/log/nginx/streamlit.error.log;

各アプリケーションの設定方法

JupyterHub

サブドメインを使用する場合(例: jupyter.example.com

server {
    listen 80;
    server_name jupyter.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

サブディレクトリを使用する場合(例: example.com/jupyter

server {
    listen 80;
    server_name example.com;

    location /jupyter/ {
        rewrite ^/jupyter/(.*) /$1 break;
        proxy_pass http://127.0.0.1:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
  • JupyterHub は WebSocket を使用するため、Upgrade ヘッダーと Connection ヘッダーが必須。

Streamlit

サブドメインを使用する場合(例: streamlit.example.com

server {
    listen 80;
    server_name streamlit.example.com;

    location / {
        proxy_pass http://127.0.0.1:8501;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

サブディレクトリを使用する場合(例: example.com/streamlit

server {
    listen 80;
    server_name example.com;

    location /streamlit/ {
        rewrite ^/streamlit/(.*) /$1 break;
        proxy_pass http://127.0.0.1:8501/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
  • Streamlit も WebSocket をサポートしているため、Upgrade ヘッダーが必要。

Code-Server の設定

サブドメインを使用する場合(例: code.example.com

server {
    listen 80;
    server_name code.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }
}

サブディレクトリを使用する場合(例: example.com/code

server {
    listen 80;
    server_name example.com;

    location /code/ {
        rewrite ^/code(/.*)$ $1 break;
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }
}
  • Code-Server も WebSocket を使用するため、適切なヘッダー設定が必要です。

MyST(myst start

myst start コマンドでサーバーを起動し、それにアクセスする場合。

サブドメインを使用する場合(例: myst.example.com

server {
    listen 80;
    server_name myst.example.com;

    location / {
        proxy_pass http://127.0.0.1:4000;  # MyST が 4000 番ポートで動作していると仮定
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

サブディレクトリを使用する場合(例: example.com/myst

server {
    listen 80;
    server_name example.com;

    location /myst/ {
        rewrite ^/myst/(.*) /$1 break;
        proxy_pass http://127.0.0.1:4000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
  • myst start コマンドを使用してサーバーを起動した後、そのポート(例: 4000)に対してリバースプロキシを設定。

WebMO

WebMO は CGI を使用しているため、少し異なる設定が必要。

サブドメインを使用する場合(例: webmo.example.com

server {
    listen 80;
    server_name webmo.example.com;

    root /home/webmo/public_html;
    index index.html index.php;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~ \.cgi$ {
        root /home/webmo/cgi-bin;
        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        fastcgi_param SCRIPT_FILENAME /var/www/webmo/cgi-bin$fastcgi_script_name;
        include fastcgi_params;
    }
}

サブディレクトリを使用する場合(例: example.com/webmo

server {
    listen 80;
    server_name example.com;

    location /webmo/ {
        rewrite ^/webmo/(.*) /$1 break;
        root /var/www/webmo/public_html;
        index index.html index.php;

        try_files $uri $uri/ /index.html;
    }

    location ~ /webmo/.*\.cgi$ {
        root /var/www/webmo/cgi-bin;
        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        fastcgi_param SCRIPT_FILENAME /var/www/webmo/cgi-bin$fastcgi_script_name;
        include fastcgi_params;
    }
}
  • WebMO では fcgiwrap を使用して CGI スクリプトを実行します。
  • サブディレクトリの場合、WebMO が cgi-bin ディレクトリ内のスクリプトを正しく実行できるように rewriteroot 設定を調整。

設定ファイルの有効化

設定ファイルを有効にするために、/etc/nginx/sites-enabled/ にシンボリックリンクを作成します。

sudo ln -s /etc/nginx/sites-available/streamlit /etc/nginx/sites-enabled/

Nginx 設定のテストと再起動

Nginx 設定をテストし、正しく設定されているか確認。

sudo nginx -t

問題がなければ、Nginx を再起動。

sudo systemctl restart nginx

サブドメイン vs サブディレクトリ

サブドメインの場合

  • サブドメインごとに異なるサービスを独立して管理することができます。
  • 各サブドメインに SSL 証明書を適用することが容易。

サブディレクトリの場合

  • 一つのドメイン内に複数のサービスを提供する場合に便利。
  • パスの書き換え(rewrite)が必要な場合があります。
Posted :