C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

Apache2 と VirtualHost を解説

自鯖の勉強したい学生さんからの相談。今回は「apache2入れたんだけど仮想ホストがわかんねーる・x・」にお答えします。

1. Apache2に於けるVirtualHostとは何か

Apache2はhttpプロトコルのサービスを提供するサーバーソフトウェアです。通常はポート80でクライアント(いわゆるウェブブラウザ)からのコネクションを待ち受け、プロトコルに基づいた通信(GET, PUT, POST, DELETE とか)を行います。

さて、ここで単純に考えれば1つのIPアドレスに対して複数のhttpd(httpのデーモン、今の話の流れではApache2)プロセスが待ち受ける事は容易にはできない。しかし、これを簡単にどうにかするのがApache2のVirtualHost(仮想ホスト)機能である。この機能によりApache2のユーザーは1つのIPの1つのポートに複数のサイトをホスティングする事が容易に可能である。

2. Apache2のVirtualHostの仕組み

Apache2は単純にListenディレクティブで指定されたポートを待ち受ける。これだけではVirtualHostは実現できないか、できるとしてもホスト毎に待ち受けポート番号を変える必要がある。例えば、 http://192.168.0.1:80/http://192.168.0.1:10080http://192.168.0.1:10081 … と言った具合に、httpクライアント(ウェブブラウザ)のユーザーに取得するアドレスをポートをセットで指示してくれればこの戦略は成功するし、サーバーもListenするポート毎にサイトのホスティング定義を関連付ければ良いので当然動作する。しかし、この様な同じIPやFQDNでもポートによってサイトが異なるという事態はユーザーにとって違和感や混乱を齎し、また非標準のポート番号を使う事となり全く美しくない。

そんな訳でApache2のVirtualHost機能を使う事で、1つのIPアドレスの1つのListenポートに対しても、ホスティングするサイト定義を多重化し、かつどうにかしてクライアントが要求してきたサイトを選択して応答する事が出来る。

「どうにかして」と書いたが実はhttpプロトコルについて少し勉強すればそれが実に簡単な事がわかる。より具体的に言えば、HTTPリクエストヘッダーのhostの仕様[Studying HTTP] HTTP Header Fieldsなど参考に確認してみよう。

…確認できただろうか?つまり、httpdはクライアントが接続したいホスト名についてhttpで通信する前提として普通に取得できるのだ。よってApacheは内部に複数のサイト定義を持っていたとしても、クライアントからのhttpリクエストヘッダーの情報から、そのクライアントがどのホスト(サイト定義)へ接続したいのかを判断し、動作を振り分けられる。

3. Apache2でVirtualHostを使う設定

バーチャルホストの例 - Apache HTTP サーバを読むと丁寧で解りやすい。

先ず、 NameVirtualHost *:80 により、あらゆるIPのポート80で名前ベースの仮想ホスト機能を有効にするフラグを立てる。なお、あらゆるIPとは、ローカルホストループバック(lo)の127.0.0.1と装着されたNIC(eth0など)に割り当てられたIPアドレス(192.168.0.1とか)、その他 ifconfig で表示されるものがあればそれらを含めた全てであり、これは*により設定されている。

続いて仮想ホスト機能を用いたサイトの定義を記述する。

<VirtualHost *:80>
  DocumentRoot /www/foo.bar
  ServerName foo.bar
  <Location />
    Options +Indexes
    Order allow,deney
    allow from all
  </Location>
</VirtualHost>

とか。はここから仮想ホストで運用するサイトの定義を行いますよ、という指示。この中でServerNameディレクティブを指示すると、Apache2はこれとクライアントからのHTTPリクエストヘッダーを元にその接続で用いるべきサイトの定義を選択する。

ちなみに、VirtualHostを用いる場合は最初に定義された仮想ホストがデフォルトの選択肢となり、ServerNameとHTTPリクエストヘッダーのホスト名のマッチングに失敗した場合は設定中で最初に定義されたVirtualHostがデフォルトとなる点には注意した方が良い。

また、Directoryはサーバーの絶対パス、Locationはドキュメントルートからの相対パスにより、そのパスにおけるOptions等の動作を変化させる事を指示する。パスに対するディレクティブは設定中で上位のスコープから適用され、下位のスコープで既に上位のスコープで定義済みのディレクティブが再定義される場合には挙動を上書きする。

なお、設定した筈の挙動にならない場合には、 /var/log/apache2/access.log や /var/log/apache2/error.log を見ると良い。(これはUbuntuの場合のパスであり、例えばArch Linuxであれば/var/log/httpd/access.logなど微妙にログファイルのパスが異なる事がある)ログファイルの内部では最下部が最新の記録である。