.htaccessでHTTPSを強制する方法
.htaccessのApache書き換えルールでHTTPSを強制し、CDNやロードバランサー背後のリダイレクトループを修正、wwwとHSTSも設定します。
Apacheですべてのトラフィックに対してHTTPSを強制するには、サイトルートの.htaccessファイルにRewriteEngine On、RewriteCond %{HTTPS} off、RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]の3行を追加します。
フォーラムの回答からリダイレクトルールを貼り付けた後、ブラウザがループし続けて最終的に諦めるという経験をしたことがあるなら、ルール自体はおそらく問題なかったはずです。多くの場合、問題の原因はサーバーの前段に配置されているコンポーネントにあります。
このルールは、プレーンなHTTPで届くすべてのリクエストをキャッチし、同一URLのHTTPS版への恒久的なリダイレクトを発行します。mod_rewriteが有効なApache環境でSSL証明書がインストール済みであれば機能しますが、CDNやロードバランサーがオリジンの前段に配置されている場合は、特定の予測可能な形で失敗します。本ガイドでは、まずコピー&ペーストで使えるルールを示し、次にドメイン・フォルダ・wwwのバリエーション、リダイレクトループの修正方法、そしてApache以外の環境での対処法を解説します。
重要なポイント
- 標準的なルールは
RewriteCond %{HTTPS} offをテストし、https://%{HTTP_HOST}%{REQUEST_URI}にリライトします。これにより、単一ドメインをハードコーディングするのではなく、訪問者がリクエストした正確なドメインとパスが保持されます。 R=301は恒久的なリダイレクトを発行し、Lはそのルールでリライト処理を停止します。テスト中は、ブラウザが301を積極的にキャッシュするため、まずR(一時的な302)を使用してください。誤った301は修正が困難です。- HTTPSの強制は、有効なTLS/SSL証明書がすでにインストールされている場合にのみ機能します。証明書なしでリダイレクトすると、サイトはセキュアになるのではなく、アクセス不能になります。
- TLS終端プロキシの背後では
%{HTTPS}がonになることはないため、ルールがERR_TOO_MANY_REDIRECTSでループします。代わりに%{HTTP:X-Forwarded-Proto}をテストしてください。 - CloudflareのFlexible SSLループはCloudflare側の設定ミスであり、
.htaccessを編集するのではなく、暗号化モードを変更することで修正します。
始める前に:SSL証明書とmod_rewrite
HTTPSの強制は、ドメインに有効なTLS/SSL証明書がすでにインストールされている場合にのみ機能します。証明書なしでHTTPSにリダイレクトしても、サイトはセキュアになりません。ブラウザのセキュリティ警告の背後でアクセス不能になるだけです(「SSL証明書」は業界の一般的な用語ですが、実際のプロトコルはTLSです)。.htaccessを編集する前に、ブラウザで直接https://yourdomain.comを読み込み、南京錠アイコンが表示されることで証明書が有効であることを確認してください。
以下のルールはApacheのmod_rewriteモジュールに依存しており、ほとんどの共有ホスティングやcPanelホスティングではデフォルトで有効になっています。.htaccessファイルはサイトルート(通常はpublic_htmlまたはドメインのドキュメントルート)に配置されています。cPanelのファイルマネージャー(ドットファイルを表示するには「隠しファイルを表示」を有効にしてください)、FTP、またはSSH経由で編集できます。ルールが誤動作した場合に復元できるよう、編集前にファイルをバックアップしてください。
すべてのトラフィックにHTTPSを強制する.htaccessルール
すべてのHTTPリクエストをHTTPSにリダイレクトするには、サイトルートの.htaccessファイルに以下を貼り付けてください:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
各行の説明:RewriteEngine Onはリライトエンジンを有効にします。RewriteCond %{HTTPS} offは接続がまだ暗号化されていない場合にのみルールを発動させます。RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}はURLをHTTPS上で再構築します。%{HTTP_HOST}と%{REQUEST_URI}変数は訪問者がリクエストした正確なドメインとパスを保持するため、このルールは複数のドメインにわたって機能し、暗黙的にwwwを強制することもありません。
フラグ[L,R=301]において、R=301は恒久的なリダイレクトを発行し、Lはそのルールでリライト処理を停止します。テスト中は、ブラウザが301を強くキャッシュするため、まずR単体(一時的な302)を使用してください。誤った301の修正は困難です。リダイレクトが正常に解決されることを確認した後にのみR=301に切り替えてください。
RewriteEngine Onを重複して記述しないでください。 この行がすでにファイルに存在する場合は、その下にRewriteCondとRewriteRuleのみを追加してください。
バリエーション:特定ドメイン、フォルダ、wwwの正規化
同じドキュメントルートを指す複数のドメインのうち、特定の1つにのみHTTPSを強制するには、HTTP_HOSTに対する条件を追加します:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
NCフラグはホストのマッチングを大文字小文字を区別しないようにします。HTTPSとwww/非wwwの正規化を組み合わせるには、htaccessbookが両方のリダイレクトをmod_rewriteガードでラップする方法を紹介しています:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
このブロックの公開バージョンではRewriteEngine Onがファイルの前の方に記述されていることを前提としているため、スニペット単体で動作するように上記に追加しています。最初のルールはリクエストをHTTPSに移行させます。2番目のルールはwwwがないホストにwwwを付加します。[L]はルールがマッチした時点で処理を終了するため、wwwなしのプレーンなHTTPリクエストは1回ではなく2回のリダイレクトが発生することに注意してください:最初にHTTPSへ、次にwwwホストへ。ルールを<IfModule mod_rewrite.c>でラップすることで、mod_rewriteがロードされていない場合に500エラーをスローするのではなく、サイトがHTTPで提供されるフェイルオープン動作になります。
HTTPS、wwwの正規化、いくつかのリダイレクト、キャッシュブロックを同じファイルで組み合わせると、これらのルールを手動で積み重ねるのは煩雑になります。フラグの誤りやルールの順序の間違いが本番環境で問題を引き起こします。OpenReplayのhtaccessジェネレーターを使えば、トグルのセットからファイルを自動生成できます:HTTPSの強制、wwwの追加または削除、301または302リダイレクトの追加、gzipとブラウザキャッシュの有効化、IPのブロック、カスタムエラーページのマッピングなどが可能です。出力はコメント付きで、オプションを変更するたびに更新され、すべてブラウザ内で実行されるため、コピーアウトまたはダウンロードして既存のファイルと差分を確認できます。
CDNやロードバランサー背後でのERR_TOO_MANY_REDIRECTSの修正
リダイレクトがERR_TOO_MANY_REDIRECTSを引き起こす場合、ブラウザが多くのホップを追跡して諦めており、通常の原因はTLS終端プロキシまたはロードバランサーです。TLSはプロキシで終端されるため、オリジンでは%{HTTPS}がonになることはなく、ルールはすべてのリクエストで発動し、ループが終わりません。修正方法は、転送されたスキームを信頼することです:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
ここでRewriteCond %{HTTP:X-Forwarded-Proto} !httpsはプロキシが設定するX-Forwarded-Protoヘッダーを読み取るため、元の訪問者接続がHTTPであった場合にのみルールが発動します。R=301に昇格させる前にRでテストしてください。
CloudflareのFlexible SSLループは、異なる原因を持つ別の問題です。Flexible暗号化では、Cloudflareとサーバー間のホップが暗号化されていないため、HTTPSを要求するオリジンルールがリクエストを送り返し続けます。Cloudflareには2つの解決策があります:オリジンでのHTTPSリダイレクトを削除するか、ゾーンをFullまたはそれ以上のモードに移行する(オリジン自体に証明書が必要)かです。どちらの変更もCloudflareダッシュボードで行い、.htaccessは編集しません。Flexibleモードの訪問者は引き続きHTTPSでブラウジングしており、CloudflareがX-Forwarded-Protoで報告するスキームは訪問者自身の接続を反映するため、上記のヘッダーテストはここでは誤動作しません。それでも、暗号化モードの修正が本質的な解決策です。
変更後は、キャッシュされた301が修正を隠す可能性があるため、再テスト前にブラウザのキャッシュとCookieをクリアしてください。特定のプロキシ経由で到着するユーザーにのみ影響する条件付きループは、自分のブラウザからの単一の手動テストでは見えません。移行後のサイトのセッションリプレイは、実際のユーザーが遭遇する断続的なリダイレクトループや混在コンテンツの問題を、無限バウンスパターンとして表面化させることができます。
.htaccessが適切なツールでない場合
.htaccessはApache専用であり、Apacheベースのホスティングでのみ読み取られます。Nginxには.htaccessファイルがありません。Nginxでは、ポート80でリッスンしてリダイレクトを返すサーバーブロックでHTTPSを強制します:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
return 301はポート80のブロックにのみ記述してください。443ブロック内に記述するとループが再発します。モダンなスタックでは、HTTPSの強制はサーバー設定ではなく、CDN、プラットフォーム、またはロードバランサー層で行うことが多くなっています。
リダイレクトが機能したら、HSTSヘッダーで強化することで、ブラウザが自動的にHTTPSで接続し、安全でないHTTPリクエストを完全にスキップするようになります。HSTSはRFC 6797で定義されており、OWASPのHSTSチートシートはStrict-Transport-Security: max-age=63072000; includeSubDomains; preloadを推奨しています。preloadは一方通行の扉として扱ってください:リストからドメインを削除するのは時間がかかり、その間にHTTPへのフォールバックが必要になった場合、訪問者はドメインとその配下のすべてにアクセスできなくなる可能性があります。
自分の環境に合ったルールを選択し、一時的な302でデプロイし、リダイレクトが1ホップで解決することを確認してから、恒久的な301に昇格させてHSTSを追加してください。このシーケンスにより、5分間の変更を障害に変えてしまうリダイレクトループやキャッシュの誤りなしにHTTPSを強制できます。
よくある質問
HTTPSを強制する際の301リダイレクトと302リダイレクトの違いは何ですか?
301は恒久的なリダイレクト、302は一時的なリダイレクトです。ブラウザは301を積極的にキャッシュして長期間保持するため、誤った301は元に戻すのが困難です。HTTPSリダイレクトをテストする際は、まずRewriteRuleフラグにR(302)を使用し、リダイレクトが1ホップで正常に解決することを確認してから、恒久的なバージョンとしてR=301に昇格させてください。
ブラウザのキャッシュをクリアするだけでなく、HTTPSリダイレクトが正しく解決されているかどうかを確認するにはどうすればよいですか?
コマンドラインからcurl -IL http://yourdomain.comを実行してください。-Iフラグはヘッダーのみをリクエストし、-Lはリダイレクトを追跡するため、完全なチェーンを確認できます。正しい設定では、https URLを指すLocationヘッダーを含む単一の301が返され、その後セキュアなアドレスで200が返されます。繰り返す301やhttpへのリダイレクトが見られる場合は、ループが発生しています。これはキャッシュされたブラウザタブを検査するよりも確実な方法です。
HTTPSリダイレクトがリダイレクトせずに500エラーをスローするのはなぜですか?
500エラーは通常、mod_rewriteがロードされていないにもかかわらず、ルールがRewriteEngineまたはRewriteRuleを直接呼び出していることを意味します。ルールをIfModule mod_rewrite.cガードでラップすることで、モジュールが存在しない場合にApacheがそれらをスキップしてHTTPで提供するようになります。ほとんどの共有ホスティングやcPanelホスティングではmod_rewriteはデフォルトで有効ですが、有効であることを確認できない場合はガードを使用するのが安全なパターンです。
.htaccessのHTTPSルールはAWS Application Load Balancerや他のTLS終端プロキシで機能しますか?
標準的な%{HTTPS} offルールでは機能しません。AWS ALBや同様のロードバランサーがTLSを終端する場合、暗号化接続はプロキシで終了し、ApacheオリジンはプレーンなHTTPのみを受け取るため、%{HTTPS}がonになることはなく、ルールはERR_TOO_MANY_REDIRECTSでループします。代わりに、プロキシが元の訪問者プロトコルを報告するために設定するヘッダーを読み取るRewriteCond %{HTTP:X-Forwarded-Proto} !httpsをテストしてください。