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 を複数台にするなら、データベース・アップロード・キャッシュ・デプロイの共有が前提