HTTP を HTTPS にリダイレクトする — 常時 SSL 化
常時 SSL 化とは、サイトの全ページを HTTPS で配信し、http でのアクセスを 301 リダイレクトで https へ恒久的に転送する対応です。通信の盗聴・改ざんを防ぎ、ブラウザの「保護されていない通信」警告を消し、検索でもわずかに有利になります。要点は 3 つ。リダイレクトは 302 ではなく 301 を使う、読み込むリソースも含めて全部を https に揃える、そして HSTS で 2 回目以降の http を無くすことです。
常時 SSL 化とは何ですか?
常時 SSL 化とは、サイトの全ページを HTTPS で配信し、http でアクセスされたら 301 リダイレクトで https へ恒久的に転送する構成のことです。トップページだけでなく、画像やスクリプトを含む全リソースを https で揃えるのが要点で、一部でも http が残ると混在コンテンツとして扱われます。証明書さえ用意すれば、費用も難易度も高くありません。
「常時 SSL 化」は、かつて主流だった「ログインフォームや決済ページだけを https にする」部分的な暗号化に対して、サイト全体を常に https で配信する方針を指す言葉です。今は後者が標準で、http で来たアクセスは すべて https へ転送します。やることは大きく 2 つに分かれます。
- 証明書を用意して https で配信する — サーバーに TLS 証明書を入れ、443 番で応答できるようにする
- http を https へリダイレクトする — 80 番に来たアクセスを 301 で https 側へ恒久転送する
なぜ常時 SSL 化が必要なのですか?
通信の盗聴と改ざんを防ぎ、利用者に安全なページだと示すためです。http は内容が平文で流れるため、公衆 Wi-Fi などで読まれたり書き換えられたりします。HTTPS はこれを暗号化で防ぎます。加えて Google は HTTPS を軽い順位シグナルとして扱い、ブラウザは http ページを「保護されていない通信」と警告するため、放置は信頼と流入の両方を損ないます。
http は通信内容がそのまま流れるため、経路上の第三者に読まれる(盗聴)だけでなく、書き換えられます(改ざん)。 カフェや駅の公衆 Wi-Fi のような共有回線では、これは机上の空論ではなく現実的な脅威です。HTTPS は通信を暗号化し、 相手が本物のサーバーかを証明書で検証することで、この両方を防ぎます。
効果は安全性だけにとどまりません。Google は HTTPS を軽い順位シグナルとして公表しており、 主要ブラウザは http のページに「保護されていない通信」という警告を出します。フォームのある http ページでは 警告がさらに強くなり、利用者の離脱に直結します。安全・信頼・検索の 3 方向で、常時 SSL 化は今や前提です。
なぜ 302 ではなく 301 で恒久リダイレクトするのですか?
301 は「今後はこちらが正式な URL」という恒久移転の宣言で、検索エンジンは評価を https 側へ引き継ぎ、ブラウザも結果をキャッシュして次回から直接 https にアクセスするからです。302 は一時的な移転を意味するため評価が移らず、毎回 http へ来てリダイレクトが挟まります。常時 SSL 化のように「元へは戻さない」転送では、必ず 301 を使います。
301 と 302 は「どちらでもリダイレクトはされる」ので混同されがちですが、検索エンジンとブラウザの扱いが根本的に違います。
| リダイレクト | 意味 | 評価の引き継ぎ | 使う場面 |
|---|---|---|---|
301 | 恒久的な移転 | https 側へ引き継がれる | 常時 SSL 化はこちら |
302 | 一時的な移転 | 引き継がれない | メンテナンス画面など、元に戻す前提の一時転送 |
常時 SSL 化は「もう http には戻さない」転送なので、意味的にも 301 が正しい選択です。302 のままだと、http の URL がいつまでも正規扱いのままで、評価が https 側にまとまりません。
nginx と Caddy ではどう設定しますか?
nginx は http 用の server ブロックで return 301 を返して https 用の server に飛ばし、Caddy はドメイン名を書くだけで証明書取得と http から https へのリダイレクトが自動で有効になります。どちらも www と非 www をどちらか一方へ寄せて統一します。設定後は実際に http へアクセスし、301 で https へ飛ぶことを必ず確認します。
nginx は「http 用」と「https 用」の 2 つの server ブロックを持ち、http 用は転送だけに徹するのが定石です。$request_uri でアクセスされたパスを保ったまま飛ばすと、深いページに来た人も同じページの https 版へ着地します。
# http (80) 用の server は「301 で https へ飛ばすだけ」に徹する
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# アクセスされたパス($request_uri)を保持したまま https へ恒久リダイレクト
# ★ 302 ではなく 301。恒久であることを検索エンジンとブラウザに伝える
return 301 https://example.com$request_uri;
}
# https (443) 用。ここで実際のサイトを配信する
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# www を非 www に寄せる(統一しないと評価が 2 つの URL に分散する)
if ($host = www.example.com) {
return 301 https://example.com$request_uri;
}
# 2 回目以降の http アクセス自体を無くす(HSTS。詳細は security-headers を参照)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
root /var/www/example.com;
}Caddy は考え方が逆で、ドメイン名を書くだけで証明書の取得・更新と http からのリダイレクトが自動になります。 明示的にリダイレクトを書く必要はなく、手数が最も少ない選択肢です。
# Caddy は証明書の取得・自動更新と http から https へのリダイレクトを自動でやる。
# このブロックだけで、80 番へのアクセスは 301 で 443 へ飛ぶ
example.com {
# www で来たら非 www へ寄せる(統一)。permanent = 301
@www host www.example.com
redir @www https://example.com{uri} permanent
# 2 回目以降の http を無くす(HSTS。詳細は security-headers へ)
header Strict-Transport-Security "max-age=31536000; includeSubDomains"
root * /var/www/example.com
file_server
}
# www 用の証明書も取り、非 www へ 301 で集約する
www.example.com {
redir https://example.com{uri} permanent
}どちらの例でも、www と非 www を一方に寄せて統一しています。統一しないと、example.com と www.example.com が別 URL として二重に評価され、被リンクや評価が分散します。 どちらへ寄せても構いませんが、サイト内で首尾一貫させることが大切です。
証明書はどう用意しますか?費用はかかりますか?
証明書は Let's Encrypt などの認証局から無料で取得でき、自動更新も設定できます。nginx なら certbot、Caddy なら組み込み機能が取得と更新を代行するため、有効期限切れで突然 https が使えなくなる事故を防げます。証明書そのものに費用や有償プランは基本的に不要で、常時 SSL 化にかかるコストは実質ゼロに近づきます。
かつて証明書は有償が当たり前でしたが、今は Let's Encrypt が無料で発行し、しかも自動更新できます。 有効期間は 90 日と短めですが、これは自動更新を前提にした設計で、手動での貼り替えを想定していません。
- nginx —
certbotが証明書の取得と、期限前の自動更新(cron / systemd timer)を担う - Caddy — 追加ツール不要。組み込み機能が取得も更新も行う
混在コンテンツ(mixed content)とは何が問題ですか?
混在コンテンツとは、https のページ内で画像・スクリプト・CSS などを http のまま読み込んでいる状態です。ブラウザはスクリプトのような能動的リソースをブロックし、画像などは警告を出します。ページの URL を https にするだけでは不十分で、中で読み込む全リソースの URL も https に揃える必要があります。相対パスを使うと防ぎやすくなります。
ページの URL を https にしても、その中で読み込む画像・スクリプト・CSS の URL が http:// のままだと、そのページは「完全な https」ではありません。これが混在コンテンツで、ブラウザは危険度に応じて挙動を変えます。
| リソースの種類 | http のまま読み込むと |
|---|---|
スクリプト・CSS・iframe(能動的) | ブロックされ、その機能が動かなくなる |
| 画像・動画・音声(受動的) | 読み込まれるが、警告が出て鍵マークが外れる |
対策はシンプルで、ページ内の全リソースの URL を https に揃えることです。自サイト内の参照は/images/logo.png のような相対パスにしておけば、ページのプロトコルに自動で追従するので混在が起きません。 外部サービスを読み込む場合は、そのサービスが https に対応していることを確認します。
リダイレクトだけで十分ですか?HSTS は必要ですか?
301 リダイレクトに加えて、HSTS で 2 回目以降は http を送らせないようにします。301 だけだと初回は必ず一度 http にアクセスし、その隙を突く SSL ストリッピング攻撃が残るからです。HSTS はブラウザに「このドメインは常に https」と記憶させ、初回以降の http アクセス自体を無くします。ただし設定を誤ると解除に時間がかかるため、詳細は別の解説を参照してください。
301 リダイレクトには、原理的に消せない隙が 1 つ残ります。ブラウザが初めてそのサイトへ来るとき、最初の 1 回は http でアクセスすることです。 この 1 回のリダイレクトを通信経路上で握り潰し、http のまま偽サイトへ誘導するのが SSL ストリッピング攻撃です。
Strict-Transport-Security(HSTS)ヘッダを付けると、ブラウザは「このドメインには次から必ず https で行く」と記憶し、 2 回目以降は http アクセス自体が発生しなくなります。上の nginx・Caddy の例にも 1 行だけ含めてあります。 ただし HSTS は設定を誤ると解除に時間がかかるという別の注意点があるため、max-age やincludeSubDomains・preload の扱いは セキュリティヘッダ 7 種の意味と設定 の HSTS の項で詳しく説明しています。
ありがちな失敗は何ですか?
最も多いのは、302 を使ってしまう・一部リソースが http のまま残る・www と非 www の統一が漏れる、の 3 つです。302 は評価が https へ移らず、混在コンテンツはブロックや警告を招き、www の統一漏れは同じ内容が 2 つの URL に分かれて評価が薄まります。いずれも見た目は普通に動いてしまうため気づきにくく、確認して初めて分かります。
- 302 を使っている — 一時リダイレクト扱いになり、評価が https 側へ移らない。CMS やホスティングの既定が 302 のことがある
- 一部リソースが http のまま — 本文は https でも、埋め込み画像や広告タグが http で混在コンテンツになる
- www と非 www の統一漏れ — 両方が生きていて、同じ内容が 2 つの URL に分かれて評価される
- http の server を残したまま放置 — リダイレクトを書き忘れ、http と https の両方が同じ内容を返している
共通するのは、どれも見た目は正常に動いてしまうことです。ブラウザで開けば普通に表示されるため、 意識して確認しない限り気づけません。だからこそ、最後に機械的なチェックを挟む価値があります。
正しく常時 SSL 化できたかどう確認しますか?
コマンドや診断ツールで、http が 301 で https へ飛ぶか、混在コンテンツが残っていないかを確認します。curl -I で http にアクセスすればステータスコードとリダイレクト先が分かり、ブラウザの開発者ツールのコンソールには混在コンテンツの警告が表示されます。本ツールの診断でも、HTTPS 化とリダイレクトの状態を検出します。
# http が 301 で https へ飛ぶか(-I はヘッダのみを取得)
curl -sI http://example.com | grep -iE '^(HTTP|location)'
# → HTTP/1.1 301 Moved Permanently
# Location: https://example.com/
# www が非 www に集約されるかも確認する
curl -sI http://www.example.com | grep -i location
# 302 を返していないか(一時リダイレクトになっていたら設定ミス)
curl -sI http://example.com | grep -i '301\|302'コマンドで見るのは「http が 301 で https へ飛ぶか」と「www が非 www へ集約されるか」の 2 点です。301 Moved Permanently と正しい Location が返れば成功、302 が返っていたら設定ミスです。 混在コンテンツは、ブラウザの開発者ツールのコンソールに出る警告で確認できます。
リダイレクトと同じくサーバー設定で効かせるセキュリティ強化は セキュリティヘッダ 7 種の意味と設定、 https 化で削れるリダイレクトが速度に与える影響は Core Web Vitals — LCP・INP・CLS の改善 を参照してください。