mod_rewriteを使ったリダイレクトのパターン

mod_rewriteってよく使うのに、オプションやら何やらが意外に覚えにくくて扱いにくかったので少しまとめてみました。
設定しそうなパターンをご紹介します。

そもそも”mod_rewrite”ってなに?

WordPressやらMovableTypeでも使われているし、.htaccessを見ると結構な頻度で使われてます。

端的に言えば、複雑なリダイレクトを実現するためのApacheの1モジュールです。(正確には、リクエストされたURIの書き換え)
モジュールなのでApacheが動いている環境にあらかじめインストールされている必要があります。なので、ホスティングなんかではために利用できない物もあるようです。
VPSなんかでApacheをインストールすると概ね関連パッケージって事でインストールされると思う。当然、Nginx等の他のWebサーバではインストールされないけど、代替手段は用意されているかと思います。

まずは設定するときのお約束

mod_rewriteを使う場合、転送条件や転送先を記述する時のお約束として下記を書いておきます。

<ifModule mod_rewrite.c>
 RewriteEngine On
 [[設定はここに記述していきます]]
</ifModule>

ここでやっていることは、mod_rewriteモジュールが有効になっているかのチェックとmod_rewriteを使うよ、の宣言です。
これを書いておくことで、mod_rewriteが無効のサーバに.htaccessをコピーしたとしてもInernal Server Errorが起きることはなくなります。
当然だけどリダイレクト処理は動かないけどね。

ドメインのリダイレクト

まずはドメインのリダイレクト。サーバの引っ越しやドメインの変更があった場合、wwwみたいなサブドメインのあり/なしを統一したいときの設定をご紹介します。

www.nautilus.xyz ⇒ nautilus.xyz のリダイレクト

www.nautilus.xyzにアクセスした場合にnautilus.xyzへリダイレクトする場合はこんな書き方をします。

<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.nautilus\.xyz$ [NC]
RewriteRule ^(.*)$ http://nautilus.xyz%{REQUEST_URI} [R=301,L]
</ifModule>

RewriteCondにマッチする場合、RewriteRuleに記述しているURLへのリダイレクトをおこないます。
この場合、HTTP_HOSTがPerlの正規表現で ^www.nautilus.xyz$ にマッチする場合に次の行のRewriteRuleが実行されます。オプションの [NC] は大文字小文字を区別しないために指定しています。

RewriteRuleの {REQUEST_URI} は転送元URLのドメイン以下がそのまま入ります。たとえば、
http://www.nautilus.xyz/profile ⇒ http://nautilus.xyz/profile
みたいな感じになります。
転送する際にディレクトリ構造が変わっている場合には指定しない方がいいかもしれませんね。

R=301は永続的転送の意味です。ここは暗黙で永続になるのでRだけの指定でも大丈夫ですが、明記しておいた方が無難です。
LはURL書き換え終了の意味です。mod_rewriteの処理はここで終了します。

プロトコルのリダイレクト

Google様の方針により、HTTPSが今後メインになってくるはずです。
これまでHTTPでアクセスしてきたユーザをHTTPSに転送したい場合はこんな書き方をします。

<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^nautilus\.xyz$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www\.nautilus\.xyz$ [NC]
RewriteRule ^(.*)$ https://nautilus.xyz%{REQUEST_URI} [R=301,L]
</ifModule>

HTTPSがOFFの場合、つまりHTTPの場合にRewriteRuleが実行されます。

たとえば、http://nautilus.xyz/ と http://www.nautilus.xyz/ でアクセスすると、https://nautilus.xyz/ にリダイレクトします。

ここでのキモは、%{HTTPS} off です。
これを書き忘れるとループしちゃうので、エラーになる場合もあります。
HTTPS ⇒ HTTPにしたい場合は、%{HTTPS} on と書くと https:// の場合にだけ反応するようになります。

URL変換の問題

URLにURL変換されたパラメータが含まれている場合、2重にエンコードされてしまう問題があります。

たとえば、こんなURLをリダイレクトする場合。
http://www.nautilus.xyz/?arg=%E3%83%8E%E3%83%BC%E3%83%81%E3%83%A9%E3%82%B9%E3%81%AF%E9%B8%9A%E9%B5%A1%E8%B2%9D

これをhttp://nautilus.xyz/にリダイレクトしたいときに下のように書いたとします。

<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.nautilus\.xyz$ [NC]
RewriteRule ^(.*)$ http://nautilus.xyz%{REQUEST_URI} [R=301,L]
</ifModule>

この設定にすると”%”がさらにエンコードされて下のようなURLとしてリダイレクトされてしまいます。
http://www.nautilus.xyz/?arg=%25E3%2583%258E%25E3%2583%25BC%25E3%2583%2581%25E3%2583%25A9%25E3%2582%25B9%25E3%2581%25AF%25E9%25B8%259A%25E9%25B5%25A1%25E8%25B2%259D

これだと正しいパラメータを受け取ることができないので、URLエンコードを抑止する “NE”パラメータをRewriteRuleに追加してあげます。

正しい設定はこんな感じです。

<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.nautilus\.xyz$ [NC]
RewriteRule ^(.*)$ http://nautilus.xyz%{REQUEST_URI} [R=301,L,NE]
</ifModule>

この設定を知らず、結構ハマっちゃいました…

[参考]

Apache Module mod_rewrite