MT で動的生成を使うときの .htaccess をダメ出し

シェアする

動的生成時の .htaccess ファイルを見直す

今回は、ちょっと難しいよ! でも、Movable Type で動的生成(ダイナミック・パブリッシング)を利用している人は必見です。

MT で動的生成を利用する設定にすると .htaccess が自動的に作成されます。初期状態のままだと、思いっきりサーバに負担がかかるかも知れない──ということを発見しました。特に Perl 版ダイナミック・パブリッシングを使っている人は、とんでもないことになっているかも。──悪いのは、みんな spammer ですが……。

具体的には、.htaccess ファイルにこんな設定を施す、という提案です。

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 下の三行を追記
RewriteCond %{REQUEST_FILENAME} !\.(cgi|css|gif|jp*g|png)$
RewriteCond %{REQUEST_URI} !^/mt/cm/.*$
RewriteCond %{REQUEST_URI} !^/mt/tb/.*$
RewriteRule ^(.*)$ /mt-dynamic.php [L,QSA]

では、順を追って解説してみます。

まずはおさらい

MT3.2 で動的生成を使う設定にすると、ブログのルートディレクトリに下記の内容が書かれた .htaccess ファイルが作成されます。一部、抜粋しました。

RewriteEngine on
# don't serve mt-dynamic.php if the request is for a real directory
# (allows the DirectoryIndex lookup to function)
RewriteCond %{REQUEST_FILENAME} !-d
# don't serve mt-dynamic.php if the request is for a real file
# (allows the actual file to be served)
RewriteCond %{REQUEST_FILENAME} !-f
# anything else is handed to mt-dynamic.php for resolution
RewriteRule ^(.*)$ /mtview.php [L,QSA]

コメント部分(行頭が # から始まる行)を眺めて、重大なことに気がつきました。簡単なので一行ずつ見ていきます。

まず、RewriteEngine onApache module mod_rewrite を使う、という宣言です。

コメント部分を飛ばして、次の RewriteCond %{REQUEST_FILENAME} !-d は「ディレクトリが存在しない場合」という意味です。-d が「ディレクトリ」で ! が否定ですね。

この場合の「ディレクトリ」というのがちょっとややこしいです。このブログでいうとトップページは http://asiamoth.com/mt/ ですが、実際のアドレスは http://asiamoth.com/mt/index.php です。こういう具合に「ディレクトリのインデックスファイル」を含めて存在チェックをしています。ということで、正確には「リクエストがディレクトリの場合は、そのディレクトリにインデックスファイルが存在しない場合」ですかね(長っ)。

さらに、次の RewriteCond %{REQUEST_FILENAME} !-f を見てみます。-f が「ファイル」、! が否定なので、「ファイルが存在しない場合」ですね。

ということで、リクエストされたディレクトリ、またはファイルが存在しなければ、mtview.php に渡して、処理してもらうわけです。

──ここで何が重大なことか気がついた方は鋭い。そう──ということは、デタラメな URL や(ワケあって)削除したファイルにアクセスがあった場合でも、わざわざ mtview.php にアクセスしに行きます!

Perl版ダイナミック・パブリッシングの場合

Perl 版ダイナミック・パブリッシング を利用している場合、上記の mtview.phpmt-dynamic.php に書き換えます。

──ということは、存在しないディレクトリやファイルのリクエストがあった場合、mt-dynamic.php が処理を開始します。そして、その度に mt-dynamic.php はデータベース(各種 SQL)にアクセスして、どのような処理を行うか、確認しに行きます──。

ちゃんと、「動的生成する」と決めたテンプレートから生成される URL であれば、そのまま動的生成を行います。しかし、例えば、延々と無効な URL」にアクセスがあった場合は……?

ガクブル モノですが、その度に mt-dynamic.php くんはデータベースに問い合わせに行くわけです……。お、恐ろしい。というか、ずっっっっと、このブログではそうなっていました。何度「MySQL へのアクセス大杉」というメッセージを見たことか……。

とりあえずの解決策

さて、サクッと解決、といきたいところ。妥協案の一つはこんな感じ。

# @asiamoth
RewriteCond %{REQUEST_FILENAME} !\.(cgi|css|gif|jpe?g|png)$
RewriteCond %{REQUEST_URI} !^/mt/cm/.*$
RewriteCond %{REQUEST_URI} !^/mt/tb/.*$

2007-01-12T13:01:31+09:00 追記

はい、また嘘コード書いてました(コメント欄参照 : あんちもん2 さんに感謝!)ので修正しました

こんな感じで RewriteRule ^(.*)$ /mtview.php [L,QSA]直前に書きました(Perl 版~の場合は mt-dynamic.php に読み替えて)。

RewriteCond %{REQUEST_FILENAME} !\.(cgi|css|gif|jp*g|png)$ というのは、.cgi で終わる CGI ファイルや画像ファイルなど、「動的生成することが アリエナイ ファイル」ではない(!)という条件です(ややこしい)。要するに、CGI や画像ファイルは動的生成しないよ、ということ。

このブログでは真説・対spam最終兵器 CGIリネーム烈伝 : 亜細亜ノ蛾 で書いたようにコメント・トラックバック CGI をリネームしていますが、いまだにリネーム前の CGI にアクセスがあります。──その度に負荷が……。画像ファイルの指定はおまけです。その他、みなさんの方で思いつく拡張子をぶっこみングするヨロシ(何語?)。

RewriteCond %{REQUEST_URI} !^/mt/cm/.*$ の部分は、リネームしたコメント CGI の URL です。これも「動的生成しない」と指定しています。ここはみなさんの環境に合わせ、「動的生成するファイルが存在しないディレクトリ」を指定してください。

導入した結果

ということで、上記の数行を入れただけで、半日で 500 アクセス(!)釣れました。みんな、リネーム前のコメント CGI へのアクセスですた。──一体、どんだけサーバに負担かけていたんだろう……。というか、いまはみんな「404」を返していますが、なんか仕返ししたいなー。ファッ●! スパマーめ!

まぁ、それでもぜんぜん「負荷率」が減らないのが、Xrea.com クオリティ ☆

今後

さて、上の方法は .htaccess ファイルをブログのルートディレクトリに設置して「指定した条件に当てはまらなければ、動的生成を試みる」という方法ですが──

──書いているうちに、もっと賢い方法を思いつきました。

要するに、「動的生成するかどうかの条件」を書いた .htaccess はブログのルートディレクトリに置かず、動的生成したいファイルがある場所だけに設置する。

  • http://example.com/mt/

    • ブログ・ルート・ディレクトリ

    • ここの .htaccess には動的生成のルールは書かない

  • http://example.com/mt/archives/

    • ブログの記事がある場所

    • 動的生成するファイルがあるので、ここの .htaccess ファイルに動的生成のルールを書く

  • http://example.com/mt/tag/

    • タグのページがある場所

    • タグは動的生成ではなく Tagwire Plugin などでタグを生成する

    • よって、ここも動的生成のルールは不要

こんな感じ。これがベターですかね。

──こうして考えていくと、つくづく URL の設計って重要だなー。Web デザインというモノは、色や形だけではなく、URL も含めて考える必要がありますね。

この記事のタグ(偽)

[この世で最もお馬鹿な人種は?][spammer]

コメント

  1. たねちゃん より:

    お久しぶりです、こにゃにゃちば(=゜ω゜)ノ
    私のブログではダイナミック・パブリッシングは使ってませんが
    同じXREAなので、似たようなスパム撃退法は使ってます(笑)
    CGIリネーム究極版の副産物で出来たモノで、スパマーに
    ギャフン!と言わせる事は出来ませんが、スパム送った奴の
    情報を集めて.htaccessで完全に封鎖する様にしています。
    ポイントは…スパマーの動きをする奴には403を喰らわせる!
    って感じです。これでスパマーの情報だけを集める事が(笑)

  2. 初めてコメントします。1点指摘。
    RewriteCond %{REQUEST_FILENAME} !\.(cgi|css|gif|jp*g|png)$
    の「jp*g」の部分は、「jg」「jpg」「jppg」「jppppg」等にマッチしちゃいます。特に、「jpeg」にはマッチしません。
    正しくは「jpe?g」もしくは「jp.?g」であないかと。
    前者なら「jpg」と「jpeg」のみ、後者なら「jpg」「jpag」「jpbg」「jpeg」「jp0g」等にマッチします。

  3. asiamoth より:

    たねちゃん さん:
    どもども。なるほど、エラーログを見るだけでスパマの情報が得られるのですね(合ってる?)。ちょっと真似してみます。
    あんちもん2 さん:
    あちゃー、「──ダメ出し」をダメ出しですな。ありがたいです! たぶん、記事を書いたときに wild card と勘違いしてました。記事を修正しておきます。

  4. たねちゃん より:

    3.4時間くらい掛かりましたが、スパマーに403喰らわせる方法を
    なんとか書いてみました。また参考にして頂ければ幸いです。
    XREAでエラーログって見れるんですか?もし出るならそっちの
    方が多分(おそらく(間違いなく))そっちを見た方が楽ですね。
    私はちと分からなかったので.htaccessに
    ErrorDocument 403 /403.cgi
    を設定して、CGIでIPとUserAgentを記録する様にしました。
    エントリーの方で書きましたが、この記録したログが見れます(笑)

  5. asiamoth より:

    おお、かなりまとまった記事ですね。じっくり読みました。
    「XREAでエラーログ」を見るには、おそらく「生ログ」を見る必要があります。一度、じっくりと確認しなければ、と思いながらまだ未確認です。エラーログ用のCGI を使う、というのは素晴らしいですね。自分でもちょっと確認してみます。
    いつか、スパム対策に悩まされることがなくなるといいですね(それはそれで寂しい?)。