中学社会667106 views
小学社会308636 views
いろは2986023 views
数学講師2852771 views
高校物理158224 views
りんご192546 views
ヒストリア284143 views
MathPython491378 views
高校倫理1433119 views
LaTeX957300 views
Help
Tools

English

Nginx + WSGI サーバーの連携

本番環境で Python Web アプリケーションを運用する際、Nginx をリバースプロキシとして WSGI サーバーの前段に配置するのが標準的な構成である。Nginx は静的ファイルの配信、SSL 終端、ロードバランシングなどを担当し、WSGI サーバーはアプリケーション処理に専念する。この分業により、高いパフォーマンスと運用性を実現できる。

なぜ Nginx を前段に置くのか

WSGI サーバー単体でも HTTP リクエストを処理できるが、Nginx を組み合わせることで多くの利点が得られる。

静的ファイル配信の効率化

Nginx は静的ファイルの配信に最適化されており、WSGI サーバーよりも圧倒的に高速。画像、CSS、JavaScript の配信を Nginx に任せることで、WSGI サーバーの負荷を軽減できる。

SSL/TLS 終端

HTTPS の暗号化・復号処理を Nginx で行い、WSGI サーバーには平文の HTTP で通信する。証明書管理も Nginx 側で一元化できる。

さらに、Nginx はリクエストのバッファリング、圧縮、レート制限、キャッシュなどの機能も提供する。これらを WSGI サーバーで実装する必要がなくなる。

基本的な連携構成

Nginx と WSGI サーバーの連携方法は、大きく分けて 2 種類ある。

HTTP プロキシ

Nginx が HTTP でリクエストを受け、HTTP で WSGI サーバーに転送する。設定がシンプルで、どの WSGI サーバーでも使える。

uwsgi プロトコル

Nginx が HTTP でリクエストを受け、uwsgi バイナリプロトコルで uWSGI に転送する。オーバーヘッドが小さく、高パフォーマンス。

Gunicorn との連携

Gunicorn との連携には HTTP プロキシを使う。Unix ソケットを使うことで、TCP のオーバーヘッドを削減できる。

Gunicorn の設定

# gunicorn.conf.py
bind = 'unix:/tmp/gunicorn.sock'
workers = 4
worker_class = 'gthread'
threads = 4
timeout = 60
gunicorn -c gunicorn.conf.py app:application

Nginx の設定

# /etc/nginx/sites-available/myapp
upstream gunicorn_backend {
    server unix:/tmp/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://gunicorn_backend;
        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_redirect off;
    }

    location /static {
        alias /var/www/myapp/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

proxy_set_header で設定するヘッダーは重要だ。これにより、アプリケーションはクライアントの実際の IP アドレスやプロトコル(HTTP/HTTPS)を取得できる。

uWSGI との連携

uWSGI との連携では、専用の uwsgi プロトコルを使うことで最高のパフォーマンスを得られる。

uWSGI の設定

# uwsgi.ini
[uwsgi]
socket = /tmp/uwsgi.sock
chmod-socket = 666
wsgi-file = app.py
callable = application
processes = 4
threads = 2
master = true
vacuum = true

Nginx の設定

# /etc/nginx/sites-available/myapp
upstream uwsgi_backend {
    server unix:///tmp/uwsgi.sock;
}

server {
    listen 80;
    server_name example.com;

    location / {
        include uwsgi_params;
        uwsgi_pass uwsgi_backend;
    }

    location /static {
        alias /var/www/myapp/static;
        expires 30d;
    }
}

uwsgi_params は Nginx に付属するファイルで、uWSGI に渡す環境変数を定義している。通常は /etc/nginx/uwsgi_params に配置されている。

SSL/TLS の設定

HTTPS を有効にするには、Nginx で SSL 終端を行う。

server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

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

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    location / {
        proxy_pass http://gunicorn_backend;
        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;
    }

    location /static {
        alias /var/www/myapp/static;
        expires 30d;
    }
}

HTTP(ポート 80)へのアクセスは HTTPS にリダイレクトする。http2 を指定することで HTTP/2 も有効になり、パフォーマンスが向上する。

ロードバランシング

複数の WSGI サーバーにリクエストを分散させる場合、Nginx の upstream ブロックで設定する。

upstream app_servers {
    least_conn;  # 接続数が最も少ないサーバーに振り分け
    
    server unix:/tmp/gunicorn1.sock weight=3;
    server unix:/tmp/gunicorn2.sock weight=2;
    server unix:/tmp/gunicorn3.sock weight=1;
    
    keepalive 32;  # 持続的接続を維持
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://app_servers;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        # ... 他のヘッダー設定
    }
}

ロードバランシングのアルゴリズムは複数から選べる。

アルゴリズム説明
round-robinデフォルト。順番に振り分け
least_conn接続数が少ないサーバーを優先
ip_hashクライアント IP でハッシュ。セッション維持に有効

weight パラメータでサーバーごとの重みを設定できる。高性能なサーバーに多くのリクエストを振り分けたい場合に使う。

バッファリングとタイムアウト

適切なバッファリングとタイムアウト設定は、安定性とパフォーマンスに影響する。

location / {
    proxy_pass http://gunicorn_backend;
    
    # バッファリング設定
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
    proxy_busy_buffers_size 8k;
    
    # タイムアウト設定
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    
    # リクエストボディの最大サイズ
    client_max_body_size 10m;
    
    # ヘッダー設定
    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_buffering on により、Nginx がバックエンドからのレスポンスをバッファリングしてからクライアントに送信する。これにより、バックエンドの接続が早く解放され、スループットが向上する。

静的ファイルの最適化

静的ファイルの配信を最適化することで、全体のパフォーマンスが大幅に向上する。

location /static {
    alias /var/www/myapp/static;
    
    # キャッシュ設定
    expires 30d;
    add_header Cache-Control "public, immutable";
    
    # gzip 圧縮
    gzip on;
    gzip_types text/css application/javascript application/json;
    gzip_min_length 1000;
    
    # 直接ファイルを返す(try_files 不要)
    access_log off;
}

location /media {
    alias /var/www/myapp/media;
    expires 7d;
}

expiresCache-Control ヘッダーにより、ブラウザキャッシュを有効活用できる。gzip 圧縮はテキストベースのファイルで効果的だ。

アプリケーションでのプロキシ対応

リバースプロキシを経由すると、アプリケーションから見えるリクエスト情報が変わる。X-Forwarded-ForX-Forwarded-Proto ヘッダーを参照して、正しい情報を取得する必要がある。

Flask の場合は ProxyFix ミドルウェアを使う。

from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

Django の場合は settings.py で設定する。

# settings.py
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True

完全な設定例

Gunicorn + Nginx の完全な設定例を示す。

# /etc/nginx/sites-available/myapp
upstream gunicorn_backend {
    server unix:/tmp/gunicorn.sock fail_timeout=0;
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

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

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;

    location / {
        proxy_pass http://gunicorn_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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 60s;
        client_max_body_size 10m;
    }

    location /static {
        alias /var/www/myapp/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
        gzip_static on;
        access_log off;
    }
}

この構成により、SSL 終端、静的ファイル配信、プロキシ機能が統合された本番環境が完成する。Nginx と WSGI サーバーの役割分担を理解し、適切に設定することで、高パフォーマンスで運用しやすいシステムを構築できる。