移転しました

独自ドメインサイトへ移行しました。5秒後に

https://straypenguin.winfield-net.com/

へジャンプします。

つまずきやすい設定項目

ディレクティブ個々の解説は Apache のドキュメントや様々な書籍で見られ、改めて論じても仕方がないので、ここでは、混同しやすい似たようなディレクティブの比較を中心に、覚え書きを並べることにした。各項は、前ページの設定ディレクティブ一覧からリンクしている。

Global Environment セクションのディレクティブ

バーチャルホスト設定や <Directory> ブロックの中などでは使えない、サーバの動作環境設定専用ディレクティブ群。ただし、本来 HostsDefaultセクションに属するディレクティブも、 Global Environment のディレクティブと関連性が高いものは、幾つか一緒に説明する。

LimitRequest* の区別

LimitRequestFields, LimitRequestFieldSize, LimitRequestLine, LimitRequestBody という 4 つのディレクティブは全て、クライアントからの HTTP リクエストの要素数や最大長を制限するのに使われる。主な目的は、異常に長い、あるいは不正なフォーマットのリクエストによる DoS 攻撃を排除することだ。これらディレクティブの違いを理解するには HTTP プロトコル (RFC2616 日本語訳 原文) の構造を理解する必要がある。下に、HTTP リクエストメッセージのフォーマットと、Apache の各ディレクティブ (赤字) がどの部分を制限するかを図解してみた:

[ 図 ] HTTP リクエストメッセージと LimitRequest* ディレクティブ
http request message

Perl で WEB アプリケーションを書いたことのある人なら、特に Message-Header のフォーマットには心当たりがあるだろう。これらのディレクティブ値を調整したくなるのも、専ら、サーバ上で CGI を運用している場合ではないだろうか。クライアントが送信するフォームデータやアップロードファイルが充分納まりながら、それ以上の異常に長いリクエストは排除できるような値に調節したいと考えるに違いない。

そこでおさえておかなくてはならないポイントは、メソッドによってリクエストメッセージの体裁が変化するという点。図中の実例 1 のようにフォームのメソッドを GET にした CGI の場合、フォームデータは Request-URI に含まれてサーバへ送られてくる (もちろん、まともなブラウザならば、きちんとエンコードされて)。つまり、 Method = GET の場合には、 LimitRequestLine の値を特に慎重に決める必要がある。実例 3 のように POST の場合、あるいはファイルアップロード CGI の場合には、データは Message-Body (おおざっぱに言えば Entity-Body と同義) に乗ってくるので、そのようなケースならば LimitRequestBody を特に念入りに考える必要性が生じることとなる。

ついでの予備知識だが、実例 2 のように Request-URI が相対パスの場合には、サーバ名が Request-Header 内の Host ヘッダとして "Host: www.hoge.cxm" といったカタチで送られてくる。

ServerTokens, ServerSignature と ExtendedStatus

これら 3 つは実際には全く異なったディレクティブなのだが、Apache をいじり始めた頃には迷ったので、ここでまとめておくことにした。

ServerTokens は、Apache がクライアントに送る HTTP レスポンスの中のヘッダ内容を調整するのに使う。まず HTTP 1.1 で規定されたレスポンスメッセージのフォーマットを図にまとめたので見ていただこう:

[ 図 ] HTTP レスポンスメッセージのフォーマット
http response message

ServerTokens ディレクティブは、上図 Message-Header 内の Response-Header に属する Server ヘッダをどれくらい冗長にするかを規定する。一般的なブラウザは、確かに Server ヘッダは読み取っているはずだが、普段その内容をユーザの目に触れさせることはない。 Server ヘッダによって某かの互換性調整をしているブラウザが存在するかどうかは知らないが、ServerTokens の設定を最も情報の少ない Prod にして問題が生じた経験はないので、Prod で充分だろう。ただし、Apache 2.0 からは、次に述べる ServerSignature でもこの情報を利用する仕様となったので、それとの兼ね合いで調整したい管理者もいるかも知れない。

ServerSignature ディレクティブは、Page Not Found や Unauthorized などのエラー時や、ディレクトリインデックスビューなど、 Apache が自動生成するページに表示されるサーバ情報の詳細度を制御する。ただし、ErrorDocument ディレクティブやコンテントネゴシエーションを活用してカスタムエラーメッセージページ (.var.html ファイル) を送るようにしてある場合には、サーバ情報のフッタ行は自動付加されないので ServerSignature 設定は意味を成さない。いずれにしろ、インターネットの世界は「無法地帯」なので、これを On や EMail にして余分な情報を公開する必要性を、筆者は全く感じたことがない。

ExtendedStatus は、サーバの環境変数や設定の一覧を表示する server-status ページの詳細度を変化させるだけ。正確には、それにかかわる詳細な情報を、収集/保存するかを決めるディレクティブだ。サーバステータスページとは、"http://www.hoge.cxm/server-status" で見られるページ。 Apache の設定ファイルのデフォルトでは、このロケーションへのアクセスは許可していない。この状態ならば ExtendedStatus ディレクティブからは何の恩恵もない。ステータスページを有効にするには httpd.conf の終盤にある "<Location /server-status>" ブロックのコメントを外してやる必要がある。しかし、わざわざ情報を外に晒す必要はないので、デバグの参考にする目的以外で開けるべきではない。開けるとしても、アクセスできるクライアントの IPアドレスを Allow fromDeny from 句でローカルネットワーク内にだけ限定するとか、 AuthType 句などによって認証を掛けておくべきだ。また、 ExtendedStatus ディレクティブをオンにしておくと情報の収集/保存によるオーバーヘッド (多少だが) が生まれるので、滅多に server-status をチェックしないのであれば、パフォーマンスの観点からオフにしておくのが望ましい。

ServerRoot と DocumentRoot

ServerRoot は、Apache の設定ファイル、エラーログ、ログファイルなどの基底ディレクトリを決定する (デフォルトでは /etc/httpd)。 DocumentRoot は、カスタムエラードキュメントやディレクトリインデックス用アイコンも含めて、コンテンツをサーブできるディレクトリの基底を決める。

ServerRoot は Apache デーモンがアクセスできるディレクトリを限定したり、ルートディレクトリを移行 (chroot) させるわけでない。設定ファイル内で、頭に "/" を付けずにファイルを相対指定した際に、ServerRoot で規定したディレクトリを前に補完してくれるだけだ。httpd.conf の記述中で、例えば "conf.d/perl.conf" と書けば /etc/httpd/conf.d/perl.conf を指すが、 "/etc/mime.types" と書けば、実ファイルシステム上の /etc/mime.types を参照することになる。

これに対して、DocumentRoot 外のファイルシステム上にあるファイルを、 Apache はコンテンツとして読み取ることができない。 デフォルトの通り DocumentRoot/var/www/html なら、 "http://www.hoge.cxm/doc.html" という URL は、ファイルシステム上の /var/www/html/doc.html を参照する。言い換えると、コンテンツの参照要求に対しては /var/www/html/ がルートディレクトリ (/) とみなされる。つまり /var/www/html/ へ chroot jail されたような状態とも言えるだろう。この制限を部分的に乗り越えるために用意された手法はふたつある。 <Directory>OptionsSymLinksIfOwnerMatchFollowSymLinks を指定し、シンボリックリンクを辿ることを許す方法。もうひとつは Alias ディレクティブを使って DocumentRoot 外のディレクトリを DocumentRoot 下にあるように見せかける方法だ。

<Location> ディレクティブによる弊害やうっかりミスを避けるためにも、筆者は *SymLinks* を一切使わないようにしている (デフォルトの httpd.conf から全て抹消)。コンテンツファイルの参照先の拡張は Alias ディレクティブで行っている。例えば

Alias /imode/ "/home/wwwadmin/www/imode-site/"

と設定すれば、クライアントからの "http://www.hoge.cxm/imode/" という要求はファイルシステム上の /home/wwwadmin/www/imode-site/index.html ファイルを参照する結果となる。 URL も短く、入力しやすくなって一石二鳥だ。もちろん <Directory "/home/wwwadmin/www/imode-site">...</Directory> による適切なオプション設定は別途きちんとやっておかなくてはならない。

TypesConfig と MIMEMagicFile

ともに引数には設定ファイルの名前 (ServerRoot からの相対パス) を指定するが、 TypesConfig のほうは拡張子によるファイルタイプ判別であり、モジュール mod_mime の守備範囲、 MIMEMagicFile のほうは、ファイルの実内容に基づくファイルタイプ判別であり、 mod_mime_magic モジュールが動作を受け持つ。 MIMEMagicFile のデフォルトである conf/magic を眺めれば分かるが 「ファイルの先頭にビッグエンディアンの "0xffd8" が見つかったら jpeg」といったルールが記述されている。 magic ファイルの書式については mod_mime_magic (Apache Doc) に詳しく書かれている。

なお、Apache ドキュメントによると TypesConfig のデフォルトファイルは conf/mime.types だとあるが、少なくとも RedHat 系では、そのようなファイルはなく、その役目は /etc/mime.types が担っている。また、 TypesConfig ディレクティブで設定ファイルを指定していても、 AddType ディレクティブによる個別指定のほうが優先度は高く、これによって拡張子規定を追加あるいは部分的に上書きすることができる。

Hosts Default と Virtual Hosts セクションで使えるディレクティブ

ホストのデフォルト動作を設定するセクションで使えるディレクティブのほとんどは、バーチャルホストセクションでも使えるので、この章ではそれらをまとめて扱う。

<Directory> と <Location>

セクションの設定 (Apache Doc) は必読。ここではポイントと注意事項のみ述べる。

Directory と Location の指し示すもの

<Directory ...> ディレクティブでの定義は、ファイルシステム上の実パスに対する定義となる。最も基本的な例として:

<Directory />
  some configurations...
</Directory>

というブロックが指しているパスは、サーバマシンの実ファイルシステム上のルートディレクトリ "/" だ。決して DocumentRoot (/var/www/html/) ではないし ServerRoot (/etc/httpd/) でもない。ファイルシステム上の "/" は唯ひとつしかないので、上記のパス指定ブロックには一切の曖昧さがない。 some configuretions... の部分に、アクセスやオプションを禁止するような設定を書けば、ルートディレクトリ以下つまりファイルシステム全域の安全を、とりあえずデフォルト値として、確保することができる。こうしてまず全体の縛りをきつくしておいて、必要なディレクトリだけ適宜制限を緩める、というのが apache アクセス制限の基本。

これに対して、<Location ...> ディレクティブで指定したパスは、WEB サーバへのリクエストに対する定義で、

<Location />
 some configurations...
</Location>

は、Hosts Default セクションや <VirtualHost> 内で定義された DocumentRoot を指す。言い換えると、 Location による "/" は <VirtualHost> ブロックの設定によってはいくつも存在することになる。これがもっと末端のディレクトリとなれば、 Alias ディレクティブや FollowSymLinks オプションなどによって迂回アクセスできる可能性はさらに高まる。アクセスやオプションに「制限」を掛けるような設定を <Location> を使って定義してはいけない、という原則の所以だ。なお、<Directory> ブロック内で使えるディレクティブのほとんどは <Location> 内でも使えるが、そのうち以下のものだけは使用できない:

<Location> 内で使用できないディレクティブ:
  • AllowOverride
  • OptionsFollowSymLinksSymLinksIfOwnerMatch
<Directory>, <Location> とワイルドカードと正規表現

正規表現版である <..Match> を含めると <Directory><Location> には各々 4 種類もの記述法があり、大変まぎらわしい。それぞれの性質を下表にまとめてみた。

<Location> の場合

記述例 説明
<Location /dir> ワイルドカードも正規表現も使わない。 セクションの設定 (Apache Doc) によれば http://this.server/dir123 や http://this.server/dir123/test.html といった URL にも影響を与えるはずだが、実験してみるとそうはならない。 /dir/ 以下全階層のファイル及びディレクトリには効力がある
<Location /dir/*> シェル形式のワイルドカードで、最後に "/" がない例。 ?*/ にはヒットしないので、 http://this.server/dir/sub といった URL にはヒットする (sub がファイルかディレクトリかにかかわらず)。しかし dir/sub/ というスラッシュ付きの URL や、それより下のディレクトリやファイルには影響なし
<Location /dir/*/> シェル式ワイルドカードで最後に "/" がある例。文字通りの http://this.server/dir/sub/ や http://this.server/dir/child/ という URL にはヒットする。しかし /dir/ 直下のファイルにも、 /dir/sub/ 以下や /dir/child/ 以下のファイルやディレクトリにもマッチしない
<LocationMatch "^/dir/.*"> Perl 互換の正規表現。 ".*" は / にもヒットするので、サブディレクトリ及び構成ファイル全てに影響を及ぼす
<Location ~ "^/dir/.*"> 上記の古い書き方。 <LocationMatch> と同じ。紛らわしいので使わないほうが良い

<Directory> の場合

記述例 説明
<Directory /dir> ワイルドカードも正規表現も使わない <Directory> の例。 /dir/ とそれ以下全階層のサブディレクトリに効果を現す。しかし /dir123 などとその配下には効力なし
<Directory /dir/*> 最後にスラッシュのないシェル式ワイルドカード。 /dir/sub/ 以下や /dir/child/ 以下全てに影響を与える。ただし /dir/ 直下のファイルには影響なし
<Directory /dir/*/> もともとディレクトリの指定である <Directory> で最後にスラッシュを付けるとおかしな挙動となるので非推奨
<DirectoryMatch "^/dir/.*"> Perl 互換の正規表現。 ".*" は / にもヒットするので、サブディレクトリ及び構成ファイル全てに影響を与える
<Directory ~ "^/dir/.*"> 上記の古い書き方。 <DirectoryMatch> と同じ。紛らわしいので使わないほうが良い
<Directory>, <Location> とシンボリックリンク

OptionsFollowSymLinksSymLinksIfOwnerMatch を有効にしてあると、 <Directory> 指定は、シンボリックリンクのある場所のみを規制し、リンク先が参照禁止かどうかはお構いなしだ。例として以下のようなディレクトリ構造を考えてみる:

例えば http://this.server/allowdir/dirlink/ にアクセスした時、 実際に送り出されるのはシンボリックリンク先である denydir/denysub/ のコンテンツなのだが、 Apache はあくまでも allowdir/dirlink/ をブラウズさせている体裁を押し通す。よって、このアクセスに対しては「Allowなディレクトリ」の設定が適用され、「Denyなディレクトリ」の denysub ディレクトリ以下は筒抜けとなる。 <Location> は URL に対する定義なので、なおさら曖昧で、セキュリティの穴はもっと広がる。

自分以外が WEB コンテンツを放り込めるサーバなら無論だが、そうでなくても、まずはルートディレクトリから根こそぎ "<Directory />" で "Options None" プラス "AllowOverride None" を設定してシンボリックリンク遡上及び .htaccess による同設定の変更を禁止しておこう。また、 DocumentRoot 内にはシンボリックリンクは作らないことをお勧めする。なにせ、シンボリックリンク自体は設定ファイルで一元管理するわけにいかないシロモノ。とかくミスを犯しやすい。

FollowSymLinks と DirectoryIndex

DirectoryIndex ディレクティブで指定されているファイル (通例は index.htm*) がそのディレクトリに存在すれば、 "/" で終わるロケーションを要求しただけで index.html の内容が表示される。これは mod_autoindex モジュールの司る挙動。ここで、シンボリックリンクに関する注意点がある。オートインデックス機能は、 FollowSymLinks オプションをあっさりと無視してしまうのだ。

ここに、ディレクトリ /var/www/html/nosym/ があるとする。 <Directory> Options セットによって、このディレクトリ下でのシンボリックリンク参照は禁止してある。そこに、DocumentRoot 外に置かれた index.html ファイルへのシンボリックリンクを張る。 /var/www/html/nosymls すると以下のようになる:

ls -l /var/www/html/nosym
lrwxrwxrwx 1 root root index.html -> /test/index.html
lrwxrwxrwx 1 root root test.html -> /test/index.html

/var/www/htmlDocumentRoot だとして、 http://this.server/nosym/test.html というリクエストは test.html のリンクを辿って /test/index.html の内容を参照しようとするが、 FollowSymLinks が無効なので見られない。ところが、 http://this.server/nosym/ というリクエストは、まんまと /test/index.html を参照する。 SymLinksIfOwnerMatch も同様に無視される。アクセス制限の抜け穴となるので注意が必要だ。

UseCanonicalName と スクリプト変数

予定

Deny と Allow の Order について

<Directory><Files> などのブロック中で指定する "Order Deny,Allow" は、 mod_access (Apache Doc) を読んでもなかなか理解しにくい。 Order 句、 Allow/Deny from 句セットの基本的なルールを Apache Doc とは別の表現でまとめると、以下のようになる:

例を示す。まずは単純な例だ:

Order <1>,<2>
Deny from 202.200.100
Allow from 192.168.0

<1>,<2> のところが Deny,Allow なら、デフォルトポリシーは「許可」。まず、 202.200.100.* のネットワーク範囲からのアクセスは「拒否」され、 192.168.0.* のネットワーク範囲からは「許可」。どちらのポリシーにも当てはまらないその他全ての アドレスからのアクセスは「許可」。

<1>,<2> のところが Allow,Deny なら、デフォルトポリシーは「拒否」。まず、 192.168.0.* のネットワーク範囲からのアクセスは「許可」され、 202.200.100.* のネットワーク範囲からは「拒否」。どちらのポリシーにも当てはまらないその他全てのアドレスからのアクセスは「拒否」。

次に、 Allow fromDeny from のアドレスがカブっている、複雑な例を考察してみる:

Order <1>,<2>
Deny from 192.168
Allow from 192.168.1

<1>,<2> が Deny,Allow なら、デフォルトポリシーは「許可」。 Deny from が先に評価され、 192.168.*.* 全体からのアクセスが「拒否」され、後ポリシーの Allow from 句が 192.168.1.* の範囲だけは「許可」で上書きする。 「192.168.*.* 以外」からのアクセスはデフォルトポリシーによって「許可」される。

注意しなければならないのは、 <1>,<2> を Allow,Deny とした場合だ。デフォルトは「拒否」。 Allow from が先に評価され、 192.168.1.* からのアクセスが「許可」されるのだが、Deny from が、 Allow from 句のアドレスを内包する 192.168.*.* 全体を「拒否」で上書きする。それら以外はデフォルトポリシーである Deny が「拒否」してしまうので、結局「全て拒否」というルールになってしまう。もっと深刻なのは Allow fromDeny from の範囲が逆転している場合で、その状態で Order を "Deny,Allow" と書いた場合「アクセス制限を掛けたつもりが実はワイドオープン」という危機的な状況に陥ってしまう。

AddHandler と SetHandler

AddHandler ディレクティブは

AddHandler cgi-script .cgi

という具合に使い、この例で言えば、拡張子 cgi のファイルをハンドラ cgi-script に「関連付け」する。

SetHandler のほうは通常 <Directory><Location> ブロックの中で使用し、そのディレクトリあるいはロケーションにあるファイルを拡張子にかかわらず全てハンドラに結びつける。 AddHandler を使うべきところで SetHandler を使ってしまうと、そこにある .html ファイルも .txt ファイルも何もかもそのハンドラで処理されてしまうので、正常に出力されず "File Not Found" などのエラーにぶつかることになる。

ハンドラとは、Apache Doc の言葉を借りれば;

「ハンドラとは、ファイルが呼ばれた際に行われるアクションの、Apache 内部における別名 (representation) である。」

また PHP ソースの sapi/apache2handler/ にある README によれば;

「Apache 2.0 では、コンテンツを生成 (ディスク上のスクリプトを読み取るなど) するのにハンドラという仕組みがある。それによって、コンテンツは一連のフィルタを経ることになる。PHP はそういったフィルタのひとつと成り得るもので、スクリプトを処理してその出力を次のフィルタ (通常はネットワークへの書き出し処理) に渡す。」

AddHandler はよく、最初の例のように Perl スクリプトを Apache に CGI として処理させるために使う。それに対して PHP スクリプトの場合は AddHandler でなく;

AddType application/x-httpd-php .php

という風に AddType ディレクティブを使い MIME タイプとして関連付けするのが普通で、 PHP のドキュメントでもこのやりかたが推奨されている。しかし実は、

AddHandler php-script .php

でもちゃんと機能する。また逆に、 Perl については

AddType application/x-httpd-cgi .cgi

でも、CGI スクリプトは動く。CGI や PHP モジュールへの処理渡しは、MIME タイプに対してもハンドラに対しても定義されているからだ。 Apache がネイティブで備えているもの以外の定義は、各 Apache モジュールの中 (CGI なら mod_cgi.so , PHP4 なら libphp4.so) にコーディングされており、それらのモジュールをロードすることによって Apache にトリガーが追加される仕組みになっているわけだ。

言語設定と文字化け

文字化けの多くは、実際のドキュメントで採用されている文字コードと、 HTTP サーバの付加した HTTP ヘッダが食い違うことで起こる。一般的なブラウザでは、コンテンツ内の <META> タグよりも HTTP ヘッダによる指定のほうが優先して解釈されるようで、いくら META タグで言語やキャラクターセットを示しても、ヘッダの言語指定が勝ってしまう。

Apache では、表示言語に関する設定とコンテントネゴシエーションに関する設定の境界線がわかりにくく、実際、このふたつが協調して動いている部分もある。そのため、文字化け対策のつもりで実は見当違いのディレクティブをいじくりまわしていたという経験が筆者にもある。そこでまず、下表に主な言語関連ディレクティブを類別してみた。

ディレクティブ 機能の要約 管轄モジュール 影響するHTTPヘッダ
コンテントネゴシエーション関係
LanguagePriority コンテントネゴシエーションでドキュメントがひとつに絞り込めなかった場合の、言語マップの優先順位を指定 mod_negotiation Accept-Language
ForceLanguagePriority コンテントネゴシエーションでドキュメントがひとつに絞り込めなかった場合に、LanguagePriority ディレクティブによる設定をどう利用するか。これを None に設定すると、上記 LanguagePriority は無効化される mod_negotiation Accept-Language
Options Multiviews クライアントの要求してきた名称にフルマッチするファイルが存在しない場合に、自動的に、拡張子を取り除いた名称を使って foo.* のようにワイルドカード検索を行い一時的なタイプマップを生成し、コンテントネゴシエーションを行う mod_negotiation, core Accept-Language, Accept
AddLanguage ファイル拡張子 (.en, .ja など) と Content-Language 属性とを関連付け mod_mime Content-Language
DefaultLanguage AddLanguage で定義されていないか言語拡張子の付いていないファイルをどういった Content-Language 属性を持つとみなすか。なお、この設定を "DefaultLanguage en" としてある時に、コンテンツ自体が "Content-Language: ja" というヘッダを持っていた場合、実際にサーブされるヘッダは "Content-Type: ja, en" となる。 RFC-2616 (HTTP/1.1) に忠実に従えば、これは「このコンテンツは日本語を母国語とする人及び英語を母国語とする人向けに書かれています」を意味し、"ja, en" の順序は優先順位を示すわけではないので、良い挙動とは言い難い。敢えてコンテントネゴシエーションを活用する場合を除いては、何も設定しない (コメントアウトしておく) のが最善 mod_mime Content-Language (Accept-Language)
AddCharset ファイル拡張子と charset 属性とを関連付け mod_mime Content-Type charset
MIME関係
AddEncoding コンテントネゴシエーションでも言語でもなく MIME タイプに関するディレクティブ。ファイル拡張子と MIME エンコード方式とを関連付ける mod_mime Content-Encoding
文字コード関係
AddDefaultCharset サーブしようとしたコンテンツの Content-Typetext/html または text/plain で、なお且つ charset が記述されていなかった場合に charset を自動的に付加するか。引数は Off, On (iso-8859-1 つまりラテン系欧州語), 具体的charset のいずれか core Content-Type charset

詰まるところ、ページの出力言語に直接結びついているディレクティブは AddDefaultCharsetDefaultLanguage くらいしかない。ほとんどの WEB ブラウザは Content-Language ヘッダによって挙動を変えることはないので、実質的には AddDefaultCharset 唯ひとつということになる。

具体的な文字化け対策としては、ふたつの方法がある。ひとつは Hosts Default セクションで;

AddDefaultCharset Off

として、 Apache が Content-Type ヘッダに勝手に charset 属性を付加するのを阻止する方法。もうひとつは Hosts Default セクションと適宜特定のディレクトリまたはロケーションに charset を明示する方法で、例えば;

AddDefaultCharset EUC-JP
<Directory /var/www/foo>
  AddDefaultCharset Shift_JIS
</Directory>

としておけば、 /var/www/foo 下の HTML コンテンツは "Content-Type: text/html; charset=Shift_JIS" という HTTP ヘッダを付加して送り出され、それ以外は charset=EUC-JP で送り出される。こちらの方法は、管理者がすべてのドキュメントの言語コードを把握できている場合なら、より確実と言えるだろう。しかし、多人数がコンテンツをアップロードできるような HTTP サーバ環境には適さない。

ここで肝に銘じておかなくてはならないのは、どちらの方法にしろ、いいかげんなドキュメントコードを書いていたのでは元も子もないという点だ。スタティックな HTML ドキュメントなら HTML ヘッダで必ず;

<META http-equiv="Content-Type" content="text/html; charset=EUC-JP">

といった記述を入れること。 Perl スクリプトによる動的コンテンツならば、内容本体を送り出すコードに先立って;

print "Content-Type: text/html; charset=EUC-JP\n\n";

といった HTTP ヘッダ出力コマンドを備えておくこと。根本的に、スクリプト側が charset 属性を出力していれば、 AddDefaultCharset の設定にかかわらず、Apache が charset を勝手に付加することはないのだ。そしてもちろんスタティックなコンテンツの場合と同じく META タグの charset もきちんと吐かせること。 PHP なら HTTP ヘッダを出力する header() 関数という便利なものが用意されている。

文字化け対策として Apache に "DefaultLanguage ja" を設定するというのは、実害こそ無いが、ひどく見当違いだ。それをやると、ASCII のみのドキュメントを送る際にも "Content-Language: ja" という HTTP ヘッダを伴う結果となってしまうし、繰り返しになるが Content-Language ヘッダはブラウザに対してほぼ全く実益がない (上記分類表の DefaultLanguage を参照のこと)。なお、書き方が幾つかある日本語 charset の記述法については 初めてのホームページ講座 > 逆引きHTMLリファレンス > ワンポイント > 「Shift_JIS」or「x-sjis」が参考になる。

UserDir について

UserDir ディレクティブは、かなりおかしな書式を持っている。しかも Apache Doc が的確でないのでさらに混乱を招いているように思える。指定方法のバリエーションを以下に示す。disabled, enabled キーワードは現在のところ disable, enable でも通用する:

記述例 説明
1 UserDir disabled UserDir 機能を全てのユーザに関して無効にする。ただし例 3 による個別指定はこれをオーバーライドできる
2 UserDir disabled user1 user2 user1, user2 に関しては無効にする。例 4 以降のいずれかと併用
3 UserDir enabled user1 user2 user1, user2 に関しては有効にする。引数 user1 ... は必ず要る。例 4 以降のいずれかと併用。例 2 による禁止指定のほうが勝る
4 UserDir public_folder 相対指定のディレクトリ名。http://www.this-server/~hoge/ というリクエストは実ファイルシステム上の /home/hoge/public_folder/ を参照する。最も一般的な方法
5 UserDir /users/public_folder 絶対指定のディレクトリ。http://www.this-server/~hoge/ というリクエストは実ファイルシステム上の /users/public_folder/hoge/ を参照する
6 UserDir /users/*/public_folder ワイルドカードを含む絶対指定。http://www.this-server/~hoge/ というリクエストは実ファイルシステム上の /users/hoge/public_folder/ を参照する
7 UserDir http://www.other-server/*/public_folder 別の HTTP サーバへリダイレクト。この例なら http://www.this-server/~hoge/ というリクエストは結果的に www.other-server/hoge/public_folder/ というロケーションを参照する

筆者は UserDir 機能は嫌い。WEB スペースをたくさんの人にレンタルでもするのならいざ知らず、この機能はめったに必要ないだろう。管理者が把握できる程度のロケーションしか開放しないのなら Alias を使えば充分だ。セキュリティに配慮した、禁止するための設定句は以下。root に対する個別禁止指定は念のため。

UserDir disabled
UserDir disabled root