2026年9月23日

2026年9月23日

Nginx LB でセッションアフィニティする方法|ip_hash・hash・Cookie振り分けとWordPressでの要否

Nginx のオープンソース版でセッションアフィニティ(同じ利用者を同じバックエンドに振り分け続けること)を実現するには、ip_hash、hash ディレクティブ、Cookie の値を使った振り分けの3通りがあります。NGINX Plus には Cookie を自動で発行する sticky もありますが、オープンソース版にはありません。この記事では各方式の設定と弱点を説明したうえで、WordPress ではそもそもアフィニティが必要かどうかの判断基準も示します。

本記事は Nginx の振り分け方式の比較と WordPress での要否に重点を置いています。Nginx のディレクティブの提供範囲(オープンソース版と Plus の区分)は(2026年10月現在)の公式ドキュメントに基づく理解なので、利用中のバージョンのドキュメントも確認してください。

まず、本当にアフィニティが必要か

アフィニティは「サーバーごとに状態を持っている」ことへの対処です。逆に言えば、状態を共有できればアフィニティは要りません。WordPress の場合、次の点を押さえておくと判断しやすくなります。

  • ログイン状態:WordPress のログインは Cookie とデータベース(ユーザーメタに保存されるセッショントークン)で管理されます。全台が同じデータベースを参照し、wp-config.php の認証用キーとソルトが全台で同じなら、どのサーバーに振られてもログインは維持されます
  • WooCommerce のカート:カート情報は Cookie とデータベースのセッションテーブルで管理されるため、データベースを共有していればアフィニティ無しで動く構成が一般的です
  • **PHP の $_SESSION を使うプラグイン**:セッションファイルが各サーバーのローカルに保存されると、別のサーバーに振られた途端に状態が消えます。ここがアフィニティを求められる典型的な原因です
  • アップロード画像:一台にだけ保存されると、ほかのサーバーでは 404 になります。これはアフィニティではなく、共有ストレージやオブジェクトストレージへの保存で解決すべき問題です

PHP セッションが原因なら、Redis などにセッションを保存して共有するほうが、障害時の振り直しにも強い構成になります。アフィニティは、共有化がすぐにできない場合の現実的な回避策として位置づけるとよいでしょう。

方式1:ip_hash

最も手軽なのが ip_hash です。クライアントの IP アドレスからバックエンドを決めるため、同じ IP からのアクセスは同じサーバーに届きます。

upstream wp_backend {
    ip_hash;
    server 10.0.1.11:80;
    server 10.0.1.12:80;
    # メンテナンスで外すときは削除せず down を付ける(振り分けの再計算を抑える)
    # server 10.0.1.13:80 down;
}

server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://wp_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

弱点は3つあります。IPv4 ではアドレスの上位3オクテットで判定されるため、同じネットワークの利用者が一台に偏ることがあります。携帯回線などで利用者の IP が途中で変わると、別のサーバーに移ります。そして、CDN や別のロードバランサーの後ろに Nginx がある場合、すべての接続が前段の IP から来るように見え、全員が一台に集中します。前段がある構成では、set_real_ip_from と real_ip_header で本来のクライアント IP を復元する設定と組み合わせてください。なお ip_hash を使う upstream では backup パラメーターは使えません。

方式2:hash ディレクティブ

hash ディレクティブは、任意の値をキーにしてバックエンドを決めます。consistent を付けるとコンシステントハッシュになり、サーバーを増減したときに振り分けが変わる利用者の割合を小さくできます。

upstream wp_backend {
    hash $remote_addr consistent;
    server 10.0.1.11:80;
    server 10.0.1.12:80;
}

キーに Cookie を使うこともできます。たとえば PHP セッションの Cookie をキーにすると、同じセッションは同じサーバーに届きます。

# Cookie がまだ無い初回は IP をキーにする
map $cookie_PHPSESSID $affinity_key {
    ""      $remote_addr;
    default $cookie_PHPSESSID;
}

upstream wp_backend {
    hash $affinity_key consistent;
    server 10.0.1.11:80;
    server 10.0.1.12:80;
}

この方式の注意点は、初回のリクエストと Cookie 発行後のリクエストでキーが変わることです。初回に IP で決まったサーバーと、Cookie の値で決まるサーバーが一致するとは限らないため、セッション開始直後に一度だけ別のサーバーに移る可能性があります。セッションを開始するページ(ログインやフォームの最初の画面)で問題が出ないかを、テストで確認しておく必要があります。

方式3:サーバー識別用 Cookie で振り分ける

初回の移動を避けたい場合は、各バックエンドが「自分の識別子」を Cookie で返し、Nginx がその値でサーバーを選ぶ方法があります。NGINX Plus の sticky route に近い考え方を、map と変数付きの proxy_pass で再現するものです。

# 各バックエンド側の Nginx(例: 10.0.1.11 では srv=a)
# add_header Set-Cookie "srv=a; Path=/; HttpOnly; Secure; SameSite=Lax" always;

# ロードバランサー側
upstream wp_backend {
    server 10.0.1.11:80;
    server 10.0.1.12:80;
}

map $cookie_srv $sticky_backend {
    a       10.0.1.11:80;
    b       10.0.1.12:80;
    default wp_backend;
}

server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://$sticky_backend;
        proxy_set_header Host $host;
    }
}

proxy_pass に変数を使うと、値が upstream 名と一致すればそのグループへ、一致しなければアドレスとして直接接続します。この方式では、Cookie で指定されたサーバーが停止していても自動では別のサーバーに切り替わりません。障害時の扱い(Cookie を消して再振り分けしてもらう運用など)を事前に決めておくか、切り替えが重要なら共有セッションへの移行を優先してください。

NGINX Plus の sticky

NGINX Plus では sticky cookie を upstream に書くだけで、Nginx が振り分け先を示す Cookie を自動発行し、以降はその Cookie でサーバーを固定します。ほかにも、アプリが発行した値を学習する sticky learn などがあります。商用製品のため、採用時は機能の提供範囲とライセンスを公式情報で確認してください。

動作を確かめる方法

設定後は、どのバックエンドに振られたかを確認します。検証の間だけ、ロードバランサーの応答に upstream のアドレスを返すヘッダーを付けると分かりやすくなります。内部の IP を外部に見せることになるため、確認が終わったら削除してください。

add_header X-Upstream $upstream_addr always;  # 検証用。終わったら削除する
# Cookie を保存しながら複数回アクセスし、X-Upstream が変わらないか見る
for i in 1 2 3 4 5; do
  curl -s -o /dev/null -D - -c /tmp/cj -b /tmp/cj https://example.com/ | grep -i x-upstream
done

設定を変えるときは、変更前の設定ファイルを控え、nginx -t で文法を確認してから反映します。本番に入れる前に、ステージング環境でログイン、フォーム送信、カート操作が途中で途切れないかを一通り試してください。

まとめ

  • WordPress のログインや WooCommerce のカートは、データベースとキー・ソルトを共有していればアフィニティ無しで動く構成が一般的
  • アフィニティが必要になる主な原因はローカル保存の PHP セッション。根本対策はセッションの共有化
  • オープンソース版では ip_hash、hash(Cookie キー)、識別用 Cookie と map の組み合わせで実現でき、それぞれ偏り・初回の移動・障害時の切り替えに弱点がある
  • 設定後は検証用ヘッダーと curl で振り分け先が固定されているかを確かめ、終わったらヘッダーを外す

お気軽にご相談ください

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