【WSL2/Ubuntu対応】Nginxリバースプロキシ導入ガイド(単一ポートで複数C++エンジンを公開)
0. はじめに:なぜNginxが必要か?
WSL2環境で、job_1、job_2、job_3...といった複数のC++製APIエンジンを起動すると、それぞれがlocalhost:8001、localhost:8002、localhost:8003のように異なる内部ポートで待ち受けることになります。
これら全てに外部(インターネット)からアクセスするために、ルーターのポートを何千個も開放するのは非現実的で、セキュリティ上も危険です。
この記事では、Nginx(エンジンエックス)をリバースプロキシとしてWSL内に導入します。
これにより、外部からはたった1つのAPI用ポート(例: 1721)にアクセスするだけで、NginxがURLパス(例: /job_27/predict)を賢く解析し、**内部の正しいC++エンジン(localhost:8027)**にリクエストを自動で振り分ける環境を構築します。
この記事で使う仮名(ダミー)情報
-
あなたのWSLユーザー名:
myuser -
あなたのグローバルIP:
123.45.67.89(ルーターに表示されるダミーIP) -
あなたのWSL2のIP:
172.25.100.50(WSLが持つダミーの内部IP) -
SSH用外部ポート:
1720(あなたが管理用に別途設定済みのポート) -
API用外部ポート(新規):
1721(今回Nginx用に新しく使うポート) -
Nginxポート (内部):
80(WSL内でNginxが待つポート) -
C++エンジンポート (内部):
8001,8002,8027... (C++エンジンが待つポート) -
C++エンジンポート計算式:
8000 + (Job ID)
ステップ1: API用ポートの確保 (ルーター設定)
まず、Nginxが外部からの通信を受け取るための「玄関」を用意します。SSH用の1720番ポートとは別に、API用の新しいポート1721番をルーターに設定します。
【ルーターの管理画面 (http://192.168.1.1 など) での操作】
ご自宅のルーター設定(OCNバーチャルコネクトなど)に従い、以下の2つの設定を追加します。
-
IPフィルター (パケットフィルター):
-
動作:
通過(または許可) -
方向:
Internet->LAN -
IPアドレス (送信元):
すべて -
プロトコル:
TCP/UDP -
任意のTCP/UDPポート:
1721 - ルールを追加します。
-
動作:
-
ポート変換(ポートフォワーディング):
-
外部ポート (WAN側):
1721 -
内部IPアドレス:
172.25.100.50(あなたのWSL2のIPアドレス) -
内部ポート (LAN側):
80(NginxがWSL内で待ち受ける標準ポート) - ルールを追加し、
ONにします。
-
外部ポート (WAN側):
これで、外部(123.45.67.89)の1721番ポートに来たHTTPリクエストは、すべてWSLのNginx(ポート80)に転送されるようになりました。
ステップ2: NginxとLuaモジュールのインストール (修正版)
Nginxで「/job_27 $\to$ 8027」のような動的なポート計算(8000 + ID)を行うには、標準のNginxでは力不足です。
計算処理(Luaスクリプト)を実行できる高機能版Nginx(nginx-extras)と、そのLuaモジュール本体をインストールします。
【WSLターミナル (myuser@...:~$) で実行】
sudo apt update
# 高機能版Nginxと、Luaモジュール本体を「同時に」インストール
sudo apt install -y nginx-extras libnginx-mod-http-lua
【修正理由】
nginx-extrasだけではrewrite_by_lua_blockディレクティブが認識されずエラーになるため、libnginx-mod-http-luaパッケージの明示的なインストールが必須です。
ステップ3: Nginx リバースプロキシの設定 (vimを使用)
Nginxに「URLを解析してポートを計算し、転送する」という設定ファイル(agenthub_proxy)を作成します。
-
vimで設定ファイルを作成します。sudo vim /etc/nginx/sites-available/agenthub_proxy -
(
vimが開きます)キーボードの**i** キーを押して「挿入モード」に入ります。(画面左下に-- INSERT --と表示されます) -
以下の設定をそのまま貼り付けてください。
- この設定が、
/job(ID)/...$\to$localhost:(8000 + ID)/...の振り分けを実現します。
server { # ステップ1でルーターから転送されてくるポート listen 80; server_name _; # タイムアウト設定 (AIの推論は時間がかかるため長めに設定) proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; # /job(ID)/(残りのパス) にマッチするすべてのリクエスト # 例: /job27/predict location ~ ^/job(?<job_id>\d+)(?<path>/.*)?$ { # --- Luaによる動的ポート計算 --- # $job_id (例: "27") を使って $target_port (例: 8027) を計算 set $target_port 0; # 初期化 rewrite_by_lua_block { -- 1. URLからキャプチャしたJob IDを取得 (例: "27") local job_id_str = ngx.var.job_id; if job_id_str then -- 2. 数値に変換 local job_id_num = tonumber(job_id_str); if job_id_num then -- 3. C++エンジンと同じ計算式でポートを算出 -- (8001 + (ID - 1) は 8000 + ID と同じ) local calculated_port = 8000 + job_id_num; -- 4. Nginxの変数にポート番号をセット ngx.var.target_port = calculated_port; end end } # --- 計算完了 --- # $path が空の場合(例: /job27)、デフォルトで /health に飛ばす set $final_path $path; if ($final_path = "") { set $final_path "/health"; } # 計算結果のポート (例: 8027) にリクエストを転送(プロキシ) # 例: http://127.0.0.1:8027/predict proxy_pass http://127.0.0.1:$target_port$final_path; # 必要なヘッダーをC++エンジンに渡す 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; } } - この設定が、
-
貼り付けたら、キーボードの**
Esc** キーを押して「ノーマルモード」に戻ります。(-- INSERT --が消えます) -
:wqと入力し、Enterキーを押します。(:w= 保存,:q= 終了)
ステップ4: Nginxサービスの有効化と再起動
作成した設定ファイル(sites-available)を、Nginxが読み込む場所(sites-enabled)にリンクします。
# 1. デフォルト設定(sites-enabled/default)は競合するため無効化
sudo rm -f /etc/nginx/sites-enabled/default
# 2. 今作った設定を有効化
sudo ln -s /etc/nginx/sites-available/agenthub_proxy /etc/nginx/sites-enabled/agenthub_proxy
# 3. Nginxの設定に文法ミスがないかテスト
sudo nginx -t
# ( "syntax is ok" と "test is successful" と表示されればOK )
# 4. Nginxを再起動して設定を読み込ませる
sudo systemctl restart nginx
# 5. Nginxが起動しているか確認
sudo systemctl status nginx
-
Active: active (running)と表示されていれば成功です。
ステップ5: 最終テスト(外部からのAPI実行)
C++エンジン(例: job_27、内部ポート8027)が起動している状態で、外部のPCまたはWSLとは別のWindowsターミナルから、**新しいAPIポート(1721)**を使ってAPIを叩きます。
テスト1: 生存確認 (job_27)
# 外部からポート1721の /job27/health を叩く
curl http://123.45.67.89:1721/job27/health
期待する結果: OK
(Nginxがこのリクエストを http://127.0.0.1:8027/health に正しく転送してくれた証拠です)
テスト2: 推論実行 (job_27)
# 外部からポート1721の /job27/predict を叩く
curl -X POST -H "Content-Type: application/json" -d '{"prompt": "This is a test prompt."}' http://123.45.67.89:1721/job27/predict
期待する結果: C++エンジンからの推論結果JSON
{"results":[{"method":"...","similarity":"..."}, ...],"start_time":"...","end_time":"...","power":null}
これが成功すれば、あなたは外部の単一ポート(1721)経由で、WSL内の無数のC++エンジンすべてにアクセスできるようになったことになります。
ネットワーク全体の流れ(概念図)
[ 外部のあなた (例: myuser@client) ]
|
| (1) APIリクエスト
| http://123.45.67.89:1721/job27/predict
|
[ (インターネット) ]
|
[ あなたの家のルーター (グローバルIP: 123.45.67.89) ]
|
| (2) IPフィルター: ポート 1721 を許可 (通過)
|
| (3) ポート変換: 1721 -> WSL (172.25.100.50:80) へ転送
|
[ Windowsホスト (192.168.1.100) ]
|
+---- [ WSL2 (Ubuntu) (IP: 172.25.100.50) ] ---------------------------+
| | |
| | (4) Nginxがポート80でリクエストを受け取る |
| | Nginx (agenthub_proxy.conf) |
| | - URLが /job27/predict であることを解析 |
| | - Luaがポートを計算: 8000 + 27 = 8027 |
| | |
| | (5) Nginxが内部のC++エンジンにリクエストを転送 |
| | http://127.0.0.1:8027/predict |
| | |
| +---- [ C++ Engine (job_27) (localhost:8027) ] <----+ |
| | | | (自動デプロイ)
| | +------------------------------------------+ |
| | |
| +---- [ C++ Engine (job_1) (localhost:8001) ] ... |
| | |
| +---- [ C++ Watcher (agenthub-watcher.service) ] ----------+ |
| | ( /home/myuser/AgentHubStorage/models を監視 ) | |
| +----------------------------------------------------------+ |
| |
+-------------------------------------------------------------------+