2026年5月24日

2026年5月24日

ロードバランサーでSSLターミネーションする構成と WordPress 側の設定

SSL ターミネーションとは、HTTPS の暗号化をロードバランサー(LB)で解き、背後の Web サーバーには HTTP(または改めて暗号化した通信)で転送する構成です。証明書の管理を LB に集約でき、Web サーバーの台数を増やしても証明書を配り直す必要がなくなります。一方で、WordPress からは「自分は HTTP で呼ばれている」ように見えるため、何もしないとリダイレクトのループや mixed content が起きます。この記事では、構成の選び方、HAProxy を例にした設定、WordPress 側で必要な対応、確認方法を説明します。

3つの構成と選び方

LB で HTTPS を扱う方法には、主に次の3つがあります。

  • ターミネーション(オフロード):LB で復号し、バックエンドへは HTTP で送る。設定が単純で、LB でヘッダーの追加やパスによる振り分けができる
  • 再暗号化(ブリッジ):LB で一度復号してから、バックエンドへも HTTPS で送る。LB での振り分けと、内部経路の暗号化を両立できる
  • パススルー:LB は TCP のまま中継し、復号はバックエンドが行う。LB は中身を見られないので、HTTP ヘッダーによる振り分けや X-Forwarded-For の付与はできない

LB とバックエンドが同じプライベートネットワーク内にあり、その経路を信頼できるならターミネーションで十分なことが多いです。LB とバックエンドの間がデータセンターをまたぐ、共有ネットワークを通る、業界の基準(クレジットカード情報を扱う場合など)で内部通信の暗号化が求められる、といった場合は再暗号化を選びます。

HAProxy でターミネーションする設定例

HAProxy は、証明書と秘密鍵(必要なら中間証明書)を1つの PEM ファイルにまとめて読み込みます。Let's Encrypt の証明書を使う場合は、更新のたびに結合し直して HAProxy を再読み込みする仕組み(certbot の deploy フックなど)を用意しておきます。

# 証明書・中間証明書・秘密鍵を1ファイルにまとめる(パスは環境に合わせる)
sudo cat /etc/letsencrypt/live/example.com/fullchain.pem \
         /etc/letsencrypt/live/example.com/privkey.pem \
  | sudo tee /etc/haproxy/certs/example.com.pem > /dev/null
sudo chmod 600 /etc/haproxy/certs/example.com.pem

設定ファイルの例です。HTTP で来たアクセスは HTTPS へリダイレクトし、バックエンドには「元は HTTPS だった」ことを伝えるヘッダーを付けます。

defaults
    mode http
    option httplog
    timeout connect 5s
    timeout client  30s
    timeout server  60s

frontend fe_web
    bind :80
    bind :443 ssl crt /etc/haproxy/certs/example.com.pem alpn h2,http/1.1
    http-request redirect scheme https code 301 unless { ssl_fc }
    # クライアントが送ってきた値は捨て、LB が判定した値で上書きする
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    option forwardfor
    default_backend be_wp

backend be_wp
    balance roundrobin
    option httpchk
    http-check send meth GET uri /healthz.html ver HTTP/1.1 hdr Host www.example.com
    http-check expect status 200
    server web1 10.0.0.11:80 check
    server web2 10.0.0.12:80 check

set-header は同名のヘッダーを置き換えるので、利用者が偽の X-Forwarded-Proto を送ってきても上書きされます。ヘルスチェック用の healthz.html は、WordPress を通らない静的ファイルにしておくと、PHP の不調と Web サーバーの停止を区別しやすくなります。WordPress のトップページをヘルスチェックに使うと、HTTPS へのリダイレクトで 301 が返ってきて「異常」と判定されることがあるので注意してください。

設定を変える前に現在の設定ファイルをバックアップし、haproxy -c -f /etc/haproxy/haproxy.cfg で文法を確認してから再読み込みします。

クラウドの LB(AWS の Application Load Balancer、Google Cloud の外部アプリケーションロードバランサーなど)でも考え方は同じで、HTTPS リスナーに証明書を設定し、バックエンドへ転送します。これらは X-Forwarded-Proto と X-Forwarded-For を自動で付けるのが一般的です。TLS のバージョンや暗号スイートは、事業者が用意したセキュリティポリシーから選ぶ形式が多く、ポリシー名や推奨値は更新されるため(2026年10月現在)、各社のドキュメントで最新のものを確認してください。TLS 1.2 未満を受け付けない設定にしておくのが現在の一般的な水準です。

WordPress 側で必要な設定

HTTPS であることを WordPress に伝える

WordPress は is_ssl() 関数で HTTPS かどうかを判定します。この関数は $_SERVER['HTTPS'] やポート番号を見るため、LB から HTTP で受け取ると「HTTP で呼ばれた」と判断し、管理画面へのアクセスで HTTPS へリダイレクトし続けたり、CSS の URL を http で出力したりします。

wp-config.php の、require_once ABSPATH . 'wp-settings.php'; より上の位置に次を追加します。

// LB が付けた X-Forwarded-Proto を見て HTTPS と扱う
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
	&& 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
	$_SERVER['HTTPS'] = 'on';
}

この設定は、バックエンドが LB からしか到達できないことが前提です。Web サーバーのポートがインターネットに直接開いていると、誰でもこのヘッダーを付けて HTTPS を装えてしまいます。セキュリティグループやファイアウォールで、バックエンドの 80 番ポートへの接続元を LB に限定してください。

あわせて、管理画面の「設定」→「一般」にある WordPress アドレスとサイトアドレスが https:// になっていることも確認します。

利用者の IP アドレスを取り出す

ターミネーション構成では、Web サーバーから見た接続元は LB の IP になります。アクセスログやログイン試行の制限が LB の IP を対象にしてしまうと、1人の攻撃で全員が締め出されることもあります。nginx をバックエンドにしている場合は realip モジュールで、LB の IP 範囲からの X-Forwarded-For だけを信頼させます。

set_real_ip_from 10.0.0.0/24;   # LB が属するサブネットに合わせる
real_ip_header X-Forwarded-For;
real_ip_recursive on;

セキュリティプラグインにも「プロキシの背後にある場合の IP の取得方法」を選ぶ設定があることが多いので、LB 構成に合わせて見直します。項目名はプラグインによって異なります。

複数台構成で忘れやすいこと

WordPress のログイン状態は Cookie とデータベースで管理されるため、LB でセッションを特定のサーバーに固定(スティッキーセッション)しなくても動くのが普通です。その代わり、アップロードされた画像が1台目にしか保存されない、プラグインの更新が片方のサーバーにしか反映されない、といった問題が起きます。wp-content/uploads を共有ストレージやオブジェクトストレージに置く、デプロイを全台にそろえる、オブジェクトキャッシュを Redis などで共有する、といった対策を組み合わせます。

動作を確認する

LB の外から HTTPS で接続し、証明書チェーンと、バックエンドから返るヘッダーを確認します。

# 証明書チェーンと TLS のバージョンを確認
openssl s_client -connect www.example.com:443 -servername www.example.com < /dev/null 2>/dev/null \
  | grep -E "Protocol|Verify return code|subject=|issuer="

# HTTP から HTTPS へ1回だけリダイレクトされるか
curl -sI http://www.example.com/ | grep -iE "^HTTP|location"
curl -sI https://www.example.com/wp-login.php | grep -iE "^HTTP|location"

Verify return code: 0 (ok) が出ていれば、チェーンに問題はありません。中間証明書が抜けていると、ブラウザでは表示できてもスマートフォンや API クライアントで失敗することがあります。wp-login.php が自分自身へのリダイレクトを繰り返す場合は、wp-config.php の設定が wp-settings.php の読み込みより後ろにないか、LB が X-Forwarded-Proto を付けているかを確認します。

最後に、HSTS(Strict-Transport-Security)を設定するなら LB か Web サーバーのどちらか一方に寄せ、ヘッダーが二重に付かないようにします。最初は短い max-age で試し、問題がないことを確かめてから延ばしてください。

まとめ

  • ターミネーション・再暗号化・パススルーの違いは「どこで復号するか」。内部経路を信頼できない場合は再暗号化を選ぶ
  • LB は X-Forwarded-Proto を上書きで付け、ヘルスチェックは WordPress を通らない静的ファイルにする
  • WordPress には wp-config.php で HTTPS を伝える。ただしバックエンドへの接続元を LB に限定することが前提
  • 実 IP の取り出し、uploads の共有、全台のデプロイ統一を忘れない
  • openssl と curl で、チェーンとリダイレクトの回数を確認する

お気軽にご相談ください

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