2026年10月15日

2026年10月15日

Nginxでロードバランシングを設定する方法(upstreamの書き方・分散方式・障害時の切り替え)

Nginx は、リバースプロキシとして受けたリクエストを複数のバックエンドサーバーへ振り分けられます。設定の中心は、バックエンドの一覧を定義する upstream ブロックと、そこへ転送する proxy_pass の2つです。

この記事では、基本の設定から、分散方式の選び方、バックエンドが止まったときの動き、動作確認までを説明します。設定例は 2026年11月時点の Nginx 1.30(公式イメージ)で nginx -t と curl により動作を確かめています。Ubuntu 24.04 の標準パッケージ(1.24)でも同じ書き方が使えます。

構成の前提

ここでは次の構成を例にします。

  • ロードバランサー(Nginx): 外部から 80 番/443 番で受ける
  • バックエンド: 192.168.1.10、192.168.1.11、192.168.1.12 の 8080 番で同じアプリが動いている
  • 予備のバックエンド: 192.168.1.20(ほかがすべて止まったときだけ使う)

バックエンドはどれも同じ内容を返す必要があります。WordPress などで複数台に分ける場合は、アップロードファイルの共有(NFS やオブジェクトストレージ)、データベースの共通化、ログインセッションの扱いを先に決めておかないと、リクエストごとに違うサーバーに当たって表示や動作が食い違います。

基本の設定

Nginx を入れていなければ入れます(Ubuntu/Debian の例)。

sudo apt update
sudo apt install nginx

設定ファイルを /etc/nginx/conf.d/ に作ります。このディレクトリのファイルは nginx.conf の http ブロックの中で読み込まれます。upstream は http ブロックの直下に置く必要があり、server や location の中には書けません。

sudo nano /etc/nginx/conf.d/app.conf
upstream app_backend {
    zone app_backend 64k;

    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.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 http://app_backend; の app_backend は、upstream に付けた名前です。分散方式を何も書かなければ、順番に振り分ける重み付きラウンドロビンになります(roundrobin のようなディレクティブはありません)。

zone は、振り分けの状態や障害の記録をワーカープロセス間で共有するための共有メモリです。これが無いと各ワーカーが別々に数えるため、ワーカー数が多い環境では振り分けの比率や障害時の切り替えが設定どおりに見えないことがあります。

proxy_set_header は、バックエンドに本来のホスト名と接続元の IP アドレスを伝えるための設定です。これが無いと、バックエンドのログやアプリには、すべてロードバランサーの IP アドレスからのアクセスとして記録されます。

Ubuntu では /etc/nginx/sites-enabled/default が既定のサイトとして 80 番で待ち受けています。同じ server_name を使う場合や、既定のサイトが不要な場合は無効にします。

sudo rm /etc/nginx/sites-enabled/default

構文を確かめてから反映します。reload なら処理中の接続を切らずに設定を入れ替えます。

sudo nginx -t
sudo systemctl reload nginx

分散方式を選ぶ

分散方式は upstream の中に1行書いて指定します。

書き方 振り分け方 向いている場面
(指定なし) 重み付きラウンドロビン 処理時間がそろっている一般的な Web アプリ
least_conn; 処理中の接続が最も少ないサーバーへ 処理時間にばらつきがある、長い接続が混ざる
ip_hash; 接続元 IP アドレスで振り分け先を固定 セッションをサーバーごとに持つアプリ
hash $request_uri consistent; 指定したキーで振り分け先を固定 キャッシュサーバーの手前など、同じ URL を同じサーバーに集めたい
random two least_conn; 2台を無作為に選び、接続の少ないほうへ ロードバランサーが複数台あるとき
upstream app_backend {
    zone app_backend 64k;
    least_conn;

    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

ip_hash は、多くの利用者が同じ IP アドレスを共有する環境(会社のネットワーク、携帯回線)では偏りやすくなります。また、ロードバランサーの手前にさらに CDN などのプロキシがあると、すべての利用者が同じ IP に見えて1台に集中します。その場合は hash $cookie_セッション名; のように Cookie をキーにする方法も検討します。

なお、応答時間で振り分ける least_time と、Cookie でセッションを固定する sticky は、商用版の NGINX Plus だけの機能です。無料版で書くと unknown directive のエラーになります。

サーバーごとのパラメーター

server 行の後ろには、振り分けや障害時の扱いを変えるパラメーターを付けられます。

パラメーター 意味
weight=3 重み。ほかの3倍のリクエストを受ける(既定は 1)
max_fails=3 fail_timeout の時間内にこの回数失敗したら、一時的に外す(既定は 1)
fail_timeout=30s 失敗を数える時間と、外しておく時間(既定は 10 秒)
backup 予備。ほかのサーバーがすべて使えないときだけ使う
down 停止中として扱い、振り分けない
max_conns=100 このサーバーへの同時接続数の上限

性能の違うサーバーを混ぜる場合や、予備を置く場合の例です。

upstream app_backend {
    zone app_backend 64k;

    server 192.168.1.10:8080 weight=3 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.20:8080 backup;
}

backup は、hash、ip_hash、random の分散方式とは一緒に使えません。メンテナンスで1台を外したいときは down を付けて reload します。

バックエンドが止まったときの動き

無料版の Nginx は、バックエンドを定期的に確かめる「能動的なヘルスチェック」(health_check)を持っていません(NGINX Plus の機能)。代わりに、実際のリクエストで接続できなかった、タイムアウトしたといった失敗を数え、max_fails に達したサーバーを fail_timeout の間だけ外します。

失敗したリクエストを別のサーバーへ送り直す条件は proxy_next_upstream で決めます。既定は error timeout(接続できない、時間切れ)です。バックエンドが 502 や 503 を返したときも送り直したい場合は追加します。

location / {
    proxy_pass http://app_backend;
    proxy_next_upstream error timeout http_502 http_503;
    proxy_connect_timeout 5s;
    # proxy_set_header は前の例と同じ
}

いくつか注意があります。

  • POST など、繰り返すと結果が変わるリクエストは、バックエンドへ送った後に失敗しても既定では送り直しません。non_idempotent を追加すると送り直しますが、注文や投稿が二重に処理されるおそれがあります。
  • proxy_next_upstream_tries で送り直しの回数を絞ると、予備サーバーまで届かないことがあります。試したところ、通常のサーバー2台が止まった状態で proxy_next_upstream_tries 2; を指定すると、2台を試した時点で 502 になり、backup のサーバーは使われませんでした。
  • proxy_connect_timeout の既定は 60 秒です。止まったサーバーが応答しない場合に利用者を長く待たせないよう、短めに設定しておくと切り替えが早くなります。

バックエンドとの接続を使い回す(keepalive)

既定では、Nginx はリクエストごとにバックエンドとの接続を開いて閉じます。keepalive を設定すると、接続を保持して使い回せるため、アクセスが多いときの負荷が下がります。HTTP/1.1 を使い、Connection ヘッダーを空にする設定とセットで書きます。

upstream app_backend {
    zone app_backend 64k;
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
    keepalive 16;
}

server {
    listen 80;
    server_name example.com;

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

keepalive 16 は、各ワーカープロセスが保持しておく待機中の接続数の上限です。同時接続数の上限ではありません。

動作を確かめる

どのバックエンドが応答したかを確かめるため、試験の間だけ、レスポンスヘッダーに振り分け先を出します。

location / {
    proxy_pass http://app_backend;
    add_header X-Upstream $upstream_addr always;
}
sudo nginx -t && sudo systemctl reload nginx
for i in $(seq 1 10); do
  curl -s -o /dev/null -D - http://example.com/ | grep -i x-upstream
done

重み 3:1:1 の設定で、1台が止まっている状態の結果の例です。止まったサーバーで失敗したリクエストは、次のサーバーへ送り直されています(カンマ区切りで2台が表示されている行)。

X-Upstream: 192.168.1.10:8080
X-Upstream: 192.168.1.11:8080
X-Upstream: 192.168.1.10:8080
X-Upstream: 192.168.1.12:8080, 192.168.1.10:8080
X-Upstream: 192.168.1.10:8080

失敗の記録はエラーログに出ます。upstream server temporarily disabled は、max_fails に達してそのサーバーを一時的に外したことを示します。

sudo tail -f /var/log/nginx/error.log

確認が終わったら add_header X-Upstream の行は削除してください。内部の IP アドレスを外部に見せることになるためです。

運用上の注意

  • 接続元 IP の扱い: バックエンドの Nginx では ngx_http_realip_module の set_real_ip_from と real_ip_header X-Forwarded-For で、Apache では mod_remoteip で、本来の接続元 IP を復元します。信頼するのはロードバランサーの IP アドレスだけにします。
  • HTTPS: 証明書はロードバランサー側に置き、バックエンドへは内部ネットワークで HTTP 転送するのが一般的です。アプリが HTTPS かどうかを判断できるよう、X-Forwarded-Proto を渡します。
  • ロードバランサー自身の冗長化: Nginx が1台だけだと、そこが止まると全体が止まります。必要に応じて、ロードバランサーを2台にして仮想 IP で切り替える構成や、クラウドのロードバランサーの利用を検討します。

関連する設定は次の記事でも扱っています。

まとめ

  • upstream に名前を付けてバックエンドを並べ、proxy_pass http://名前; で転送します。upstream は http ブロックの直下に書きます
  • 分散方式は既定の重み付きラウンドロビンのほか、least_conn、ip_hash、hash、random から選びます。least_time と sticky は NGINX Plus 専用です
  • zone でワーカー間の状態を共有し、max_fails/fail_timeout/backup で障害時の扱いを決めます
  • 無料版は実際のリクエストの失敗で切り替える方式で、proxy_next_upstream で送り直しの条件を決めます
  • keepalive は proxy_http_version 1.1 と Connection "" とセットで使います
  • 設定後は nginx -t で確かめてから reload し、振り分け先とエラーログで動作を確認します

お気軽にご相談ください

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