httpd.confについて調べたのでまとめたよ

最近学科の友人3人とサーバ/セキュリティについての勉強会を週1で行っていて、毎回何か調べてくることになっているのですが、折角だからオレはhttpd.confを選ぶぜ!ということでapacheの設定について少し調べてきました。初心者がまとめたので間違っている部分があるかもしれませんが、勉強の役に立てて頂ければ幸いです。

  • httpd.confはどこにある?
  • 最小限のhttpd.conf
  • 3つのセクション
    • セクション1: GlobalEnvironment
    • セクション2: MainServerConfiguration
    • セクション3: VirtualHosts
  • モジュールの追加
  • 外部設定ファイルの読込み
  • サーバリソースの監視方法

httpd.confはどこにある?

OSによって異なりますが、以下の階層に置いてある可能性が高いです。

CentOSFedoraなどRed Hat /etc/httpd/conf/
SUSE系、MacOSX /etc/apache2/
ソースからインストールした場合 /usr/local/apache2/conf/

最小限のhttpd.conf

httpd.confは標準でもコメント含めて1000行くらい記述してあることが多いですが、以下の最小限の設定で動作します。httpd.confの理解を目的とするのであれば、小さな設定から徐々に設定項目を増やしていくことをお勧めします。ちなみにhttpd.confは再起動した時点で反映されます。

Listen 80
ServerRoot "/etc/httpd"
DocumentRoot "/var/www/html/"

User  nobody
Group nobody

<IfModule prefork.c>
MaxClients       150
StartServers     5
MinSpareServers  5
MaxSpareServers 15
</IfModule>

<IfModule worker.c>
StartServers         2
MaxClients         150
MinSpareThreads     25
MaxSpareThreads     75
ThreadsPerChild     25
MaxRequestsPerChild  0
</IfModule>

MaxRequestsPerChild 0
ErrorLog logs/error_log

<Directory />
    Options FollowSymLinks
    AllowOverride None
</Directory>

3つのセクション

httpd.confの設定項目(ディレクティブ)は、その影響範囲によって主に下記の3つに分類されます。

Section1 GlobalEnvironment Apache全体に影響を及ぼします
Section2 MainServerConfiguration メインのサーバに影響を及ぼします。VirtualHost設定時のデフォルト値にもなります
Section3 VirtualHosts 指定したドメイン/ホストに影響を与えます。MainServerConfigurationを上書きします
セクション1: GlobalEnvironment
# Sample
ServerRoot "/usr/local/apache2"
Listen 80
KeepAlive On
KeepAliveTimeout 15
MaxKeepAliveRequests 100
Timeout 300
ServerRoot Apacheをインストールした場所のパス。以降のディレクトリ指定で相対パスを利用する場合等に利用
Listen 特定のIPアドレスやポート番号だけを受け付ける指定。VirtualHostではここの設定のポート範囲内のみ使用できる
KeepAlive クライアントからの接続要求時にHTTPセッションを即座に閉じず一定時間保っておく設定。パフォーマンス向上に繋がる。ブラウザ側の対応に依存する
KeepAliveTimeout HTTPセッションを保っておく秒数。値を大きくすると転送完了後もクライアントとの接続を維持したままになり他のクライアントへの応答が遅れる。1ページ当たりの平均的な転送時間+αが参考値。サーバのリソース消費を嫌うなら2程度の極端な値に設定するなど
MaxKeepAliveRequests KeepAlive有効時に接続要求を受け付ける数の最大許容値。高い値に設定しておくことが推奨されている。大きな値を設定すると一度のリクエスト処理数が増える代わりに他の接続が割り込むタイミングが遅れる。1ページあたりの平均ファイル数+αが参考値
Timeout クライアントから接続要求を受け取ってタイムアウトするまでの秒数。これを過ぎてもパケットが送信されない場合ブラウザにエラーを返す
セクション2: MainServerConfiguration
# Sample
User apache
Group apache
ServerName example.com
ServerAdmin root@example.com
DocumentRoot "/var/www/html"
<Directory /> ... </Directory>
DirectoryIndex index.html index.php
TypesConfig conf/mime.types
DefaultType text/plain
ServerTokens Prod
ServerSignature Off
Alias /icons/ "/usr/local/apache2/icons/"
User / Group サーバーを実行する為のユーザとグループの指定。apache用に特定のユーザとグループを作成しておくことが推奨されている
ServerName サーバ自身が使用するサーバ名とポート番号の指定。BINDで自動取得出来る場合があるが起動時の問題を避けるため指定しておくことが推奨されている
ServerAdmin エラーメッセージ等に表示される管理者メールアドレス
DocumentRoot ドキュメントルートの指定。基本的にここより上位階層にはアクセス出来ないがSymbolicLinkやAliasを使用すれば実現可能。Aliasはmod_aliasで提供されている機能
... 個々のディレクトリに対する設定。サーバールート(/)に対しての設定は必須
DirectoryIndex スラッシュ「/」で終わるURLを指定した際にデフォルトで表示するファイルを指定。指定したファイルが存在しない場合は、404または403エラーコードを返す
TypesConfig ファイル拡張子とMIMEタイプのマッピングファイルの指定。.htaccessでもAddType application/x-smaf mmfなどで追加できる
DefaultType MIMEタイプファイルに記述が無かった場合の扱いを指定
ServerTokens エラーメッセージ出力時等のサーバ情報を制限。情報が多い順に Full, OS, Min, Minor, Major, Prod
ServerSignature エラーメッセージ等をクライアントに返す際のフッターラインの表示を指定。On, Off, EMail(mailto:...が付く)が指定可能
Alias 第1引数へのアクセスを第2引数へ繋ぐ。/icons/のように後ろにスラッシュが入った場合は/iconsというURL自体はエイリアスされないので注意
セクション3: VirtualHosts
# Sample
NameVirtualHost *:80
<VirtualHost *:80>
  ServerName arumakan.org
  DocumentRoot /var/www/lokka/public
  <Directory /var/www/lokka/public>
    Allow from all
  </Directory>
</VirtualHost>

<VirtualHost *:80>
  ServerName gakuweb.com
  DocumentRoot /var/www/eden/public
  <Directory /var/www/html>
    Allow from all
  </Directory>
</VirtualHost>

<VirtualHost *:80>
  ServerName 19950117.jp
  DocumentRoot /var/www/shinsaiNow/public
  <Directory /var/www/html>
    Allow from all
  </Directory>
</VirtualHost>

上記の例の場合、全てのIPアドレスの80番ポートへのアクセスはNameVirtualHostが全て扱い、ServerNameに設定しているドメイン名別に違うディレクトリへアクセスするようにしています。ここに記載されていないがIPアドレス自体はこのサーバを向いているというドメインにアクセスした場合は、最も上に記述しているServername arumakan.orgの設定が適用されます。


上記の例では名前ベースのVirtualHost(NameVirtualHost)を利用しています。
VirtualHostの設定には以下の2種類の方法があります(混合も可能)。

名前ベース アクセスされる名前(ホスト/ドメイン)によって挙動を変える
IPアドレスベース アクセスされるIPアドレスによって挙動を変える

前者は1つのサーバに対して複数の名前が与えられているとき、後者は1つのサーバに対して複数のIPアドレスが与えられている時に有効な設定です。個人でサービス開発を行っている場合には前者のケースの方が多いかと思います。例えば私の場合であれば、さくらVPSで借りているCentOSのサーバにIPアドレスを1つ頂いていますが、そのIPアドレスに対して19950117.jpgakuweb.comという名前をドメイン取得元のDNS設定で与えています。これらは別のサービスなので、名前ベースのVirtualHostの設定を行い、ドメインによってそれぞれアクセスされるディレクトリを変えています。


名前ベースのVirtualHostを期待通りに動作させるには、アクセスがどのような流れで解決されるのかを知っておく必要があります。example.comに対してアクセスがあった時の大まかな流れを以下に示します。

  1. http://example.com に対してアクセスが行われた
  2. listen *:80 を設定しているのでApacheはこれを処理することを決めた
  3. NameVirtualHost *:80 を設定しているので主サーバー自体はこれを扱わずVirtualHostに委譲
  4. VirtualHost の中でexample.comに一致する条件を設定しているものを探す
  5. VirtualHost *:80 を設定しているものが2つあった
  6. 2つの中でServerName example.comのものを選ぶ。無ければ1番上に記述しているものを選ぶ
  7. ServerName example.com の設定をしているVirtualHostが1つあった
  8. その中のDocumentRootを見に行く
  9. URLでファイル名が指定されていないのでindex.htmlなどを見に行く

モジュールの追加

Apacheの基本的な機能と設定の説明は以上ですが、Apacheはモジュールを追加することで機能を拡張することが出来ます。Apacheに組み込めるモジュールの種類は大きく分けて以下の2つに分類されます。

  1. コンパイル時に組み込まれるモジュール
  2. 実行時に組み込まれるモジュール

httpdに-lオプションを渡して実行すればコンパイル時に追加されているモジュールを確認できます。またApache2.0以降ではDSO(DynamicSharedObject)という機能で実行時にもモジュールを取り込めます。実行時にモジュールを組み込むにはhttpd.conf等に以下のように設定します。標準でもかなり多くのモジュールが設定されていますが、パフォーマンスに影響を与えるので、理解可能であれば必要最低限のモジュールのみ読み込むように設定した方が良いです。

X / _ / X < /usr/sbin/httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

X / _ / X < cat /etc/httpd/conf/httpd.conf -n | grep LoadModule
   146	# LoadModule foo_module modules/mod_foo.so
   147	LoadModule auth_basic_module modules/mod_auth_basic.so
   148	LoadModule auth_digest_module modules/mod_auth_digest.so
   149	LoadModule authn_file_module modules/mod_authn_file.so
   150	LoadModule authn_alias_module modules/mod_authn_alias.so
   151	LoadModule authn_anon_module modules/mod_authn_anon.so
     ...

外部設定ファイルの読込み

Fedora Core / SUSE / Turbo 等のOSではconf.d/*.confという外部ファイルに設定を分け、それらを起動時に読み込む設定をhttpd.confに書くが常套手段となっています。ここのパスはServerRootで指定されたディレクトリからの相対パスなので注意してください。この設定により、ServerRoot/conf.d/ 以下の拡張子.confのファイルが全て設定ファイルとして読み込まれます。例として、http://example.com/blog へのアクセスに対してアクセスされるディレクトリをwordpressに設定するため、conf.d/wordpress.confにAliasの設定を書くなどの利用方法が挙げられます。

X / _ / X < cat /etc/httpd/conf/httpd.conf -n | grep \*.conf
   210	Include conf.d/*.conf

X / _ / X < tree /etc/httpd
/etc/httpd
|-- conf
|   |-- httpd.conf
|   `-- magic
|-- conf.d
|   |-- README
|   |-- php.conf
|   |-- phpmyadmin.conf
|   |-- proxy_ajp.conf
|   |-- welcome.conf_old
|   `-- wordpress.conf
|-- logs -> ../../var/log/httpd
|-- modules -> ../../usr/lib64/httpd/modules
`-- run -> ../../var/run

X / _ / X < cat /etc/httpd/conf.d/wordpress.conf 
Alias /blog /var/www/wordpress

サーバリソースの監視方法

本題とは少し内容が逸れますが、設定のために必要になったのでサーバリソースの監視方法についても少し調べました。Apacheでは使用するプロセス数を設定出来ますが、これにはApacheのプロセスがサーバのリソースにどれだけ影響を与えるかを見極める必要があります。1プロセスあたりのメモリ使用量はpsコマンドやtopコマンドで調べられます。psはシステムで実行中のプロセスを表示するコマンドです。$ ps aux | grep [a]pache のように使用します。[a]と角括弧で括っているのは出力結果にgrepのプロセス自体を含めないためのハックです。真面目に書きたい人は$ ps aux | grep apache | grep -v grepとして「grepが含まれない行だけ出力する」としても良いですね。しかしgrepではpsコマンド1行目の部分が表示されず残念な感じなので、psコマンドに-u apache(USERを指定するオプション)か-C httpd(COMMANDを指定するオプション)を付けます。

# Usage
ps [-] [acefhjlmnrsuvwxS] [txx] [O[+|-]k1[[+|-]k2...]] [pids]

# Sample - COMMANDにhttpdを含むプロセスをユーザ名と開始時刻とツリー付きで表示
X / _ / X < ps uf -C httpd
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     18796  0.0  0.5 235012  3020 ?        Ss   Feb21   0:00 /usr/sbin/httpd
apache   18813  0.0  0.4 235148  2552 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18814  0.0  0.5 235152  2608 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18815  0.0  0.4 235148  2548 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18817  0.0  0.4 235148  2540 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18818  0.0  0.5 235152  2612 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18819  0.0  0.4 235148  2544 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18820  0.0  0.5 235148  2588 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   18821  0.0  0.5 235148  2556 ?        S    Feb21   0:01  \_ /usr/sbin/httpd
apache   17850  0.0  0.5 235148  2708 ?        S    Feb22   0:00  \_ /usr/sbin/httpd
apache   20876  0.0  0.5 235148  2804 ?        S    Feb22   0:00  \_ /usr/sbin/httpd
apache   19144  0.0  0.5 235148  2788 ?        S    Feb23   0:00  \_ /usr/sbin/httpd

# Sample - uid18796のプロセス(rootが動かしているhttpd)の遷移状態をツリー表示
X / _ / X < pstree 18796 -u -A
httpd-+-PassengerWatchd-+-PassengerHelper-+-ruby---2*[{ruby}]
      |                 |                 `-14*[{PassengerHelper}]
      |                 |-PassengerLoggin(nobody)---{PassengerLoggin}
      |                 `-3*[{PassengerWatchd}]
      `-11*[httpd(apache)]

apacheのプロセスは、まずrootで1本起動させてから内部でUser/Groupに指定したユーザで子プロセスを複数生成します。勉強会中に友人に教えてもらったのですが、pstreeコマンドを利用すると実行中のプロセスの親子関係がツリー構造で表示されて分かりやすいです。上記の例では、rootのhttpdプロセスがapachehttpdプロセスを11本生成していることが分かります。またPassengerというRubyOnRailsのアプリをapacheで動かしてくれるモジュールを入れているので、その関係のプロセスも生成されています。プロセス数はapacheがよしなに調整してくれますが、これは『最小限のhttpd.conf』で記述したprefork.c内のStartServers 5(起動時)、MinSpareServers 5(最小数)、MaxSpareServers 15(最大数)の設定に基づいて管理されています。今回はこれらの設定値を最適化するためにメモリ使用量を調べた、という顛末でした。
最後に、psコマンドで利用するオプションと表示される要素について説明しておきます。



オプション

a 自分以外のユーザーのプロセスも表示する
c task_structに格納されているコマンド名を表示する
e 「実行命令 + 」に環境変数を付加する
f ツリー形式で表示する
h ヘッダーを表示しない
j pgidとsidを表示する
l 標準のPID,TTY,TIME,CMDに加え,F,S,UID,PPID,C,PRI,NI,ADDR,SZ,VSZ,RSS,WCHAN,STATも表示する
m スレッドも表示する
n USERとWCHANを数字で表示する
r 実行中のプロセスだけ表示する
s シグナル形式で表示する
u ユーザー名と開始時刻を表示する
v vm 形式で表示する
w 1行追加して表示を拡大する。wを増やすことによって行数をさらに増やせる
x 制御端末のないプロセスの情報も表示する
S 子プロセスのCPU消費時間とページ・フォルトを合計する
txx tty xxのプロセスのみ表示する
pids 表示するプロセスIDを指定する


表示される要素の意味

F プロセスの状態を示すフラグ。16進数で表されている。それぞれ,00:プロセスが終了している,01:システム・プロセス(常にメモリー上に存在する), 02:親プロセスからトレースされている,04:親プロセスからトレースされ,停止している,08:プロセスがシグナルで起動できない,10:プロセスがメモリー上にあり,イベント終了までロックされている,20:プロセスがスワップできない,ことを意味している。
USER プロセスの所有ユーザ
UID ユーザーID
PID プロセスID
&CPU CPUの占有率
&MEM 実メモリでの占有率
SIZE 仮想分も含めた使用サイズ[kB]
VSZ 仮想メモリの全サイズ
RSS 使用中の物理メモリー量
TTY 制御端末の種類および番号
STAT/S プロセスのステータス。Rは実行可能,Sは停止,Dは割り込み不可の停止,Tは停止またはトレース中,Zはゾンビ・プロセス,Wはスワップ・アウトしたプロセス,Nはナイス値が正であることを表す
PPID 親プロセスID
PRI 優先度
NI ナイス値
WCHAN プロセスが休眠状態の時のカーネル関数名
START プロセスの開始時刻
TIME プロセスの総実行時間
COMMAND/CMD プロセスのコマンド名