Monthly Archives: 6月 2008

suPHPの設定とインストール

//概要
CGIWrapではperlCGIによるラッパー機能を提供してきた。
しかし、このラッパーではPHP容易にセキュア化したり、バーチャルホストごとの設定が困難である。
そこで、今回はsuPHPを用いてこの問題に対処する。


//suPHPとは
suPHPとは、mod_cgiwrapの後継となるもので、元々はcgiwrapのモジュール版であった。
cgiwrapをモジュール化することにより、より高速にCGIを動かす工夫がなされた。
これを発展させたのがsuPHPであり、その名のとおりPHPに対応したラッパーである。
本来の機能として、PHPを自UID/GIDで実行できる他、通常のCGIも自UID/GIDで実行することが可能だ。
さらに、mod_vhost_aliasに対応しているため、容易にバーチャルホスト毎に別UID/GIDで動作することができるのである。


//動作速度の問題
suPHPが嫌われる原因としてよく挙げられるのが、動作速度の問題である。
これは、本来PHPが高速で動作しているのはPHPインタプリタがモジュールとして動作しているためであって、
それ以外の方法で(CGIにより)動作させると少なからず動作速度が落ちてしまう、ということである。
従って、PHPをCGIモードで動作させるsuPHPが速度が落ちがちだといわれる。が、実はそうでもない。
現バージョンのsuPHPの場合は、FastCGI方式を採用しているためPHPインタプリタが常に常駐化され、
ほぼモジュール版と変わらない動作速度で動作することが可能なのである。
#これについては環境変数で出た情報のみから記述しているため、実際のところは不明。
#分かり次第(ソースがあり次第)追記することにする。

実際は、単にPHPがFastCGIに対応していただけの模様。


//設定・インストール
・ここでは、当サーバの設定を例に一連の流れを説明する。
Fedora Core 5の場合は、すでにrpmパッケージが公開されているので、yumからmod_suphpをインストールすればよい。
今回使用しているディストリビューションはCentOSだが、Fedoraのソースrpmをコンパイルして使用することにする。
*DACにあるパッケージはコンパイルの設定が違う、またソースからのインストールはパッチを当てなければならない箇所が多いため。
○ファイルのダウンロード・リビルド・インストール
基本的にFedoraとCentOSは互換性があるが、glibcのバージョンの関係上同じバイナリファイルを使用できない。
そのため、Fedora CoreのExtrasよりソースrpmをタウンロード、リビルドして使用する。
[root@www ~]# wget http://ftp.riken.jp/Linux/fedora/extras/5/SRPMS/mod_suphp-0.6.1-4.fc5.src.rpm
21:59:08 http://ftp.riken.jp/Linux/fedora/extras/5/SRPMS/mod_suphp-0.6.1-4.fc5.src.rpm
=> `mod_suphp-0.6.1-4.fc5.src.rpm’
Resolving ftp.riken.jp… 134.160.38.1
Connecting to ftp.riken.jp|134.160.38.1|:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 375,718 (367K) [application/x-wais-source]
100%[================================>] 375,718 1.16M/s
21:59:08 (1.15 MB/s) – `mod_suphp-0.6.1-4.fc5.src.rpm’ saved [375718/375718]
[root@www ~]# rpmbuild –rebuild mod_suphp-0.6.1-4.fc5.src.rpm←ソースrpmをリビルド
……
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd suphp-0.6.1
+ rm -rf /var/tmp/mod_suphp-0.6.1-4-root-root
+ exit 0
Executing(–clean): /bin/sh -e /var/tmp/rpm-tmp.27399
+ umask 022
+ cd /usr/src/redhat/BUILD
+ rm -rf suphp-0.6.1
+ exit 0
[root@www ~]# rpm -ivh /usr/src/redhat/RPMS/i386/mod_suphp-0.6.1-4.i386.rpm←suPHPのインストール
Preparing… ########################################### [100%]
1:mod_suphp
########################################### [100%]
[root@www ~]# chmod o+rx /usr/sbin/suphp←現行パッケージのバグ対策
○suPHPの設定
suPHPの設定ファイルを開き、設定する。
[root@www ~]# vi /etc/suphp.conf
docroot=/←変更(/home/より上層での実行禁止)

docroot=/home/
umask=0077←umaskの変更(作成ファイルのデフォルトパーミッションを644にする)

umask=0022
handle_userdir=true←変更(/~以降のユーザディレクトリでも動作可能にする)
errors_to_browser=false←変更(エラーをブラウザ上に表示)

errors_to_browser=true
○Apache再設定
suPHPを適用するためApacheを再設定する。
[root@www ~]# vi /etc/httpd/conf.d/suphp.conf
suPHP_Engine off←変更(suPHPを有効にする)

suPHP_Engine on
AddType application/x-httpd-php .php←追加(〃)
AddHandler x-httpd-php .php
AddHandler x-suphp-cgi .cgi .pl

# suPHP_AddHandler x-httpd-php←コメントアウト(〃)

suPHP_AddHandler x-httpd-php
suPHP_AddHandler x-suphp-cgi←追加(〃)
[root@www ~]# mv /etc/httpd/conf.d/php5.conf /etc/httpd/conf.d/php5.conf.org←名前変更(module版PHPによる実行をストップ)
[root@www ~]# /etc/init.d/httpd restart←Apache再起動
これにより、CGI/PHPともに自UID/GIDで実行できる。
また、suPHPにより、ディレクトリやファイルのパーミッションが777である場合、実行が強制ストップされる。
(/etc/suphp.confにより変更可能)
また、mod_vhost_aliasを適用することによりバーチャルホスト毎に別UID/GIDで動作することができた。
->ユーザ毎にバーチャルホストを設定する方法


//参考サイト
suPHP – Home:
http://www.suphp.org/Home.html
サードパーティリポジトリーを使う:
http://www.geocities.jp/hoge_tomo/20050318.html

[豆知識]perl cgiの高速化 -perlcc-

perlで大掛かりに組まれたCGIの中には、モジュールをたくさん使うものなど、処理に時間がかかるものあります。
今回は、perlccを用いてあらかじめコンパイルしておき、高速化させることにしました。
*基本的にコンパイルに時間がかかる様なCGIでのみ高速化が期待きそうな感じです。
丁度いいところに貧弱なサーバで動いてる、とっても低速なawstatsがあったので、コンパイルしてみました。
ちなみに、perlccの使い方については、 man perlccコマンドで確認できます。
[root@www cgi-bin]# perlcc -B awstats.pl ↑バイトコードバックエンドを使用してコンパイル
[root@www cgi-bin]# ll
合計 2476
-rwxr-xr-x 1 root root 1966174 5月 23 01:20 a.out   ←コンパイルされたファイルが出来上がっている
-rwxr-xr-x 1 root root 5407 11月 19 2005 awredir.pl
-rwxr-xr-x 1 root root 544954 11月 25 05:11 awstats.pl
[root@www cgi-bin]# mv awstats.pl awstats.pl.org ←もしものために元ファイルを.orgとして保存しておく
[root@www cgi-bin]# mv a.out awstats.pl ←コンパイルしたファイルを元ファイル名にリネーム
[root@www cgi-bin]#
これで、サーバに設置してあるawstatsのもたつきがほぼ無くなり、スムーズに閲覧できるようになりました!
参考: perlcc – Perl プログラムから実行形式を生成

ユーザ毎にバーチャルホストを設定する方法

//概要
普段、ユーザのpublic_htmlディレクトリはhttp://www.example.com/~foo/の形で公開される。
今回は、それをワンランクアップし、http://foo.example.com/でアクセスできるように設定する。


//mod_vhost_aliasを使用した方法
・Apache付属のモジュールの中に、mod_vhost_aliasと言うモジュールがある。
 これを使用すると、たった一行でバーチャルドメインが実現できる。以下に例を示す。
VirtualDocumentRoot /home/%1/public_html
↑http://foo.example.com/に対して/home/foo/public_htmlを割り当てる。
お分かりいただけるだろうか。見ての通り実に簡単である。
ただし問題点はある。それは各種ラッパーを一切使用できないことだ。
理由は、ラッパーの仕組みを思い出せば分かってくる。
数あるラッパー、例を挙げるとCGIWrapの場合ユーザとパスを判別するには環境変数の’PATH_INFO’か’QUERY_STRING’から情報を抜き取って判別している。
PATH_INFOの場合、/~foo/hoge.cgiの形式でないと認識できないし、
QUERY_STRINGの場合、/path-to-cgiwrap/cgiwrap/foo/hoge.cgiの形式でないと認識できない。
つまり、バーチャルホストにした際のパスでは/~foo/hoge.cgiにならないため認識できないのである。
対処方法としては、以下のようにmod_rewriteを使用した方法がある。


//mod_rewriteを使用した方法
1,/~fooへマッピングする
・すぐに思いつく方法としては、http://foo.example.com/へ向けられた要求を/~fooへ向けることである。
これにより、バーチャルホストのマッピングができるうえに、CGIWrapの認識できるパス通りにPATH_INFOを設定できる。
以下に例を示す。

ServerName www.example.com
ServerAlias *.example.com
RewriteEngine On
RewriteCond ^/cgiwrap/

RewriteCond
{REQUEST_URI} ^/~
↑www.example.com , /cgiwrap , /icons , /~ を含むアドレスにはマッピングしない
RewriteRule ^(.+) %{HTTP_HOST}$1 ©
RewriteRule ([.]+)\.example\.com/(.*) /~$1/$2 [PT]
RewriteRule ([.]+)\.example\.com$ /~$1/ [PT]
↑http://foo.example.com/に対して/~fooを割り当てる。

これで、/~fooに対してマッピングできる。しかし、これにも欠点がある。
それは、cgiなどで相対パス等を取り扱ったときにhttp://foo.example.com/~foo/と表示されてしまう点だ。
NotFoundなどのエラーメッセージにも同様の症状が発生する。http://foo.example.com/hoge.cgiでアクセスしたはずなのに、
いつの間にかhttp://foo.example.com/~foo/hoge.cgiになっていた、なんていうことも起こってしまう。
これは当然の挙動としか言いようが無い。http://foo.example.com/に対して
http://foo.example.com/~foo/をマッピングしているのだから。
対処法としては、以下の方法がある。
2,/home/foo/public_htmlへマッピングし、CGIScriptに対しては/cgi-bin/cgiwrap/foo/へマッピングする
・標準時は/home/foo/public_htmlへ直接マッピングをかけてあげて、
ラッパー対象ファイルに対しては/cgi-bin/cgiwrap/foo/へマッピングすれば、CGIWrapがQUERY_STRINGを使用して
認識できるので見事に実現できるはずである。以下に例を示す。
ServerName www.example.com
ServerAlias *.example.com
RewriteEngine On
RewriteCond ^/cgiwrap/

RewriteCond
{REQUEST_URI} ^/~
↑www.example.com , /cgiwrap , /icons , /~ を含むアドレスにはマッピングしない
RewriteRule ^(.+) %{HTTP_HOST}$1 ©
# For CGI Files
RewriteRule ([.]+)\.example\.com/(.+)\.cgi(.*) /cgi-bin/cgiwrap/$1/$2\.cgi$3
[NS,T=application/x-http-cgi,PT,L]
↑http://foo.example.com/hoge.cgiに対して/cgi-bin/cgiwrap/foo/hoge.cgiを割り当てる。
# For Normal Files
RewriteRule ([.]+)\.example\.com/(.*) /home/$1/public_html/$2 [L]
RewriteRule ([.]+)\.example\.com$ /home/$1/public_html [L]
↑http://foo.example.com/に対して/home/foo/public_htmlを割り当てる。

これで、ユーザ毎にバーチャルドキュメントを実現でき、かつCGIWrapが有効になる。
1 2