← プログラミングページの先頭へ

Nginx: Web Server および Reverse Proxy

Nginx は、高性能の Web Server および Reverse Proxy (リバース プロキシ サーバー) です。

主な用途:

  • 静的リソース (HTML、JS、CSS、写真) を提供します。
  • リバース プロキシ Django、FastAPI、およびその他のバックエンド。
  • HTTPS / TLS は終了しました。
  • HTTP 圧縮とキャッシュ。
  • 負荷分散と電流制限。
  • WebSocket、SSE、およびその他の長時間持続する接続またはストリーミング応答プロキシ。

React + Django + Docker プロジェクトの場合:

Browser
   ↓
Cloudflare(オプション)
   ↓
Nginx
   ├── /          → React SPA
   ├── /assets/   → JS / CSS
   ├── /api/      → Django DRF
   ├── /admin/    → Django Admin
   └── /static/   → Django Static Files

1. nginx.confの構成構造

Nginx は、別の構成コンテキスト (Context) を使用して構成を編成します。

events {
    worker_connections 1024;
}

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

        location / {
            # ...
        }

        location /api/ {
            # ...
        }
    }
}

主なレベル:

nginx.conf
├── Main Context
├── events
└── http
    ├── upstream
    ├── server
    │   ├── location /
    │   └── location /api/
    └── server
Context機能
mainグローバル設定 (worker_processes など)
events接続イベントの処理
httpHTTP サービスのパブリック構成
upstreamバックエンドサーバーグループの定義
server仮想ホスト、指定されたポートとドメイン名を処理します
locationURI によるリクエストを照合して処理します

worker_processes および worker_connections

worker_processes auto;

events {
    worker_connections 1024;
}
  • worker_processes: Nginx Worker プロセスの数。auto は通常、利用可能な CPU リソースに基づいて決定されます。
  • worker_connections: リクエストの最大数ではなく、Worker ごとに許可される接続の最大数。

理論上の接続容量は、この 2 つの積によっておおよそ制限されます。ただし、リバース プロキシ中は、クライアント リクエストがクライアント接続とアップストリーム接続の両方を占有する可能性があるため、製品を直接最大同時ユーザー数と見なすことはできません。

Docker の構成ファイル

公式 Nginx 画像は通常、以下を使用します。

/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf

一般的に言えば:

  • nginx.conf: events や http などの最上位構造が含まれます。
  • conf.d/default.conf: 通常、server Block のみが定義され、include を介してメイン構成によって導入されます。

したがって、conf.d/default.conf にマウントされる設定ファイルには、通常、http {} および events {} を記述する必要はありません。

2.Server BlockとHTTPS

HTTP リダイレクト HTTPS

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

    return 301 https://$host$request_uri;
}

たとえば:

http://example.com/blog?id=1
        ↓ 301
https://example.com/blog?id=1
  • listen 80: HTTP のポート 80 を監視します。
  • server_name: 要求されたドメイン名と一致します。
  • return 301: 永続的なリダイレクト。
  • $host: Nginx によって解析された、要求されたホスト名。
  • $request_uri: Query String を含む元のリクエスト URI。

HTTPS Server

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/ssl/fullchain.pem;
    ssl_certificate_key /etc/ssl/privkey.pem;

    client_max_body_size 10M;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;
}

Nginx は、TLS ハンドシェイク、証明書、および暗号化された HTTP 接続を担当します。

Cloudflare を使用する場合は、以下を使用できます。

Browser
   ↓ HTTPS
Cloudflare
   ↓ HTTPS
Nginx
   ↓ HTTP(内部ネットワーク)
Django

通常、Cloudflare Full (strict) を使用し、発信元サイトに有効な証明書を構成して、Cloudflare から Nginx への接続も認証されるようにする必要があります。

3. Location: URI のマッチング

location は、リクエスト URI に基づいて処理方法を選択するために使用されます。

location / {
    # ...
}

location /api/ {
    # ...
}

一般的なマッチング方法

文法意味
location = /api完全一致
location /api/プレフィックスマッチング
location ^~ /assets/接頭辞の一致と定期的な一致チェックのスキップ
location ~ \.css$大文字と小文字を区別する正規一致
location ~* \.(png|jpg)$大文字と小文字を区別しない正規の一致

一致の優先順位

基本的なルール:

  1. 完全一致 = が優先されます。
  2. 最長のプレフィックス一致を検索します。
  3. 最長のプレフィックスが ^~ を使用している場合は、それを直接選択します。
  4. それ以外の場合、通常のルール Location が構成順序でチェックされ、最初に一致した通常のルールが有効になります。
  5. 正規の一致がない場合は、以前に見つかった最長のプレフィックスが使用されます。

注: URI の一致には Query String は含まれません。

4. Reverse Proxy: リバースプロキシ

Django が Docker でリッスンしていると仮定します。

backend:8000

Nginx:

location /api/ {
    proxy_pass http://backend: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_set_header X-Forwarded-Proto $scheme;
}

リクエスト:

GET https://example.com/api/v1/users/me/
                   ↓
                 Nginx
                   ↓
GET http://backend:8000/api/v1/users/me/

ここで、backend は Docker Compose のサービス名です。

proxy_pass の末尾のスラッシュ

ここで物事がうまくいかない可能性があります。

location /api/ {
    proxy_pass http://backend:8000;
}

パス接頭辞を保持します:

/api/v1/users/ → /api/v1/users/

ただし:

location /api/ {
    proxy_pass http://backend:8000/;
}

一致する /api/ プレフィックスを / に置き換えます。

/api/v1/users/ → /v1/users/

その理由は、2 番目の proxy_pass には URI / が含まれており、Nginx が対応するパスの置換を実行するためです。

Django にすでに /api/v1/ プレフィックスが定義されているプロジェクトの場合は、末尾のスラッシュなしで proxy_pass http://backend:8000; を使用するのが一般的です。

5. proxy_set_header: パス要求情報

Header機能
Host元のリクエストされたドメイン名
X-Real-IPバックエンドクライアントに IP を伝えます
X-Forwarded-Forプロキシ チェーンに IP を記録します
X-Forwarded-Proto元のリクエスト プロトコルをバックエンドに伝えます
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;

共通の変数:

変数意味
$host解決されたリクエストのホスト名
$remote_addrNginx が現在認識しているクライアント アドレス
$proxy_add_x_forwarded_for現在のクライアント アドレスに元の X-Forwarded-For が追加される
$scheme現在の接続は HTTP または HTTPS を使用しています
$request_uriオリジナルの URI、Query String を含む
$uri現在は Query String を除く URI に正規化されています
$http_upgradeUpgrade Header リクエスト中

Cloudflare と実際のクライアント IP

Cloudflare プロキシを使用する場合:

Browser IP
    ↓
Cloudflare IP
    ↓
Nginx

Nginx がデフォルトで認識する $remote_addr は、Cloudflare ノード IP である可能性があります。

ゲスト IP は、Real IP モジュールを通じて復元できます。

# 説明のために、次のように置き換えます。 Cloudflare 完全な公式発表 IP セグメント
set_real_ip_from <trusted_cloudflare_cidr>;
real_ip_header CF-Connecting-IP;

本物の Cloudflare プロキシ アドレスのみを信頼し、偽造の可能性がある信頼できないプロキシからのリクエストをオリジンが受け入れないようにする必要があります。

回復後、$remote_addr は、信頼されたプロキシ情報によって識別されるクライアント アドレスを表します。

Cloudflare IP リストは定期的なメンテナンスが必要です。 Cloudflare公式ドキュメントを参照してください。

6. Static Files および SPA ルーティング

Vite ビルド結果:

dist/
├── index.html
└── assets/
    ├── index-Ab12.js
    └── index-Cd34.css

Nginx:

root /usr/share/nginx/html;
index index.html;

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

処理の流れ:

GET /profile
      ↓
チェックする /usr/share/nginx/html/profile
      ↓
存在しません
      ↓
戻る index.html
      ↓
React Router プロセス /profile

root および alias

root スプライスは URI を静的ファイルのルート ディレクトリにリクエストします。

location /assets/ {
    root /usr/share/nginx/html;
}

リクエスト:

/assets/app.js
→ /usr/share/nginx/html/assets/app.js

alias は、一致する Location プレフィックスを指定されたファイル システム パスに置き換えます。

location /media/ {
    alias /data/media/;
}

リクエスト:

/media/avatar/a.jpg
→ /data/media/avatar/a.jpg

ディレクトリ タイプ Location の場合、alias パスは通常、プレフィックスに対応する末尾の / を保持する必要があります。

7. HTTP キャッシュ

Hash を使用して Vite によって生成された静的ファイルの場合:

location /assets/ {
    try_files $uri =404;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

この方法:

index-A1b2.js

1 年間キャッシュできます。

更新後にビルドすると次のものが生成されます。

index-C3d4.js

ブラウザはそれを新しいリソースとして扱います。

index.html

location = /index.html {
    add_header Cache-Control "no-cache";
}

no-cache は、キャッシュを完全に無効にするのではなく、キャッシュを使用する前に検証が必要であることを意味します。

注: SPA の /profile などのパスは、/index.html 内部リダイレクトを介して HTML に戻る場合があるため、最終的な HTML 応答に適切なキャッシュ Header があることの確認も必要です。

SPA のフォールバック HTML を長期間キャッシュしないでください。また、存在しない JS ファイルを HTML にフォールバックさせないでください。

8. gzip / Brotli 圧縮

Nginx は、テキスト HTTP 応答を圧縮して、ネットワーク送信量を削減できます。

gzip

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;

gzip_types
    text/plain
    text/css
    application/javascript
    application/json
    image/svg+xml;

Brotli

互換性のある Brotli Nginx モジュールのインストールが必要です:

brotli on;
brotli_comp_level 5;

brotli_types
    text/plain
    text/css
    application/javascript
    application/json
    image/svg+xml;

両方のアルゴリズムを同時に構成できます。

Browser
    ↓ Accept-Encoding: br, gzip
Nginx
    ↓ Content-Encoding: br
Compressed Response

通常は Brotli が優先され、gzip がフォールバックとなります。

注: 通常、公式 nginx:alpine イメージでは Brotli コマンドを直接有効にすることはできません。まず、対応するモジュールが存在し、正しくロードされていることを確認する必要があります。

9. リクエストのサイズとプロキシのタイムアウト

client_max_body_size

client_max_body_size 10M;

クライアントリクエストの本文サイズを制限します。

制限を超えると、通常は次のものが返されます。

413 Content Too Large

アバター、写真、その他のアップロードされたコンテンツを制限するのに適しています。

エージェントのタイムアウト

proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
指示機能
proxy_connect_timeoutアップストリーム接続確立のタイムアウト
proxy_send_timeoutアップストリームへの 2 つの連続した書き込み操作の間に許可されるタイムアウト
proxy_read_timeoutアップストリームからの 2 つの連続した読み取り操作の間に許可されるタイムアウト

proxy_read_timeout は、HTTP リクエスト全体の合計実行時間制限ではありません。

バックエンドがデータを送信し続ける場合、合計応答時間が 60 秒を超えても、このタイムアウトがトリガーされないことがあります。

10. Buffering: 応答バッファリング

Nginx は、デフォルトでプロキシ応答バッファリングを有効にします。

proxy_buffering on;

通常、API 応答はデフォルトのままで問題ありません。

仕組み:

Django
   ↓
Nginx Buffers
   ↓
Browser

Nginx はアップストリームの応答を読み取り、可能な限りバッファリングします。これにより、遅いクライアントによるバックエンドの占有が軽減されます。

ただし、データをすぐに送信する必要がある SSE などのインターフェイスの場合は、閉じることができます。

proxy_buffering off;

現時点では、応答はよりタイムリーにクライアントに配信されます。

proxy_request_buffering は別の構成で、リクエスト本文を最初に Nginx にバッファリングするかどうかを制御します。レスポンスのバッファリングと混同することはできません。

11. WebSocketエージェント

HTTP/1.1 接続をアップグレードする場合、WebSocket には特別な Header が必要です。

location /ws/ {
    proxy_pass http://backend:8000;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_read_timeout 3600s;
}

基本的なプロセス:

Browser
   ↓ HTTP Upgrade
Nginx
   ↓
ASGI / WebSocket Server
   ↓
Persistent Connection

通常の HTTP と WebSocket を混在させる構成の場合、map を介して Connection Header を動的に設定することもできます。

注: Django 自体は、完全な WebSocket アプリケーション ルーティングを直接提供するわけではなく、通常は Django Channels またはその他の ASGI WebSocket 処理ソリューションを必要とします。

12. SSE / Streaming

SSE (Server-Sent Events) は、サーバーがイベントをクライアントに継続的に送信するために使用します。コミュニケーションの方向性は主に次のとおりです。

Server → Browser

典型的なシナリオ:

  • AI Token ストリーミング出力。
  • ミッションの進行状況の更新。
  • リアルタイム通知。
  • サーバーイベントのプッシュ。

Nginx構成

location /api/v1/stream/ {
    proxy_pass http://backend:8000;

    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_cache off;

    proxy_read_timeout 300s;

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

主要な構成:

  • proxy_buffering off: Nginx バッファ応答を回避し、イベント出力を遅延します。
  • proxy_cache off: Nginx プロキシ キャッシュを使用しないでください。
  • proxy_read_timeout 300s: アップストリーム読み取り間の待機時間を長くします。

バックエンドは通常、以下を返します。

Content-Type: text/event-stream
Cache-Control: no-cache

応答内容:

data: {"message":"Hello"}

data: {"message":"World"}

各イベントは空行で区切られます。

長期間新しいイベントがない接続の場合、サーバーはアイドル状態による接続のタイムアウトを避けるために定期的にハートビートを送信できます。

あるいは、バックエンドに以下を返すようにすることもできます。

X-Accel-Buffering: no

Nginx バッファリングは特定の応答に対して無効になりますが、proxy_ignore_headers によって無効になっていないことを確認する必要があります。

13. 負荷分散

複数のバックエンド インスタンスが存在する場合:

upstream django_backend {
    server backend1:8000;
    server backend2:8000;
    server backend3:8000;
}

server {
    location /api/ {
        proxy_pass http://django_backend;
    }
}

アーキテクチャ:

             ┌── Django 1
Browser      │
   ↓         ├── Django 2
Nginx ───────┤
             └── Django 3

リクエストの割り当てには、デフォルトの共通ポーリング方式が使用されます。

その他の戦略には次のようなものがあります。

  • least_conn: アクティブな接続が少ないバックエンドを優先します。
  • ip_hash: クライアント IP に基づいて比較的固定された割り当て。

単一の Docker Compose VPS にデプロイされた小規模プロジェクトの場合、マルチインスタンスの負荷分散は必ずしも必要ではありません。

14. 電流制限 (Rate Limiting)

NginxはIPおよびその他の条件に応じてリクエスト頻度を制限できます。

http コンテキストで定義:

limit_req_zone
    $binary_remote_addr
    zone=api:10m
    rate=10r/s;

Location では次を使用します。

location /api/ {
    limit_req zone=api burst=20;
    limit_req_status 429;

    proxy_pass http://backend:8000;
}

主要なパラメータ:

パラメータ機能
$binary_remote_addrクライアント IP のバイナリ表現
zone=api:10m電流制限状態の共有メモリ領域
rate=10r/s平均して 1 秒あたり 10 リクエスト
burst=20ある程度のリクエストのバーストを許容する
limit_req_status 429電流制限がトリガーされると 429 を返します

nodelay が設定されていない場合、Burst 内の一部の超過リクエストは、すぐに渡されるのではなく遅延される可能性があります。

Cloudflare を使用する場合は、最初に実際のクライアント IP を正しく復元する必要があります。そうしないと、電流が Cloudflare ノード IP に従って制限され、複数の実際のユーザーが同じ電流制限された ID を共有する可能性があります。

さらに、Nginx 電流制限は、Django 内のユーザーレベルの電流制限とビジネス許可制御を置き換えることはできません。

15. ログとトラブルシューティング

Access Log

HTTP アクセス ステータスを記録します。

access_log /var/log/nginx/access.log;

通常、次のものが含まれます。

  • IPをリクエストしてください。
  • リクエストメソッドはURIです。
  • HTTP ステータス コード。
  • 応答サイズ。
  • リクエスト時間 (ログ形式によって異なります)。

Error Log

error_log /var/log/nginx/error.log warn;

プロキシの失敗、接続エラー、部分的なアップストリーム エラー、および Nginx 自体のエラーをログに記録します。

Dockerログ

公式 Nginx Docker ミラーには、通常、stdout/stderr に接続されたアクセス ログとエラー ログがあります。

次のものが使用できます。

docker compose logs -f nginx

コンテナーのログを表示します。

構成テスト

nginx -t

構成構文と関連ファイルを確認してください。

実際にロードされた完全な構成を確認してください。

nginx -T

設定をリロードします。

nginx -s reload

Docker環境:

docker compose exec nginx nginx -t
docker compose exec nginx nginx -s reload

16. Nginx および Django の責任

機能NginxDjango
HTTPS / TLS主に担当するのは、通常、直接取引されることはありません
静的ファイル提供責任者構築または収集を担当する
リバースプロキシ責任のあるプロキシリクエストを受信する
HTTP圧縮通常は責任のあるオプション
HTTP キャッシュ静的リソースとプロキシ キャッシュビジネスキャッシュ
API ルーティング前へビジネスルーティング
Authentication普通に無責任責任のある
Authorization普通に無責任責任のある
ファイルアップロードのサイズ制限第一レベルの制限ビジネスレベルの検証
電流制限をリクエストするIP/リクエストレベル電流制限ユーザー/ビジネスレベルの電流制限
バックグラウンドタスク無責任なCelery およびその他のタスク システム

概要

Nginx 最も重要な知識は次のように要約できます。

モジュールコアコンセプト
構成構造events、http、server、location
リクエストルーティングserver_name、location、proxy_pass
静的ファイルroot、alias、try_files
ネットワークセキュリティTLS、Real IP、電流制限
パフォーマンスの最適化gzip/Brotli、Cache-Control、Buffering
長い接続WebSocket、SSE
運用・保守Access Log、Error Log、nginx -t、Reload

React + Django + Docker Compose プロジェクトの場合、マスターする価値があるのは次のとおりです。

  1. location マッチングと proxy_pass パス処理。
  2. Nginx と Django 間の Header パススルーおよびプロキシ信頼構成。
  3. React SPAのtry_files処理。
  4. HTML 再検証による静的リソースの長期キャッシュ。
  5. gzip/Brotli 圧縮。
  6. HTTP リクエストのタイムアウト、Buffering および SSE。
  7. Docker 環境でのログと構成のチェック。

参考資料