5分でわかる!一番わかりやすいmod_rewriteの設定 ~WordPress運営者もエンジニアも必読

Apache

apacheのmod_rewriteの設定をどこよりもわかりやすく解説

mod_rewrite モジュールは、WEBサーバー(apache)上で「URL の書き換え」を行うためのモジュールです。

WordPressなどでも標準的にも使われているくらい使用頻度が多く、便利で必要不可欠なモジュールです。

ところが一方で設定が超難解であるとともに、ひとつのミスで大混乱&大障害を招いてしまうというやっかいなエンジニア泣かせのモジュールでもあります。

そうならないために基本を理解しておくことが重要です。

mod_rewriteを学ぶ際に大事なこと

難解で有名なmod_writeですが基本的な動きを知らずに使っている人がほとんどです。

一番大事なのは大まかな処理の流れの基本をおさえることです。

おさえていないとまず確実にハマります。

それはフラグやオプションの使い方ではありません。

調べてもまとめてのっているサイトはそんなになかったです。

ので、今回は体型的にまとめてみたのでよろしければご覧ください。

mod_rewriteの基本【必読!】

基本的には設定の構成は以下のようになっています。

mod_rewriteはシンプルに言うと「ルールを順番に書き並べていく」のです。

あとはおまけだと思ってください。

多くの場合は.htaccessファイルの中か、VirtualHostディレクティブ内に書くことになると思います。

RewriteEngine On
RewriteBase /

#ルール1
RewriteCond ②変数&条件
RewriteCond ③変数&条件
RewriteRule ①転送元正規表現 ④転送先URL


#ルール2
RewriteCond ⑥変数&条件
RewriteCond ⑦変数&条件
RewriteRule ⑤転送元正規表現 ⑧転送先URL

設定にたいして

mod_rewriteは①→⑧のような順に処理が進んでいきます。
最後まで終わり、パスが書き換えられるとまた①に戻り置換後のパスを再評価します。


今超重要なことを言いました!!!
ここを理解していないと確実にハマります。

もう一度いいます。

mod_rewriteは①→⑧のような順に処理が進んでいきます。
最後まで終わり、パスが書き換えられるとまた①に戻り置換後のパスを再評価します。


順番がややこしいですし、また①から始まるとは。。。。
(※勘違いしやすいのですが、たとえフラグ[L]を使っても①に戻ります)

しかもリダイレクトの無限ループが起こりやすいです。

強めにいうと「なんでこんなわかりづらい記述にすんだよ!」と言ってやりたいです。

設定が増えてくるとまるでマルチスレッドのプログラミングをしているようです。

だらだらと文章で書いて申し訳ないですが、ここを絶対に理解してください。

RewriteCond ②変数&条件
RewriteCond ③変数&条件
RewriteRule ①転送元正規表現 ④転送先URL

①のルールの転送元の設定がマッチしたら、まずその設定箇所の評価を開始。
②、③の順に条件を評価し、条件にまたマッチしたら④のURL置換処理を行います。
そして次のルールへ。

ルール設定の最下部までいって、途中の置換があればまた最初から再評価が始まります。
ルールの適用がなくなればそこで処理は終了
します。


ここがクセモノで最初は理解できないでハマることでしょう。

無限ループが起こるのもこれを理解していないからの場合が多いです。



ひとつひとつ説明しますので安心してください。

mod_rewriteの各設定項目

RewriteEngineの設定

RewriteEngine Onでmod_rewriteの機能を有効化。Offで無効化。

例)

RewriteEngine On

RewriteBaseの設定

転送先URLで相対パスを使った場合のためのベースパス。

RewriteBase / とするとどのディレクトリに設置を行った場合でも必ずドキュメントルートからのパスになります。
ないと.htaccessを設置した位置からのパスになる。

※省略→現在のディレクトリ
※/を指定→ドキュメントルート

例)

RewriteBase /

RewriteRuleの設定

RewriteRuleではURL転送の設定をします。

記述方法の基本は以下です。

RewriteRule 転送元正規表現 転送先URL

転送元

正規表現を使います。ここにマッチしないリクエストはこのRewriteRule自体無視します。(上に記述しているRewriteCondの評価には進まない)

転送先

・URLのパス(https://****/、または/***からでもどっちでも)
・ファイルのパス(ファイルがあればこっちと判定)
・ハイフン(置換しない)

例)

#トップにアクセスしたらtop.phpで処理する
RewriteRule ^$ top.php


#ファイル名を置換
RewriteRule index1.html index2.html

RewriteRuleはRewriteCondと組み合わせて使うことができます。

適用のルールがこれまたややこしいです。
RewriteRuleには上にあるRewriteCondが採用されます。

書く順番と処理が流れる順番が・・・・逆・・・

例)RewriteRuleに対し適用されるRewriteCond 

RewriteCond →【A】の条件
RewriteCond →【A】の条件
RewriteRule【Aのルール】

RewriteRule【Bのルール】 →条件なし


RewriteCond →【C】の条件
RewriteRule【Cのルール】

RewriteRuleのオプションで使えるフラグ

RewriteRuleには様々なオプションが用意されています。

一気に覚えようとしてもおそらく無理なので都度実例を交えながら参照してみてください。

ものすごくよくある[L]の使い方の勘違いですが、今検証のループを1回だけ途中で抜けるだけで、また置換後のURLで再度検証されるということは忘れないでください。

プログラミングいうところのループのcontinue(スキップ)であってbreak(終了)ではありません。

フラグ 概要
R リダイレクト(302)
R=●とすると変更できる。
例)RewriteRule images/(.*) http://test.com/images/$1 [R,L]
F アクセス禁止(403)
L マッチしたらURL置換処理中止。
続くRewriteRuleを評価しない
N マッチしたらURL置換処理を最初にからやりなおす
NC 大文字小文字の区別をせずにマッチ
QSA クエリー文字列追加
NE URLエスケープ処理しない
END apache2.4から
PT
S=数字 数字番目のルールをスキップ
E=●:○ ●という名前の環境変数の値を○に変える
P プロキシとして処理する
G URL消去(410)
C 次のRewriteRuleにもRewriteCondを適用
T=●● MIMEタイプを●●にする
NS メインのURLリクエストの場合のみ条件を評価。
Webサーバー機能からの内部のサブリクエストの場合などはスキップ。

RewriteCondの設定

RewriteCondはURLパターンの評価に続いて、マッチするさまざまな条件を評価します。

URLやドメイン名、ユーザーエージェントなど追加の評価を複数記述できます。

RewriteCond 対象文字列 演算子&評価パターン [オプションフラグ]

例)リクエストされたファイルが存在したら

RewriteCond %{REQUEST_FILENAME} !-f
例)ホスト名かつユーザーエージェントを指定

RewriteCond %{HTTP_HOST} ^www.example.com$
RewriteCond %{HTTP_USER_AGENT} MSIE
例)ホスト名もしくはユーザーエージェントを指定

RewriteCond %{HTTP_HOST} ^www.example.com$ [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE

RewriteCondの演算子

! 文字列の前につけることで、マッチしないパターンを指定
< 文字列比較
> 文字列比較
= 文字列比較
-d 指定したディレクトリが存在すればtrue
-f 指定したファイルが存在すればtrue
-s ファイルが存在し、有限のサイズを持っていればtrue
-F アクセス可能な有効なパスを指している場合にtrue(内部サブリクエストを用いてcheckされる)
-U アクセス可能な有効なURLとなっている場合にtrue(内部サブリクエストを用いてcheckされる)

環境変数

WEBサーバーの環境変数が使用でき、phpなら$_SERVER変数で確認できるものです。
環境変数等を用いるには %{変数名}と記述。

グループ 変数名 値・意味 サンプル
HTTP ヘッダ HTTP_USER_AGENT ユーザーエージェント Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
HTTP_REFERER 参照元URL
HTTP_COOKIE クッキー情報
HTTP_FORWARDED プロキシ情報
HTTP_HOST サーバーのホスト名 ドメイン名
HTTP_PROXY_CONNECTION プロキシを経由しているか否か
HTTP_ACCEPT ブラウザのメディアMIMEタイプ
コネクション & リクエスト REMOTE_ADDR ユーザの IP アドレス情報
REMOTE_HOST ユーザーのホスト名)
REMOTE_USER リモートユーザー名 (基本認証利用時)
REMOTE_IDENT リモートユーザーのID
REQUEST_METHOD リクエストメソッド
SCRIPT_FILENAME スクリプトファイル絶対パス /var/www/html/index.php
PATH_INFO パス情報
QUERY_STRING クエリ文字列 a=b
AUTH_TYPE 認証タイプ
サーバ内部変数 DOCUMENT_ROOT ドキュメントルートのパス /var/www/html
SERVER_ADMIN サーバー管理者情報
SERVER_NAME サーバー名
SERVER_ADDR サーバーのアドレス
SERVER_PORT サーバーのポート番号
SERVER_PROTOCOL プロトコルバージョン
SERVER_SOFTWARE サーバーソフトウェア
システム関連 TIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY 曜日 (0:日 ~ 6:土)
TIME 年月日時分秒 (例:20130123123456)
特別なもの API_VERSION APIバージョン
THE_REQUEST リクエスト文字列 GET /index.html HTTP/1.1
REQUEST_URI リクエストURI /?a=b
REQUEST_FILENAME リクエストされたファイル名
IS_SUBREQ サブリクエストか否か
HTTPS HTTPSでのアクセスか否か。on/off
ENV:環境変数名 %{ENV:…} 式を指定して環境変数に基いて条件分岐を行なうことができます。

RewriteCondのオプションで使えるフラグ

例)ドメイン名を変更して301転送

RewriteCond %{HTTP_HOST} ^www\.example\.com [NC]
RewriteRule ^(.*)$ http://www.example.co.jp/$1 [R=301,L]

NC 大文字小文字の区別をせずにパターンマッチを行う。「no case」
OR RewriteCondの条件を「or」でつなぐ

動作確認

かんたんな動作で細かい動きを見ていきましょう。

頭を使って疲れるかもなのでいったん読み飛ばしていただいても結構です。

ルール設定がない状態で動きを検証

・/var/www/html/index.htmlを置く
・DocumentRoot /var/www/html
・/var/www/html/.htaccessを配置

	DirectoryIndex index.php index.html

	<IfModule mod_rewrite.c>

	        RewriteEngine on

	</IfModule>



確認のためhttps://***にアクセス


①メインリクエストの/を調査→設定がないので当然mod_writeは無視
②DirectoryIndexがindex.phpに内部アクセス(サブリクエスト)→mod_writeは無視
③DirectoryIndexがindex.htmlに内部アクセス(サブリクエスト)→mod_writeは無視

結果としては③でindex.htmlが見つかるので表示

かんたんなルールで動作確認

・/var/www/html/index1.htmlを置く
・DocumentRoot /var/www/html
・/var/www/html/.htaccessを配置

	DirectoryIndex index.php index.html

	<IfModule mod_rewrite.c>

	        RewriteEngine on
			RewriteRule ^$ index1.php #←★追加

	</IfModule>


確認のためhttps://***にアクセス

※注意点としてはDirectoryIndexで発生した内部サブリクエストの転送元URLは空で入ってくること。index.phpやindex.htmlで検出はできません。

①メインリクエストの/を調査→追加された★設定に反応。内部リクエストindex1.phpが発生
②再度、今度は/index1.phpの新しいmod_rewrite処理が最初から始まる。→設定がないので無視

結果として見つかった/index1.phpが表示される

連続したルールの動作確認

・/var/www/html/index1.htmlを置く
・/var/www/html/index2.htmlを置く
・/var/www/html/index3.htmlを置く
・DocumentRoot /var/www/html
・/var/www/html/.htaccessを配置

	DirectoryIndex index.php index.html

	<IfModule mod_rewrite.c>

	        RewriteEngine on

	        RewriteRule ^$ index1.html ★A
	        RewriteRule index1.html index2.html ★B
	        RewriteRule index2.html index3.html ★C

	</IfModule>

①メインリクエストの/を調査→追加された★A設定に反応。内部リクエストindex1.htmlが発生
②続けて内部リクエストのindex1.htmlを調査→追加された★B設定に反応。内部リクエストindex2.htmlが発生
③続けてま内部リクエストのindex2.htmlを調査→追加された★C設定に反応。内部リクエストindex3.htmlが発生

結果として最後のindex3.htmlが表示されます

とにかくサンプル

WordPressより

#ファイルやディレクトリがなければ常にindex.phpを参照

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule . /index.php [L]
</IfModule>

一時的にメンテナンス画面にしたい

#管理者IPアドレスの場合は除きすべてのアクセスを作成した/maintenance.htmlの表示に切り替える

ErrorDocument 503 /maintenance.html

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_URI} !=/maintenance.html
  RewriteCond %{REMOTE_ADDR} !=192.168.0.4
  RewriteCond %{REMOTE_ADDR} !=192.168.0.5
  RewriteRule ^.*$ - [R=503,L]
</IfModule>

<IfModule mod_headers.c>
  Header set Retry-After "Sun, 14 Jun 2009 6:00:00 GMT"
</IfModule>

正規表現のなどでマッチしたURL自体を使って置換

URLを/aaa/index.html → /aaa/ などのように変えたいときなどは正規表現のグループ化特殊変数の$1,$2,…などが使えます

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} ^.*/index\.html$
RewriteRule ^(.*)index.html$ https://www.example.com/$1 [R=301,L]

httpアクセスをhttps(SSL/TLS)に自動的にリダイレクトさせる

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

mod_writeの動作確認しながらデバッグをしたい

RewriteLog設定を使うことでデバッグのためにRewriteのログを出すことができます。
それぞれ数字が大きいほどログの量が多くなります。

※.htaccessでは書けません。httpd.conf、、またその外側に書きましょう

Apache2.2の場合

レベルとログ出力場所を指定できます。

RewriteLog /tmp/rewrite.log
RewriteLogLevel 3 #0~9

Apache2.4の場合

2.2の設定は廃止されました。

#( trace1~trace8)

LogLevel rewrite:trace8

ログ出力はapacheのログにされます

おまけ

リクエストとサブリクエスト(内部リクエスト)

簡単に言うとリクエストはユーザーがたたいてきたURL。
サブリクエストや内部リクエストはWebサーバーなどがサーバー内部で作り出したリクエストのことです。

参考

https://webtan.impress.co.jp/e/2009/06/16/5880 https://weblabo.oscasierra.net/apache-rewritecond-base/ https://web.hazu.jp/htaccess-rewrite/ https://httpd.apache.org/docs/2.2/mod/mod_rewrite.html http://koseki.hatenablog.com/entry/20090611/ModRewrite https://html-coding.co.jp/knowhow/tips/wp_modrewrite/ https://ysklog.net/mod-rewrite/flag.html https://qiita.com/ezaki/items/87c2dff8f7753ef048d2

コメント

タイトルとURLをコピーしました