.htaccessでURLを1つにまとめる|https・www・拡張子なし・index.phpの301設定
「http」と「https」、「www あり」と「なし」、「/about.php」と「/about」。何気なく作ったサイトでも、同じページが何通りものURLで開けてしまうことがあります。このサイトで実際に使っている設定をもとに、URLを1つにまとめる手順を整理します。
なぜURLを1つにまとめる必要があるのか
たとえば次の4つのURLは、何も設定していないと同じページを表示することがあります。
http://example.com/about.php
http://www.example.com/about.php
https://example.com/about.php
https://www.example.com/about
人が見る分には困りませんが、検索エンジンからは別々のページに見える可能性があります。評価が複数のURLに分散したり、意図しないURLが検索結果に出たりする原因になります。SNSで共有されるURLがばらばらだと、アクセス解析の集計も分かりにくくなります。
そこで「正しいURLはこれ」と1つ決め、それ以外でアクセスされたときは301リダイレクト(恒久的な転送)で正しいURLへ案内します。これをURLの正規化と呼びます。
作業の前に必ずやること
- 今の
.htaccessをダウンロードして、.htaccess.bkなどの名前で手元に保存します。設定を誤るとサイト全体が表示されなくなることがあるためです。 - サーバーの管理画面で、SSL(https)が有効になっていることを確認します。証明書がない状態でhttpsへ転送すると、警告画面が表示されてしまいます。
- 正規にするURLを決めます。「wwwあり・https・拡張子なし・末尾スラッシュはフォルダのみ」のように、ルールを文章で書き出しておくと迷いません。
設定例と、それぞれの意味
以下は、wwwありのhttpsに統一し、.phpを隠す場合の例です。example.com の部分はご自身のドメインに置き換えてください。
1. httpsとwwwを統一する
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L,NE]
「httpsでない」または「wwwが付いていない」場合に、wwwありのhttpsへ転送します。2つの条件を1つのルールにまとめているので、http://example.com でアクセスされても転送は1回で済みます。転送が何段階も続くと表示が遅くなるため、なるべく1回で目的地に着くようにするのがコツです。
なお、レンタルサーバーによっては環境変数 HTTPS が正しく渡らない構成もあります。転送が止まらなくなった場合は、%{HTTP:X-Forwarded-Proto} を使う書き方をサーバーのマニュアルで確認してください。
2. index.php を取り除く
RewriteCond %{THE_REQUEST} \s/+(.*/)?index\.(php|html?)\s [NC]
RewriteRule ^(.*/)?index\.(php|html?)$ /$1 [R=301,L,NE]
/blog/index.php を /blog/ へ転送します。ポイントは THE_REQUEST を条件にしていることです。これは「ブラウザが実際に送ってきたリクエストの1行目」で、サーバー内部での書き換えの影響を受けません。これを使わないと、内部でindex.phpを呼び出すたびに転送が発生し、無限ループになることがあります。
3. .php をURLから隠す
# 拡張子付きでアクセスされたら、拡張子なしへ転送
RewriteCond %{THE_REQUEST} \s/+(.+?)\.(php|html?)\s [NC]
RewriteRule ^(.+?)\.(php|html?)$ /$1 [R=301,L,NE]
# 拡張子なしURLで、対応する .php を内部的に表示
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
前半は「見えるURL」を整えるための転送、後半は「中身を表示する」ための内部書き換えです。後半には R=301 が付いていないため、ブラウザのアドレス欄は /about のまま、サーバーの中では about.php が実行されます。
3つの条件は順に「フォルダではない」「ファイルとして存在しない」「同じ名前の.phpがある」という意味です。この条件がないと、画像やCSSまで書き換えの対象になってしまいます。
ルールの順番がとても大切
.htaccess のルールは上から順に評価されます。一般的には次の順番にすると、転送の回数が少なく、ループも起きにくくなります。
| 順番 | 内容 | 種類 |
|---|---|---|
| 1 | https・wwwの統一 | 301転送 |
| 2 | index.php の除去 | 301転送 |
| 3 | 拡張子の除去 | 301転送 |
| 4 | 拡張子なしURLの内部表示 | 内部書き換え |
| 5 | 存在しないURLを404にする | エラー応答 |
転送系のルールを先に、内部書き換えを後にまとめるのが基本です。途中に別の書き換えを差し込む場合も、この流れを崩さないように位置を選びます。
設定後の確認方法
ブラウザでの確認だけでは、キャッシュの影響で古い結果を見てしまうことがあります。ターミナルが使えるなら、curl で転送先を直接確認するのが確実です。
curl -I http://example.com/about.php
結果に HTTP/1.1 301 と Location: https://www.example.com/about が表示されれば成功です。続けて、転送先のURLが 200 を返すことも確認します。
- httpとhttps、wwwありとなしの4通りすべてで確認する
- トップページ、下層ページ、フォルダのindexの3種類を試す
- 画像やCSSが正しく表示されているか(書き換えに巻き込まれていないか)を見る
- お問い合わせフォームなど、POST送信するページが動くかを試す
最後のフォームの確認は忘れがちです。送信先のURLに .php が付いていると、301転送の際に送信内容が失われることがあります。フォームの送信先は、あらかじめ拡張子なしの正規URLに書き換えておきましょう。
よくあるトラブル
- 「リダイレクトが多すぎます」と表示される
- 転送ルールが互いに転送し合ってループしています。
THE_REQUESTを使っているか、サーバー側の管理画面でも同じ転送設定をしていないかを確認します。 - 500 Internal Server Error になる
- 記述ミスか、サーバーが対応していない命令を使っています。直前に追加した行をコメントアウト(行頭に
#)して、どの行が原因かを切り分けます。 - 設定を変えても結果が変わらない
- 301転送はブラウザに強くキャッシュされます。シークレットウィンドウで試すか、
curlで確認してください。
一から書くのが不安な場合は、選択肢を選ぶだけで設定のたたき台を作れる.htaccess生成補助ツールも公開しています。生成した内容も、必ずバックアップを取ってから反映してください。