WordPressとPython(FastAPI/Uvicorn)を同一ドメインで共存させるNginxリバースプロキシ設計

この記事は約13分で読めます。
この記事が役立ったらブックマーク! あとで読み返したり、環境構築時のリファレンスに活用できます
B! はてなブックマークに追加

Webサイトのメインコンテンツやブログ機能は扱い慣れたWordPress(PHP-FPM)で運用しつつ、高度な独自検索機能、機械学習モデルの推論、軽量APIなどはPython(FastAPI / Uvicorn)で高速に処理したいという要件は少なくありません。
しかし、別ドメイン(例: api.example.com)に切り分けると、CORS(オリジン間リソース共有)の設定やCookie・セッション共有の煩雑さ、SEO的なドメイン評価の分散といった問題がつきまといます。

本記事では、同一ドメイン(例: example.com)のまま、ルートや通常のWebページはWordPressへ、特定のパス(/search や /api)配下のみをポート8000で常駐するUvicornへ安全に中継するNginxリバースプロキシの設計手順を解説します。

1. アーキテクチャの概要

全体の通信トラフィックはすべてフロントに立つ Nginx がポート443(HTTPS)で受け止め、URLパスのパターンに応じて内部の適切なバックエンドへルーティングします。

Plaintext
                 [ブラウザ]
                     │
                     │ (HTTPS)
                     ▼
                  [Nginx]
                     │
     ┌───────────────┴────────────────┐
     │                                │
     ▼                                ▼
[/ (通常アクセス)]             [/search /api (特定パス)]
     │                                │
     │ (UNIX Domain Socket)           │ (HTTP: 127.0.0.1:8000)
     ▼                                ▼
 [PHP-FPM]                        [Uvicorn]
     │                                │
     ▼                                ▼
[WordPress]                       [FastAPI]
  • WordPress(PHP-FPM):UNIXドメインソケット通信で接続し、オーバーヘッドを最小化。
  • FastAPI(Uvicorn):ローカルホスト(127.0.0.1:8000)限定でリッスン。外部インターネットからのポート直接アクセスを遮断し、必ずNginx経由でSSL終端された通信のみを受け入れます。

2. Nginx設定(nginx.conf)の実装例

サイト用のバーチャルホスト設定ファイル(例: /etc/nginx/sites-available/example.com)に、Pythonアプリへ流す location ブロックを追加します。

Nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    root /var/www/example.com/htdocs;
    index index.php index.html;

    # SSL証明書設定(省略)
    # ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # --------------------------------------------------
    # 1. Python (FastAPI / Uvicorn) へのリバースプロキシ
    # --------------------------------------------------
    # /search または /api 配下へのリクエストをポート8000へ流す
    location ~* ^/(search|api)(/.*)?$ {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;

        # WebSocketや長時間のストリーミング(SSE)対応
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # クライアントの正確なIPやプロトコル情報をFastAPI側へ引き渡す
        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_connect_timeout 60s;
        proxy_read_timeout 120s;
    }

    # --------------------------------------------------
    # 2. WordPress (静的ファイル & PHP-FPM)
    # --------------------------------------------------
    # 通常の静的アセットやパーマリンクのルーティング
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # PHPスクリプトの実行
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # セキュリティ: .htや隠しファイルへのアクセス拒否
    location ~ /\. {
        deny all;
    }
}

3. 実装時にハマりやすい3つの注意点

① root_path(URLプレフィックス)の扱い

FastAPI側でエンドポイントを定義する際、Nginxがパスをそのまま渡す(/search や /api/items)設計にするか、プレフィックスを取り除くかを決めておく必要があります。

FastAPI側で直接プレフィックスを認識させる場合、アプリ初期化時に root_path を設定すると、Swagger UI(/docs)のパス解決が狂いません。

Python
from fastapi import FastAPI

# Nginxで /search 配下をプロキシする場合
app = FastAPI(root_path="/search")

@app.get("/")
def read_root():
    return {"message": "Search API is running"}

② WordPressのパーマリンク(try_files)との衝突回避

Nginxの評価順序において、location ~* ^/(search|api) のような正規表現ブロックは、一般的なプレフィックスマッチ(location /)よりも優先されます。

これにより、WordPress側に「search」というスラッグを持つ固定ページやカテゴリーが存在しても、Nginxが先に拾ってPython側へリクエストを転送します。WordPress側で同じURLスラッグを二重作成しないよう運用ルールを整理しておきましょう。

③ Uvicornの安全な常駐化(systemd)

Pythonアプリはバックグラウンドプロセスとして放置するのではなく、systemd でデーモン化してOS再起動時にも自動起動するように構成します。

/etc/systemd/system/my-search-app.service の作成例:

INI
[Unit]
Description=FastAPI Search Application
After=network.target

[Service]
User=root
WorkingDirectory=/root/my-search-app
ExecStart=/root/my-search-app/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
Bash
# 反映と起動
sudo systemctl daemon-reload
sudo systemctl enable --now my-search-app

4. 設定反映と動作確認

設定ファイルの文法をチェックしてからNginxをリロードします。

Bash
# 構文チェック
sudo nginx -t

# 反映
sudo systemctl reload nginx
  • https://example.com/ にアクセスしてWordPressが正常に表示されるか
  • https://example.com/search にアクセスしてFastAPIのレスポンス(JSON等)が返ってくるか
  • curl -I https://example.com/search でHTTPステータス200が確認できるか

これらを確認し、双方から想定通りの応答が返ってくれば共存環境の完成です。

まとめ

Nginxをリバースプロキシとして配置することで、「CMSとしてのWordPress運用の手軽さ」 と 「Pythonによる高速・柔軟なバックエンド開発」 の長所を同一ドメイン上で両立できます。

  • 同一ドメイン運用の恩恵(CORS問題の回避、SSL証明書の一元管理、SEO資産の集中)
  • location ブロックによる安全なパス分割
  • Uvicornの 127.0.0.1 バインドとsystemd常駐による堅牢性

既存のWordPressサイトに独自の検索ロジックやAI・データ処理APIを無理なく後付けしたい場合に、最も扱いやすいインフラ構成パターンです。

コメント

タイトルとURLをコピーしました