2026年8月8日

2026年8月8日

AWS CLB(Classic Load Balancer)でSSL終端する手順とWordPress側の設定

AWS の Classic Load Balancer(CLB)でSSL終端を行うには、HTTPS リスナー(ロードバランサー側443番)からインスタンス側の HTTP 80番へ転送する構成を作り、証明書と TLS のセキュリティポリシーをリスナーに設定します。そのうえで WordPress 側に「LB の手前では HTTPS だった」ことを伝える設定を入れれば、リダイレクトループや混在コンテンツを避けられます。この記事では、証明書の用意からリスナー作成、ポリシー選択、WordPress とWebサーバーの設定、動作確認までを順に説明します。

始める前に:CLB は前世代のロードバランサー

CLB は AWS で「前世代」と位置づけられており、新規構築では Application Load Balancer(ALB)か Network Load Balancer(NLB)が推奨されています(2026年10月現在)。ALB なら HTTP から HTTPS へのリダイレクトをLB側で設定でき、SNI による複数証明書にも対応します。既存の CLB を当面使い続ける場合や、移行前に HTTPS 化だけ済ませたい場合に、この記事の手順が役立ちます。

作業前に次の点を確認してください。

  • 既存リスナーとヘルスチェックの設定を控えておく(aws elb describe-load-balancers の出力を保存しておくと戻すときに便利です)
  • WordPress のデータベースと wp-config.php をバックアップする
  • 可能ならステージング環境の CLB で一度試す

構成の考え方

SSL終端とは、TLS の暗号化をロードバランサーで解き、背後のインスタンスへは HTTP で転送する方式です。証明書の管理がLBの1か所にまとまり、インスタンス側で証明書を更新する必要がなくなります。

一方で、インスタンスから見るとすべてのリクエストが HTTP で届きます。WordPress は「自分は HTTP で呼ばれている」と判断するため、サイトURLが https なのにリクエストは http という食い違いが起き、管理画面へのログインでリダイレクトが繰り返される、という典型的なトラブルにつながります。これを防ぐのが、CLB が付けるヘッダー X-Forwarded-Proto です。CLB は HTTP/HTTPS リスナーで X-Forwarded-For、X-Forwarded-Proto、X-Forwarded-Port を付けて転送します。

LB とインスタンスの間も暗号化したい場合は、インスタンス側のプロトコルを HTTPS にする方法もあります。社内規程で経路全体の暗号化が求められる場合は、こちらを検討してください。

手順1:証明書を用意する

CLB のリスナーには、AWS Certificate Manager(ACM)の証明書か、IAM にアップロードした証明書を指定できます。ACM の公開証明書は DNS 検証にしておけば自動更新されるため、更新忘れの心配が減ります。証明書は CLB と同じリージョンで発行してください。リージョンが違うと選択肢に出てきません。

CLB は1つのリスナーに1枚の証明書しか設定できず、ALB のように SNI で複数の証明書を出し分けることはできません。example.com と www.example.com の両方を同じ CLB で受けるなら、両方の名前を含む証明書(SAN 付き)を発行します。

手順2:HTTPS リスナーを追加する

コンソールでは CLB の「リスナー」設定から追加できますが、画面の表記は変わることがあるため、ここでは AWS CLI の例を示します。値は自分の環境に置き換えてください。

aws elb create-load-balancer-listeners \
  --load-balancer-name my-clb \
  --listeners "Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80,SSLCertificateId=arn:aws:acm:ap-northeast-1:123456789012:certificate/your-certificate-id"

あわせて CLB のセキュリティグループで 443番の受信を許可します。インスタンス側のセキュリティグループは、80番の受信元を CLB のセキュリティグループだけに絞ってください。後で WordPress に X-Forwarded-Proto を信用させるため、インスタンスへ直接アクセスされてヘッダーを偽装される経路を塞いでおく意味があります。

証明書を差し替えるときは次のコマンドを使います。

aws elb set-load-balancer-listener-ssl-certificate \
  --load-balancer-name my-clb \
  --load-balancer-port 443 \
  --ssl-certificate-id arn:aws:acm:ap-northeast-1:123456789012:certificate/your-new-certificate-id

手順3:TLS のセキュリティポリシーを選ぶ

CLB の HTTPS リスナーには、使用する TLS バージョンと暗号スイートを決める「セキュリティポリシー」を設定します。AWS があらかじめ用意したポリシーから選ぶのが基本で、古いクライアント対応が不要なら TLS 1.2 以上に限定したポリシーを選びます。

aws elb create-load-balancer-policy \
  --load-balancer-name my-clb \
  --policy-name tls12-only \
  --policy-type-name SSLNegotiationPolicyType \
  --policy-attributes AttributeName=Reference-Security-Policy,AttributeValue=ELBSecurityPolicy-TLS-1-2-2017-01

aws elb set-load-balancer-policies-of-listener \
  --load-balancer-name my-clb \
  --load-balancer-port 443 \
  --policy-names tls12-only

用意されているポリシー名は aws elb describe-load-balancer-policies で一覧できます。CLB は TLS 1.3 に対応していないとされているため、TLS 1.3 が必要な場合は ALB/NLB への移行が現実的です。

手順4:WordPress に HTTPS を認識させる

wp-config.php の require_once ABSPATH . 'wp-settings.php'; より前に、次のコードを追加します。

// CLB で SSL 終端している場合、元のプロトコルを WordPress に伝える
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}

これで is_ssl() が true を返し、ログインCookieやURL生成が https 前提で動きます。このヘッダーはクライアントが自由に付けられるため、手順2のとおりインスタンスへの直接アクセスを塞いでいることが前提です。

次に、管理画面の「設定」→「一般」で WordPress アドレスとサイトアドレスを https に変更します。本文中に http の画像URLが残っている場合は、バックアップを取ったうえで WP-CLI の置換を使います。まず --dry-run で件数を確認してから実行してください。

wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run

手順5:HTTP から HTTPS へリダイレクトする

CLB にはリダイレクト機能がないため、インスタンス側で X-Forwarded-Proto を見てリダイレクトします。ここで注意したいのがヘルスチェックです。CLB のヘルスチェックはインスタンスの80番へ直接届き、X-Forwarded-Proto が付きません。ヘルスチェックのパスまで301を返すと、CLB は 200 以外を異常とみなし、全インスタンスが切り離されてしまいます。

Apache(.htaccess)の例です。

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteCond %{REQUEST_URI} !^/healthcheck\.html$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Nginx の例です。

location = /healthcheck.html {
    access_log off;
}

location / {
    if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
    }
    try_files $uri $uri/ /index.php?$args;
}

ヘルスチェック先には静的ファイル healthcheck.html を置くと、PHP やDBの負荷を増やさずに済みます。DB まで含めて監視したい場合は別の監視ツールで行う、と役割を分けるのが無難です。

手順6:アクセスログに本当の訪問者IPを残す

SSL終端構成では、Webサーバーのログに記録される接続元が CLB のIPになります。セキュリティプラグインのログイン試行制限なども、すべて同じIPからのアクセスとして扱ってしまうことがあります。Apache なら mod_remoteip、Nginx なら realip モジュールで、信頼できる送信元(VPC の CIDR)から来た X-Forwarded-For だけを採用します。

set_real_ip_from 10.0.0.0/16;   # VPC の CIDR に置き換える
real_ip_header X-Forwarded-For;
real_ip_recursive on;

動作確認

確認は外部から行います。

# 証明書の発行先と有効期限
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -dates

# HTTP が HTTPS へ 301 されるか
curl -sI http://example.com/ | head -n 5

# TLS 1.1 が拒否されるか(拒否されれば handshake エラーになる)
openssl s_client -connect example.com:443 -servername example.com -tls1_1 < /dev/null

あわせて、CLB の画面でインスタンスが「InService」になっているか、管理画面へログインできるか、ブラウザの開発者ツールで混在コンテンツの警告が出ていないかを確認します。

つまずきやすい点

  • ログインがループする:wp-config.php の追記が wp-settings.php の読み込みより後ろにある、またはヘッダー名の綴りが違う、が主な原因です
  • 全インスタンスが OutOfService になる:ヘルスチェックのパスがリダイレクトされているか、セキュリティグループで CLB からの80番が閉じています
  • 証明書が選べない:ACM の証明書が別リージョンで発行されているか、検証がまだ完了していません
  • CloudFront と併用している:CloudFront からオリジンへのプロトコルと CLB のリスナーの組み合わせによっては、X-Forwarded-Proto が期待した値にならないことがあります。どの区間が HTTPS かを図にして確認すると原因を見つけやすくなります

まとめ

  • CLB の SSL 終端は「HTTPS 443 → HTTP 80」のリスナーに ACM 証明書とセキュリティポリシーを設定して行う
  • CLB は1リスナー1証明書で、リダイレクト機能もない。前世代扱いのため、新規なら ALB/NLB を選ぶ
  • WordPress には X-Forwarded-Proto を見て $_SERVER['HTTPS'] を立てる設定を入れ、インスタンスへの直接アクセスはセキュリティグループで塞ぐ
  • リダイレクトはインスタンス側で行い、ヘルスチェックのパスは除外する
  • 作業前のバックアップと、外部からの openssl/curl での確認を忘れずに行う

お気軽にご相談ください

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