端っこプログラマーの手帳

主にプログラムに関する手記です

httpd.conf と .htaccess でリライト設定が異なる

.htaccess リライト設定をそのままApache設定ファイル(VirtualHostディレクティブ)に書いても動かずハマったのでメモ。

.htaccessに設定

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L] 

RewriteCond でリクエストファイルが存在するか判定します。

判定 実行される処理
存在する RewriteRuleを通らず直接リクエストファイルを表示
存在しない RewriteRuleを通り index.php にリライトする

よく見るリライト設定です。 説明の便宜上 .htaccess は example.jp のドキュメントルート直下に置いてあることにします。 ドキュメントルートは /var/www/html で /var/www/html/.htaccess にファイルがあるということになります。

VirtualHost ディレクティブに設定

同じように内容を VirtualHostディレクティブに設定します。 上と同じ動きになることを期待しますが、 「400 Bad Request」とエラーになってしまいます。

httpd.conf

<VirtualHost *:80>
    ServerName example.jp
    DocumentRoot /var/www/html

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L] 
</VirtualHost>

何が異なるのか?

リライトログを取って詳細の動きを追ってみました。 .htaccess と VirtualHostディレクティブ で異なる点は2点

REQUEST_FILENAME に入る値が違う

http://example.jp/hoge にアクセスすると

.htaccess   → /var/www/html/hoge
VirtualHost → /hoge

VirtualHostの場合はドキュメントルート部分が抜けます。 正確に動かすには、 %{DOCUMENT_ROOT} 部分を追加する必要があります。

RewriteRule のリライト先に / が必要かどうか

.htaccess   → RewriteRule のリライト先 index.php は .htaccess の置いてある階層の index.php と判定される。
VirtualHost → RewriteRule のリライト先 index.php は、ドキュメントルート直下にならずにエラーとなる

VirtualHost の場合は、/index.php と絶対指定に指定する必要があります。

上の2点を直すとこんな感じになります。 どうやら、VirtualHost 下に書くとドキュメントルートが基点にはならないようです。

httpd.conf

<VirtualHost *:80>
    ServerName example.jp
    DocumentRoot /var/www/html

    RewriteEngine On
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ /index.php [QSA,L] 
</VirtualHost>

ええぃ憶えるのめんどくさいぞぉ

こんなのすぐ忘れます。いつもApacheの設定をいじっている訳でもないですし。 曖昧な記憶から「あれっなんだたっけ」と思いだすオーバーヘッドも大きいです。

実は、Directoryディレクティブを使えば、.htaccess と同じ設定で書けます

こんな感じです。

httpd.conf

<VirtualHost *:80>
    ServerName example.jp
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ index.php [QSA,L] 
    </Directory>

</VirtualHost>

Apacheのドキュメントにも、上の設定での、.htaccess と Directoryディレクティブは等価とあります。

ところで、ディレクティブの書かれた .htaccess を /www/htdocs/example に置くことと、同じディレクティブを 主サーバ設定の Directory セクション > に書くことは 完全に等価です

Apache HTTP Server Tutorial: .htaccess files - Apache HTTP Server Version 2.4

Apache設定ファイルのリライト設定は、Directory [ドキュメントルート]に書く

と覚えておけば良いのではないでしょうか。これでコードを修正する手間などなくなります。