2026年7月5日

2026年7月5日

Nginxのupstreamモジュールの使い方|振り分け方式・障害時の動き・keepalive

Nginx の upstream は、転送先のサーバーをグループにまとめて名前を付ける仕組みです。http コンテキストに upstream 名前 { server ...; } を書き、proxy_pass http://名前; や fastcgi_pass 名前; から参照すると、複数のサーバーへの振り分け、障害時の切り離し、接続の再利用(keepalive)が使えるようになります。この記事では、基本の書き方、振り分け方式の選び方、server 行のパラメーター、障害時の挙動、keepalive の設定、WordPress を複数台で動かすときの注意点、動作の確認方法を順に説明します。

基本の書き方

upstream ブロックは http コンテキスト(server ブロックの外)に書きます。Debian や Ubuntu なら /etc/nginx/conf.d/ 配下のファイルに置くと、http の中で読み込まれます。

# /etc/nginx/conf.d/upstream.conf
upstream app_backend {
    server 10.0.0.11:8080;
    server 10.0.0.12:8080;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://app_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_pass の URL のホスト部分に upstream の名前を書くと、Nginx はその名前を DNS で引かずにグループとして扱います。proxy_set_header の4行は、バックエンドに元のホスト名、訪問者の IP アドレス、元の接続が HTTP か HTTPS かを伝えるためのものです。これが無いと、バックエンドの WordPress が自分の URL を誤認したり、アクセスログやセキュリティ系プラグインがすべてのアクセスを Nginx の IP アドレスから来たものとして扱ったりします。

PHP-FPM への転送でも同じ書き方が使えます。ソケットのパスは OS と PHP の版によって異なるため、/run/php/ などの実際のファイル名を確認して書き換えてください。

upstream php_backend {
    server unix:/run/php/php-fpm.sock;   # 実際のソケット名に合わせる
}

# location ~ \.php$ { ... fastcgi_pass php_backend; }

振り分け方式を選ぶ

何も指定しなければ、リクエストを順番に配るラウンドロビンになります。方式は upstream ブロックの先頭に1行書いて切り替えます。

  • ラウンドロビン(指定なし): 処理時間がそろっているサーバー群に向く。weight で配分の比率を変えられる
  • least_conn;: 処理中の接続が最も少ないサーバーに送る。重いページと軽いページが混在するときに偏りを抑えやすい
  • ip_hash;: 訪問者の IP アドレスから振り分け先を決め、同じ人を同じサーバーに送る。ただし IPv4 では上位3オクテットで判定するため、同じ会社や同じ携帯回線からのアクセスが1台に集中することがある
  • hash キー [consistent];: 任意の値(例: $request_uri)で振り分け先を決める。consistent を付けると、サーバーの増減時に振り分け先が変わるリクエストを減らせる。キャッシュサーバーの前段で使われることが多い
  • random;: ランダムに選ぶ。random two least_conn; のように、2台を無作為に選んで接続の少ないほうに送る書き方もできる

迷ったら、まずラウンドロビンか least_conn で始め、特定の要件があるときだけハッシュ系を検討します。

server 行のパラメーター

upstream app_backend {
    least_conn;
    server 10.0.0.11:8080 weight=2 max_fails=3 fail_timeout=30s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.13:8080 backup;
    # server 10.0.0.14:8080 down;   # メンテナンス中は down で外す
}
  • weight=数値: 配分の比率。上の例では 11番の重みが12番の2倍になり、より多くのリクエストが割り当てられる(既定値は1)。least_conn でも重みは考慮されるが、配分は接続数の状況によって変わる
  • max_fails と fail_timeout: fail_timeout で指定した時間内に max_fails 回失敗すると、そのサーバーを fail_timeout の間だけ使わない。既定値は1回・10秒
  • backup: 他のサーバーがすべて使えないときだけ使う予備。ハッシュ系(hash・ip_hash)や random とは組み合わせられない
  • down: 恒久的に使わないことを示す。サーバーの入れ替え作業で一時的に外すときに便利
  • max_conns=数値: そのサーバーへの同時接続数の上限

ここで言う「失敗」とは、接続エラーやタイムアウトなど、後述の proxy_next_upstream で失敗と定義された応答です。オープンソース版の Nginx が行うのは、実際のリクエストの結果から判断する「受動的な」ヘルスチェックだけです。一定間隔でサーバーに問い合わせる能動的なヘルスチェック(health_check ディレクティブ)は、商用版の NGINX Plus の機能です。

障害時にどう動くか

あるサーバーへの転送が失敗すると、Nginx は既定で、接続エラーかタイムアウトの場合に限り、同じリクエストを次のサーバーへ送り直します。どの失敗で次へ回すかは proxy_next_upstream(FastCGI なら fastcgi_next_upstream)で変えられます。

location / {
    proxy_pass http://app_backend;
    proxy_next_upstream error timeout http_502 http_503;
    proxy_next_upstream_tries 2;
    proxy_connect_timeout 5s;
}

POST のように、二重に実行されると困るリクエストは、既定ではバックエンドに送信した後には再送されません。non_idempotent を付けると再送されるようになりますが、注文やコメントが二重に登録されるおそれがあるため、WordPress では付けないほうが安全です。

すべてのサーバーが使えない状態になると、エラーログに no live upstreams と記録され、訪問者には 502 Bad Gateway が返ります。502 が出たときは、まずエラーログでどのサーバーへの接続に失敗したかを確認します。

keepalive で接続を再利用する

既定では、Nginx はバックエンドへのリクエストごとに接続を張り直します。keepalive を設定すると、使い終わった接続を一定数だけ保持して再利用でき、アクセスが多いときの接続コストを減らせます。HTTP で転送する場合は、HTTP/1.1 を使い、Connection ヘッダーを空にする設定も必要です。

upstream app_backend {
    server 10.0.0.11:8080;
    server 10.0.0.12:8080;
    keepalive 16;   # ワーカープロセスごとに保持する待機中の接続数
}

location / {
    proxy_pass http://app_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
}

keepalive の数値は同時接続数の上限ではなく、待機中の接続をいくつ残しておくかの数です。大きすぎるとバックエンド側の接続枠を占有するため、バックエンドの上限に余裕を残せる値にします。PHP-FPM への FastCGI 転送で接続を再利用する場合は、fastcgi_keep_conn on; も必要です。

WordPress を複数台で動かすときの注意

upstream で振り分けること自体は数行で書けますが、WordPress は1台で動くことを前提に作られている部分があります。複数台に分ける前に、次の点を準備しておきます。

  • データベースは1か所に集め、全台が同じものに接続する
  • wp-content/uploads を全台で共有する(共有ストレージやオブジェクトストレージ用のプラグインなど)。共有しないと、アップロードした画像が他のサーバーで表示されない
  • プラグインやテーマの更新は管理画面から1台だけに行うと台ごとに差が出るため、デプロイの手順で全台にそろえる
  • ページキャッシュやオブジェクトキャッシュを使う場合は、Redis などの共有のキャッシュに寄せる

WordPress のログイン状態は Cookie とデータベースで管理されるため、基本的には ip_hash で同じサーバーに固定しなくても動きます。ただし、独自にセッションを使うプラグインがある場合は例外です。また、Nginx 経由で HTTPS を判定させるには、WordPress の wp-config.php で X-Forwarded-Proto を見て $_SERVER['HTTPS'] を設定する処理が必要になることがあります。この場合、ヘッダーを偽装されないよう、バックエンドへは Nginx からの通信だけを許可します。

反映と確認

設定を変える前に /etc/nginx をバックアップし、ステージング環境で試してから本番に入れます。

sudo cp -a /etc/nginx /etc/nginx.bak-$(date +%Y%m%d)
sudo nginx -t && sudo systemctl reload nginx

どのサーバーに振り分けられたかは、アクセスログに upstream の変数を出すと分かります。

log_format upstreamlog '$remote_addr [$time_local] "$request" $status '
                       'upstream=$upstream_addr ustatus=$upstream_status '
                       'rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/upstream.log upstreamlog;

1台を down にしたり、バックエンドのサービスを止めたりして、残りのサーバーへ振り分けが移ること、$upstream_addr に複数のアドレスが記録される(再送が起きた)ことを確認しておくと、本番で障害が起きたときの挙動を把握できます。upstream の server 行に書いたホスト名は、Nginx の起動時や再読み込み時に名前解決されるのが基本です。DNS の変更を自動で追従させる resolve パラメーターは、オープンソース版では比較的新しい版から使えるようになったため、使う場合はお使いの版のドキュメントを確認してください(2026年10月現在)。

まとめ

  • upstream は http コンテキストに書き、proxy_pass や fastcgi_pass から名前で参照する
  • 振り分け方式は、まずラウンドロビンか least_conn。同じ人を固定したいときに ip_hash やハッシュ系を検討する
  • max_fails・fail_timeout・backup・down で障害時とメンテナンス時の動きを決める。オープンソース版は受動的なヘルスチェックのみ
  • POST は既定では再送されない。non_idempotent は二重登録のおそれがあるため慎重に
  • keepalive は proxy_http_version 1.1 と Connection "" をあわせて設定する
  • WordPress を複数台にするなら、データベース・アップロード・キャッシュ・デプロイの共有が前提

お気軽にご相談ください

お見積りへ お問い合わせへ
▲