#0026（2024/01/26）Nginx<->uWSGI<->Flask

# Nginx<->uWSGI<->Flask

**Web ブラウザ**からの HTTP リクエストを受け取って **Flask** アプリケーションに処理を渡す流れ

```
(ブラウザ)
   ↓
(Nginx)
   ↓   (uWSGIプロトコル)
(uWSGI)
   ↓
(Flaskアプリ)
```


## 1. Nginx の設定

### Nginx から uWSGI への連携設定

Nginx 側では、`server` ブロックの中で `location` ディレクティブを使ってリクエストをどこへ転送するか設定します。典型的には次のようになります。（パスやファイル名は例です。）

```nginx
# /etc/nginx/conf.d/myapp.conf (あるいは sites-available/myapp.conf など)
server {
    listen 80;
    server_name example.com;  # ドメインまたはIP

    location / {
        include uwsgi_params;                    # uWSGIのパラメータを読み込む
        uwsgi_pass unix:///path/to/yourapp.sock; # uWSGIに転送するソケットパス
    }
}
```

- `server_name`  
  - このサーバブロックがどのドメインまたは IP を扱うか指定します。  
- `location /`  
  - ルートパス(`"/"`)へのアクセスをどう処理するか定義します。  
- `include uwsgi_params;`  
  - uWSGI のデフォルトパラメータをインクルードしています。HTTPヘッダなど必要な情報を uWSGI に渡すために使います。  
- `uwsgi_pass unix:///path/to/yourapp.sock;`  
  - uWSGI によって作成される Unix ソケットファイル（あるいは TCP ソケット）を指定します。ここでは例として Unix ソケットを使用しています。

### Unix ソケット vs TCP ソケット

- **Unix ソケット（`unix:///path/to/yourapp.sock`）**  
  - 同じサーバ内で Nginx と uWSGI をやり取りする場合によく使われます。ファイルパスの指定になるのでパーミッション設定に注意が必要です。  
- **TCP ソケット（`127.0.0.1:8000` など）**  
  - 複数サーバ間で通信する場合などに使われます。

## 2. uWSGI の設定

### uWSGI での Flask アプリ結合

Nginx から渡されたリクエストを受け取るのが uWSGI です。uWSGI は WSGI (Python 用ウェブサーバゲートウェイインタフェース) を実装しており、Flask などの WSGI アプリケーションを動かせます。

uWSGI の設定は、以下のような `ini` ファイルや `yaml` ファイルなどで行われることが多いです。例えば `uwsgi.ini` という名前で用意したとします。

```ini
[uwsgi]
# Flaskアプリをロードするためのモジュール(エントリーポイント)
module = wsgi:app

# masterプロセスを使うかどうか
master = true

# ワーカープロセス数
processes = 5

# Unixソケットで待ち受ける場合
socket = /path/to/yourapp.sock
chmod-socket = 660

# プロセス終了時などにソケットを消す
vacuum = true

# masterプロセス終了時にきれいに停止する
die-on-term = true
```

- `module = wsgi:app`  
  - ここで指定している「`wsgi:app`」は、「`wsgi.py` というファイルの中にある `app` という名前の WSGI アプリケーション」を意味しています。  
  - 例えば Flask の場合、`wsgi.py` の中で `app = Flask(__name__)` のように定義したものを指すことが多いです。  
- `socket = /path/to/yourapp.sock`  
  - 上述の Nginx 設定で指定したソケットパスと一致させます。  
- `chmod-socket = 660`  
  - ソケットファイルのパーミッションです。Nginx から読み書きができるようにする必要があります。  

### wsgi.py (あるいは main.py など)

Flask アプリを uWSGI や Gunicorn といった WSGIサーバから読み込ませるために、エントリーポイントが必要になります。典型的には `wsgi.py` というファイルを用意し、そこに Flask アプリを作成するコードを書きます。

```python
# wsgi.py
from myapp import create_app  # 自分のFlaskアプリのファクトリ関数をインポートする場合など
# あるいは from flask import Flask; app = Flask(__name__)

app = create_app()  # Flaskアプリケーションを初期化
```

ここで定義された `app` という変数が、先述の `module = wsgi:app` の `app` に対応します。

※ もしシンプルに `app.py` の中で `app = Flask(__name__)` と定義しているなら、  
`module = app:app` のように書くことも可能です。


## 3. Flask アプリケーション自体 (Python コード)

Flask アプリは、典型的には以下のような構成をとることが多いです。

```
myapp/
  ├── __init__.py
  ├── app.py        # Flaskのエントリーポイントになるファイル(または wsgi.py)
  ├── views.py      # ルーティングの定義など
  ├── ...
  └── uwsgi.ini     # uWSGIの設定ファイル
```

### ルーティング例

```python
# views.py
from flask import Blueprint, request, jsonify

bp = Blueprint('main', __name__)

@bp.route('/')
def index():
    return "Hello, world!"

@bp.route('/api/data', methods=['GET'])
def get_data():
    # 何か処理
    return jsonify({"message": "some data"})
```

### アプリ本体

```python
# app.py (または __init__.py)
from flask import Flask
from .views import bp as main_bp

def create_app():
    app = Flask(__name__)
    # Blueprint を登録
    app.register_blueprint(main_bp)
    
    # もしDB接続や拡張機能の初期化などがあればここで
    # ...

    return app
```

こういった形で**Flask アプリ**が定義されます。  
uWSGI は、`create_app()` で生成された Flask アプリ (ここでは `app`) を読み取り、WSGI 経由でリクエストを捌きます。


## 接続まとめ

1. **ブラウザ -> Nginx**  
   - ブラウザ(クライアント)は `http://example.com` にアクセスする。  
   - Nginx はポート 80(または443)で受け取り、サーバブロックの `location /` の設定に基づき次へ転送。

2. **Nginx -> uWSGI**  
   - `uwsgi_pass unix:///path/to/yourapp.sock` で受け取ったリクエストを uWSGI へ渡す。  
   - `uwsgi_params` に書かれた HTTPヘッダなどの情報を含めて転送。

3. **uWSGI -> Flask**  
   - `uwsgi.ini` などに設定された `module = wsgi:app` を元に、`wsgi.py` に定義された `app` (Flask インスタンス) を WSGI 経由で呼び出す。  
   - Flask が該当ルート(エンドポイント)を解決し、レスポンスを生成して返す。

---

## 実際のファイル・エンドポイントまとめ

- **Nginx 設定ファイル**  
  - `/etc/nginx/conf.d/myapp.conf` または `/etc/nginx/sites-enabled/myapp.conf` など  
  - `server { ... location / { uwsgi_pass ... } }`

- **uWSGI 設定ファイル**  
  - `uwsgi.ini` など  
  - `module = wsgi:app`  
  - `socket = /path/to/yourapp.sock`  

- **Flask エントリーポイント (wsgi.py など)**  
  - `app = Flask(__name__)` が定義されている、もしくはファクトリ関数から返す。  
  - uWSGI がここを読み込んで Flask アプリを呼び出す。

- **Flask 内部のルーティング (views.py など)**  
  - `@app.route('/')` のように書いてある部分  
  - ブラウザから `http://example.com/` や `http://example.com/api/data` などにアクセスすると実際に呼び出される関数


## まとめ

- **Nginx** は **HTTP** リクエストを受け付け、`uwsgi_pass` で **uWSGI** に転送。  
- **uWSGI** は **WSGI** インタフェースを通じて **Flask** の `app` を呼び出す。  
- Flask で定義されたルート(エンドポイント)が処理を行い、レスポンスを作ってブラウザへ返す。