2026年6月6日

2026年6月6日

Nginx でロードバランサーを構築する手順|専用サーバーの用意からHTTPS終端・WordPress側の設定・動作確認まで

Nginx は、Web サーバーとしてだけでなく、複数台のサーバーに通信を振り分けるロードバランサー(LB)としても使えます。この記事では、Nginx を入れた専用の LB サーバーを1台用意し、その後ろに WordPress サーバー2台を置く構成を、構築の順番どおりに説明します。読み終えると、LB の設定、HTTPS の終端、WordPress 側で必要な調整、振り分けの確認方法までを一通り自分で組めるようになります。分散方式(ラウンドロビンや least_conn など)の細かな比較は扱わず、「動く LB を正しい順番で作る」ことに絞っています。

完成形の構成と作業の順番

想定する構成は次のとおりです。

  • LB サーバー:グローバル IP を持ち、80/443 番で外部からの通信を受ける。プライベート IP は 10.0.0.10
  • WordPress サーバー:10.0.0.11 と 10.0.0.12。外部からは直接接続させず、LB からの通信だけを受ける
  • データベース:WordPress サーバーから共通で使う(別サーバーやマネージド DB)

作業は「LB を HTTP で動かす → バックエンドで送信元を正しく扱う → HTTPS を終端する → 振り分けと障害時の切り離しを確認する」の順で進めます。最初から HTTPS や細かな調整を入れると、問題が起きたときにどの段階が原因か分からなくなるためです。本番に入れる前に、同じ構成をステージング環境で組んで試してください。

ステップ1:LB サーバーに Nginx を入れる

Ubuntu / Debian 系なら、ディストリビューションのパッケージで入れるのが手軽です。より新しい版が必要な場合は、nginx.org が提供する公式リポジトリも使えます。

sudo apt update
sudo apt install nginx
nginx -v

バージョンによって使えるディレクティブが異なるため、nginx -v の結果は控えておきます。たとえば HTTP/2 の有効化は、新しい版では listen の http2 パラメータではなく http2 on; という独立したディレクティブで書く方式に変わっています(2026年10月現在)。

インストール直後に有効になっている既定のサイト設定は、LB 用の設定と競合しやすいので無効にしておきます。

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

これはシンボリックリンクを外すだけで、元の設定ファイルは /etc/nginx/sites-available/ に残ります。

ステップ2:upstream と転送の設定を書く

/etc/nginx/conf.d/lb.conf を作り、振り分け先と転送のしかたを書きます。

upstream wordpress_backend {
    server 10.0.0.11:80 max_fails=3 fail_timeout=30s;
    server 10.0.0.12:80 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://wordpress_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;
        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;
        proxy_next_upstream error timeout http_502 http_503;
    }
}

それぞれの行には理由があります。

  • Host を引き継がないと、バックエンドの WordPress が別のドメインへのアクセスと解釈し、リダイレクトが繰り返されることがある
  • keepalive と proxy_http_version 1.1、空の Connection ヘッダーの3つをそろえると、LB とバックエンドの接続が使い回され、接続確立の負荷が減る
  • max_fails と fail_timeout は、失敗が続いたサーバーを一定時間振り分け対象から外す設定。オープンソース版の Nginx は、実際のリクエストの失敗を見て判断する「受動的な」チェックのみで、定期的に確認しにいく能動的なヘルスチェックは商用版(NGINX Plus)の機能
  • proxy_next_upstream は、接続エラーやタイムアウト時に別のサーバーで再試行する条件。POST のような冪等でないリクエストは、既定では再送されない

書いたら文法を確認してから反映します。

sudo nginx -t
sudo systemctl reload nginx

設定に誤りがある状態で restart すると Nginx が起動できず、LB 自体が止まります(reload なら古い設定のまま動き続けます)。この2行を毎回セットで実行する習慣にすると事故が減ります。

ステップ3:バックエンド側でクライアントの IP を正しく扱う

LB を通すと、WordPress サーバーから見た接続元はすべて LB の IP(10.0.0.10)になります。このままだと、アクセスログ、コメントの投稿者 IP、ログイン試行の制限などが LB の IP で記録されてしまいます。バックエンドの Nginx に realip モジュールの設定を入れ、LB から届いたときだけ X-Forwarded-For の値を接続元として扱わせます。

# バックエンド(10.0.0.11 / 10.0.0.12)の server ブロック内
set_real_ip_from 10.0.0.10;
real_ip_header X-Forwarded-For;

set_real_ip_from に LB 以外のアドレスを広く書くと、クライアントが偽の X-Forwarded-For を付けるだけで IP を詐称できてしまいます。信頼する範囲は LB のアドレスに限定してください。あわせて、バックエンドの 80 番はファイアウォールで LB からの接続だけを許可します。

# ufw の例(バックエンド側)
sudo ufw allow from 10.0.0.10 to any port 80 proto tcp

ステップ4:LB で HTTPS を終端する

HTTP で振り分けが動くことを確認できたら、LB に証明書を入れて HTTPS を終端します。Let's Encrypt を使う場合は、Certbot の Nginx プラグインで取得と設定の追記ができます(パッケージ名や推奨の入れ方は Certbot の公式手順を確認してください)。

sudo certbot --nginx -d example.com

LB とバックエンドの間はプライベートネットワーク内の HTTP のままにする構成が一般的です。この場合、WordPress からは HTTP で接続されたように見えるため、ステップ2で付けた X-Forwarded-Proto を見て HTTPS と判定させる設定を wp-config.php に入れます。

// LB 経由で HTTPS だったときだけ HTTPS として扱う
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}

これを入れないと、管理画面でリダイレクトが繰り返される、画像や CSS が http:// で読み込まれて混在コンテンツの警告が出る、といった症状が起きます。ステップ3のファイアウォール設定で、バックエンドに外部から直接届かないようにしておくことが、このヘッダーを信頼する前提です。

ステップ5:WordPress を複数台で動かすための準備

LB の設定が正しくても、WordPress 側が1台構成のままだと不具合が出ます。

  • アップロードファイル:管理画面から画像を上げると、受け付けた1台にしか保存されない。共有ストレージやオブジェクトストレージへのオフロードで全台から同じファイルを見られるようにする
  • プラグインやテーマの更新:1台だけ更新されると、台ごとにコードが食い違う。管理画面からの更新を止め、デプロイの仕組みで全台に配る
  • セッション:WordPress のログイン状態は Cookie とデータベースで管理されるため、DB を共有していれば台をまたいでも維持される。PHP セッションを使うプラグインがある場合は、共有のセッション保存先を用意するか、ip_hash などで同じ台に振り分ける
  • オブジェクトキャッシュ:Redis などを使う場合は全台で同じサーバーを参照する
  • WP-Cron:各台で動くと重複実行の原因になるため、DISABLE_WP_CRON を設定し、1か所からシステムの cron で実行する

ステップ6:振り分けと切り離しを確認する

どのサーバーに振り分けられたかをログで見られるよう、LB の http コンテキストにログ形式を追加します。

log_format upstream_log '$remote_addr [$time_local] "$request" $status '
                        'upstream=$upstream_addr up_status=$upstream_status '
                        'up_time=$upstream_response_time';
access_log /var/log/nginx/lb_access.log upstream_log;

外部から何度かアクセスし、upstream= の値が2台に分かれていれば振り分けは動いています。

for i in $(seq 1 10); do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/; done
sudo tail -n 10 /var/log/nginx/lb_access.log

次に、片方のバックエンドの Nginx を止めてアクセスを続け、エラーにならず残りの1台に寄ることを確かめます。受動的なチェックのため、止めた直後の数リクエストで失敗が検知され、その後 fail_timeout の間は外されます。復旧後に再び振り分けが戻ることも確認しておきます。

LB 自体を単一障害点にしない

ここまでの構成では、LB が止まるとサイト全体が止まります。本番運用では、LB を2台にして Keepalived(VRRP)で仮想 IP を引き継ぐ構成や、クラウドのマネージドロードバランサーを前段に置く構成を検討してください。クラウドでは仮想 IP の扱いに制約があることが多いため、利用するサービスの推奨構成を確認します。設定変更の前には、/etc/nginx/ 一式をバックアップしておくと、問題が出たときにすぐ戻せます。

まとめ

  • LB は「HTTP で振り分け → 送信元 IP の処理 → HTTPS 終端 → 確認」の順に組むと、問題の切り分けがしやすい
  • Host と X-Forwarded-* ヘッダーを引き継ぎ、keepalive の3点セットでバックエンドとの接続を使い回す
  • オープンソース版 Nginx のヘルスチェックは受動的で、max_fails と fail_timeout で切り離す
  • バックエンドは LB からの接続だけを許可し、その前提で realip と HTTPS 判定を設定する
  • アップロード・コードの配布・WP-Cron など、WordPress 側の複数台対応も同時に進める
  • LB の冗長化まで考えて、初めて単一障害点のない構成になる

お気軽にご相談ください

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