サイトを運営していると、URLの制御やSEO対策、ファイルのキャッシュ対策などで触れる機会がある、.htaccessファイル。
プログラムを触る機会がある人であっても、慣れるまでは分かりにくいと感じることが多いと思います。
この記事では、サイトを運用する上でまず必要になる.htaccessの設定を紹介しながら、.htaccessの理解が深まるようリライトルールについて解説します。
この記事では、リダイレクトの条件判定の際に正規表現が毎回出てきます。正規表現について知識のない方は、先に正規表現についての理解をお願いします。
目次
httpsへのリダイレクト
WEBサイトはSSL化することで多くのメリットがあります。
単にSSL化しただけでは、まだhttpのURLにアクセスが可能です。.htaccessでhttpsにリダイレクトしておきます。
<IfModule mod_rewrite.c>
RewriteEngine On
# httpsへリダイレクト
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
コードの解説です。最初ですので、詳しく解説していきます。
<IfModule mod_rewrite.c>
これは、URLのリライトモジュールを使用可能であるかを判定しています。
RewriteEngine On
この行は、リライトモジュールを有効化しています。
このような行のことをディレクティブと呼ばれます。
コメント
.htaccessでは#をつけることでコメントを記述することができます。
RewriteCond
RewriteCondは、直後のRewriteRuleを適用するかどうかの条件式を指定する命令です。
ここでは、%{HTTPS}がoffである時、つまりhttpの時に直下のRewriteRule
の行を適用します。
RewriteRule
これはリダイレクト処理をする命令です。スペースで区切られ、1つ目のテキストは対象となるURIのパターンを示し、2つ目のテキストは、書き換え後のURIを示します。このルールによって、指定されたURIパターンに一致するとき、URIが新しい形式に書き換えられます。
ここでは^(.*)$
は全ての文字列であるという正規表現です。今回はどんなURLの時でも、https://%{HTTP_HOST}%{REQUEST_URI}にURLを書き換えます。%{HTTP_HOST}はexample.comなどのドメインを出力し、%{REQUEST_URI}はドメイン以降に記載されていたURLを出力します。
最後の[R=301,L]
の部分はフラグと呼ばれます。
R=301
は301リダイレクトであることを指定しています。
L
はルールが終了することを指定します。[L]があったとき、それ以降のリライトルールは適用されません。
ここで注意するのが、RewriteCond
でルールがスキップされたときは[L]も発動しません。今回の例では、httpsでアクセスされた際にはリライトルールが適用されないので、下に記述されているリライトルールは適用されます。
また、[R=301,L]
のように複数指定する際に、,
の前後にスペースは入れてはいけないことを注意してください。
wwwの省略
URLを正確に記述すると、www.example.comのような形式です。wwwは"World Wide Web"の略であり、省略することも可能です。URLは短い方が、覚えやすいためwwwを省略する記述が好まれることも多いでしょう。
初期設定では、wwwありでもなしでもアクセスできる状態になっています。この状態ではページのSEOのリンクの効果が分散してしまう可能性があります。ですので、wwwの有無は.htaccessで統一しておいた方が良いでしょう。
先ほどのSSL化のリダイレクトのコードが書いてある場合、その下に記載しなければいけないことを注意しましょう。
wwwなしで統一
URLにwwwが含まれるときにwwwなしのURLにリダイレクトするルールを追加します。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
</IfModule>
今回新しいのは[NC]
のフラグのみですね。[NC]
は正規表現による比較の際に大文字と小文字を区別しなくなります。
今回の例では、www.example.comであっても、Www.example.comであっても、WWW.example.comであっても判定が真になります。
wwwありで統一
URLにwwwが含まれないとき、wwwありのURLにリダイレクトするルールを追加します。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
wwwなし統一のコードとおこなっていることはほとんど同じです。
index.html(.php)の有無を変更
index.html(.phpも同様)は、ディレクトリにアクセスした際に表示される初期のファイルです。example.com/にアクセスした際は、example.com/index.htmlにアクセスしていることと同義になります。
これもwwwと同様index.htmlがある状態でもない状態でも同一ページが表示されるのはSEO観点で問題があるので、どちらかに統一するリダイレクト処理をしましょう。
index.html(.php)なしに統一
この.htaccessはルートディレクトリに記述する必要があります。ルートディレクトリ以外に.htaccessを設置したい場合は、RewriteBaseのディレクティブを指定する必要があります。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{THE_REQUEST} /index\.(html|php?) [NC]
RewriteRule ^(.*?)index\.(html|php?)$ /$1 [R=301,L]
</IfModule>
%{THE_REQUEST}
を新たに使用しています。この変数は、ドメイン以降のHTTPリクエストを保持します。
例えば、example.com/post/index.phpにアクセスした際は、「GET /post/index.php HTTP/1.1」になります。
ここが、%{REQUEST_URI}
ではいけない理由を説明します。WordPressを利用している場合で記事ページを「example.com/post/123/」のようなURLでアクセスできるように設定しているとします。
この場合、WordPressが管理しているリライトが働き、リクエストは「example.com/index.php?p=123」へリダイレクトされます。ここで、%{THE_REQUEST}
と%{REQUEST_URI}
で挙動に下記の差が出ます。
%{THE_REQUEST}
:GET /post/123/ HTTP/1.1
%{REQUEST_URI}
:/index.php?p=123
つまり、%{REQUEST_URI}
を用いると、WordPressのような内部リライトが行われている場合、予期せぬ挙動をしてしまいます。上記の例だと、「example.com/post/123/」アクセスした際に、「example.com/」にリダイレクトされてしまいます。
index.html(.php)ありに統一について
index.htmlをありはいくつかの問題を考慮しなければいけません。
まず、ディレクトリによってはindex.htmlまたはindex.phpを設置していない可能性もあると思います。また、リダイレクトは、index.htmlかindex.phpかをあらかじめ決定しておく必要があります。
WordPressで運用している場合は、/post/123/のようなURL構造にすることがあります。この場合、/post/123/というディレクトリは存在しないせず、内部リライトでindex.php?p=123になっているため、index.phpありであるという解釈されます。
以上から、自分の環境によって適切なリライト処理を行わなければいけません。
ここではexample.comのようにトップドメインにアクセスした際に、index.htmlのURLにリダイレクトする方法のみ紹介します。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^$ /index.html [R=301,L]
</IfModule>
WordPressのデフォルトのfaviconを変更する
WordPressを使っている場合、初期状態ではfaviconはWordPressのアイコンになっています。
WordPressでは、まずトップドメイン直下の/favicon.icoを参照し、/wp-includes/images/w-logo-blue-white-bg.pngにリダイレクトさせています。このリダイレクト先をオリジナルアイコンのパスに置き換えることで、faviconをオリジナルアイコンに変更することができます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^favicon\.ico$ /wp-content/themes/theme/favicon/favicon.ico [R=301,L]
</IfModule>
ここで、RewriteBase
のディレクティブを新しく使用しています。これは参照する位置を指定することができるディレクティブです。
.htaccessは初期状態では、設置しているところからの相対参照をします。今回の例ではRewriteBase /
とすることで、トップドメイン直下のfavicon.icoにアクセスされていることを示せるようになります。
example.com/favicon.icoにアクセスした際にリダイレクトが行われます。
もしRewriteBase /
を記述せずWordPressのインストール箇所がサブディレクトリである場合、(wpディレクトリなど)example.com/wp/favicon.icoからのリダイレクトになってしまいます。
また、変更先のfavicon.icoはWordPressの適用テーマのfaviconディレクトリに保存しているとしました。ここでは「wp-content/themes/theme/favicon/favicon.ico」になっています。WordPressのインストールされている場所がトップドメイン直下でない場合は「/wp/wp-content/themes/theme/favicon/favicon.ico」のようにトップドメインからのパスを指定してください。
今までのリライトモジュールをまとめる
いくつかのリライト処理を紹介しましたが、IfModuleとRewriteEngineは一度の記述でまとめることができます。
それでは、SSL化をし、wwwとindex.phpの記述は無しにするリライトルールをまとめて記述してみます。
<IfModule mod_rewrite.c>
RewriteEngine On
# httpsへリダイレクト
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# www無しにリダイレクト
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
#index.phpなしにリダイレクト
RewriteCond %{THE_REQUEST} /index\.(html|php?) [NC]
RewriteRule ^(.*?)index\.(html|php?)$ /$1 [R=301,L]
</IfModule>
このように一つのモジュールを一箇所にまとめることができます。
WordPressが制御するリライト処理
WordPressを導入しているWEBサイトは.htaccessが自動生成されます。そのhtaccessには以下の記述がされています。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
それではこのリダイレクトの流れを説明していきます。
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
このリライトルールはあらゆるリクエストにマッチするようになっており、-
が指定されているので、リダイレクトは行われません。特徴的な[E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
はAuthorization
というリクエストヘッダーにHTTP_AUTHORIZATION
という変数を代入しています。
このリクエストヘッダーはWordPressの認証で利用されます。詳細の説明は、今回のリライトの説明から逸脱するので割愛します。
RewriteRule ^index\.php$ - [L]
この行はトップページにアクセスされたらそこ以降のリライト処理を一切適用しないことを指定しています。
RewriteCond %{REQUEST_FILENAME} !-f
このディレクティブは、リクエストされたURLがファイルではないどうかを判別しています。
%{REQUEST_FILENAME}
この変数にはファイルのパスが格納されていて、-fはファイルであるかどうかの比較演算子です。!-fであるため、ファイルではないかときに直下のリライトルールを適用することになります。
RewriteCond %{REQUEST_FILENAME} !-d
このディレクティブは、リクエストされたURLがディレクトリではないかどうかを判別しています。
上記とほとんど記述が同じことがわかります。
このようにRewriteCondのディレクティブを連続させることで、RewriteRuleの適用させるための条件式を複数指定することができます。
RewriteRule . /index.php [L]
このディレクティブは、あらゆる時にindex.phpにリクエストをリライトします。
”あらゆる時に”と書きましたが、上記の2つのRewriteCond
を考慮すると、リクエストがファイルではなくディレクトリでもないことが条件になります。
また、今までのリライトルールとの違いで、[R=301]というフラグの記述がないことがわかります。この指定方法は一般的に内部リライトと呼ばれます。
例えば、「example.com/post/123/」という記事にアクセスされたとします。このURLはディレクトリでもファイルでもないので、index.phpにリライトされます。よって、参照されるファイルは「example.com/index.php」になります。
ですが、301リダイレクトは行われていないため、ブラウザのURL上では「example.com/post/123/」と表示されたままになります。
このようにして、ディレクトリやファイルでないURLにアクセスされたときは全てindex.phpをエントリーポイントにすることが可能になります。
.htaccessを設定する上での注意
.htaccessは記述する上でいくつか注意点があります。
改行コードについて
改行コードはLFかCR+LFに設定する必要があります。これはVSCodeの場合、右下のホバーすると「改行コードの選択」というチップが出てくる部分が改行コードです。
文字コードについて
海外サーバーではShift_JISが使えない場合があります。.htaccessはUTF-8で記述するのが無難でしょう。また、UTF-8にした場合、BOMとはテキストファイルの先頭に配置される特殊な文字です。
VSCodeの場合、文字コードがUTF-8となっていれば問題ありません。
最終行を空行にする
.htaccessは最終行を空行にする必要があります。
まとめ
今回は、サイトを運用するとき、最初に記載すべき.htaccessのディレクティブを紹介しながら、リライトルールの使い方と仕様を解説しました。
.htaccessは設定を間違えると、サイトが表示されなくなったりSEO的に悪影響になる可能性があります。正しい知識を身につけた上で記述するようにしましょう。
よくある質問
なぜhttpsへのリダイレクトはWordPressのリライトの前に書く必要があるのですか?
WordPressのリライト処理はホームの時はトップドメインのindex.phpでリダイレクト処理が止まります。
下層ページの場合も、ディレクトリでもファイルでもない場合はindex.phpにリダイレクトされます。
リダイレクトが完了すると以降のリライトルールは適用しなくなりますl
以上のことから、WordPressのページにアクセスした際には、httpであったとしても処理がリライトされなくなるのでhttpsへのリダイレクトはWordPressのリライトの前に行う必要があります。
正しくコードが書けているのにリダイレクトが正常にされません。
ブラウザのキャッシュが原因である可能性があります。
リダイレクトが行われているかの確認はリダイレクトチェックツールを利用することで確認できます。
ローカルのリダイレクトなどで、WEBアプリケーションが利用できない場合は、プライベートブラウザーでリダイレクトの確認をすることで、ブラウザのキャッシュがない状態で確認することが可能です。
WordPressを利用していて、.htaccessを変更したらサイトが表示されなくなりました。助けてください。
記述のミスや最終行を空行にしているか、リダイレクトループが行われていないかなど、複数の原因が考えられます。
それでも直らない場合は、.htaccessを再生成することで解決します。
.htaccessをバックアップした上で、.htaccessを削除してください。その後、管理画面の「設定」→「パーマリンク」→「変更を保存」をクリックすることで、.htaccessが再生成されます。
その後、バックアップした.htaccessを参考に.htaccessを記述し直してください。