apache + suexec, suphp

cgi + suexec

cgiapacheユーザじゃなくて、ファイルのオーナ権限で動かす設定。共有サーバで必要になりそうなので今更だけど調べた。mod_phpで動いているphpは対象外のようだ。shebangに#!/usr/bin/phpとか書いてcgiで動かすか、suphpでwrapするかの2つ?後述。

目的

cgiをユーザ権限で動かす。デフォルトだと、apacheユーザの権限で動くので、不用意に他のファイルにアクセスできる。あと、cgiが作成したファイルがユーザ権限とは異なるので、ユーザ自身で削除できなくなることもあり、管理が面倒だから。

制約

apacheの公式に書いてる20の基準を満たす必要がある。ディレクトリ、ファイルのパーミッション、ファイルのオーナーなど。しっかり把握して使用する必要あり。

configure オプション

とりまこんな感じで。

./configure" \
--prefix=/usr/local/apache2 \
--with-included-apr \
--enable-suexec \
--with-suexec-bin=/usr/local/apache2/bin/suexec \
--with-suexec-caller=www-data \
--with-suexec-docroot=/home \
--with-suexec-userdir=public_html \
--with-suexec-uidmin=100 \
--with-suexec-gidmin=100 \
--with-suexec-logfile=/usr/local/apache2/logs/suexec.log 
VirtualHost環境で動かす

各VirtualHost内に

SuexecUserGroup user1 user1

と書くだけでいい?注意点としては、各VirtualHostのDocumentRootは--with-suexec-docroot以下に配置する必要があるので、ディレクトリの場所を統一しないといけない模様。/home/user/public_html みたいに。

各ユーザのwebディレクトリで動かす
Userdir public_html

とかの設定を入れていて。

などで実行したい場合。--with-suexec-userdirで指定するディレクトリに置くだけ。

suphp

suexecはcgiが対象なのでmod_phpだとダメ。で、調べてるとsuphpてのがあるらしい。これ使うとphpのソースに#!/usr/bin/phpとか書かなくても良いらしい。へー。

メリット/デメリット

メリット:ユーザごとのphpのリソース使用状況がわかる。(mod_phpだとapacheのプロセスの中に含まれてしまうので、個別に調べるの難しい)
デメリット:cgiなのでmodule版と比較するとパフォーマンス落ちる

phpインストール

suphpを使うにはcgiphpのインストールが必要。

./configure \
--prefix=/usr/local/php \
--enable-cgi \
--enable-force-cgi-redirect 

その他必要は分は追加。--with-apxs2を入れるとenable-cgiしてもCLI版が出来てしまうというとこに少しはまってしまった。

$ php-cgi file.php

としたときに、HTTPヘッダが表示されていればcgi版バイナリ。

suphp install
./configure \
--prefix=/usr/local/suphp \
--with-apxs=/usr/local/apache2/bin/apxs 
--docdir=/home \
--with-apache-user=www-data \
--with-apr=/usr/local/apache2/bin/apr-1-config \
--with-setid-mode=paranoid \
--with-min-uid=100 \
--with-min-gid=100 \
--with-logfile=/usr/local/apache2/logs/suphp_log

--with-setid-modeはowner, force, paranoidの3つから選択。デフォルトはparanoid。

MODE has to be one of:
  "owner":    Run scripts with owner UID/GID
  "force":    Run scripts with UID/GID specified in Apache configuration
  "paranoid": Run scripts with owner UID/GID but also check if they match the UID/GID specified 
                in the Apache configuration
The default is "paranoid" mode.
  You should *NEVER* use "force" mode as it is very dangerous.
  While "owner" mode is not as dangerous as "force" mode its use is disadvised and "paranoid" mode should be preferred.
suphpのconfig

debianのapt-getバージョンから拝借。

  • PREFIX/etc/suphp.conf
[global]
;Path to logfile
logfile=/usr/local/apache2/logs/suphp.log

;Loglevel
loglevel=info

;User Apache is running as
webserver_user=www-data

;Path all scripts have to be in
docroot=/home

;Path to chroot() to before executing script
;chroot=/mychroot

; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true
;Send minor error messages to browser
errors_to_browser=false
;PATH environment variable
env_path=/bin:/usr/bin

;Umask to set, specify in octal notation
umask=0077
; Minimum UID
min_uid=1000
; Minimum GID
min_gid=1000

[handlers]
;Handler for php-scripts
application/x-httpd-php="php:/usr/local/php/bin/php"
;Handler for CGI-scripts
x-suphp-cgi=execute:!self
apacheの設定

Handlerはsuphp.confのHandlersとあわせる。一致してればなんでも動くぽいけど、apacheが変なmedia typeだとapacheがエラー吐くので、suphp.confもhttpd.confもapplication/x-httpd-phpにしといた。
あと、--with-setid-mode=paranoid (デフォルト)で設定している場合はsuPHP_UserGroupでユーザとグループの指定も必要なので、VirtualHost内などに適当に設定。

LoadModule suphp_module        modules/mod_suphp.so

<IfModule suphp_module>
  <Directory /home >
    suPHP_Engine on
  </Directory>
  AddType application/x-httpd-php .php .php3 .php4 .php5 .phtml
  suPHP_AddHandler application/x-httpd-php
</IfModule>

<VirtualHost *:80>
  ServerName hoge.example.com
  suPHP_UserGroup hoge hoge
</VirtualHost>

<VirtualHost *:80>
  ServerName fuga.example.com
  suPHP_UserGroup fuga fuga
</VirtualHost>

php.iniの上書き

suphpを使うと、httpd.conf/.htaccessともにphp_value/php_flagなどのmod_phpのディレクティブが使えなくなる。なので、httpd.conf/.htaccessで各ユーザが独自に設定できるphp.iniのパスを指定して、そこで設定する。

ちなみにsuPHP_ConfigPathが指定されていない場合、phpファイルと同ディレクトリにphp.iniがあれば、それが適用される模様。でも下位のディレクトリには反映されないので、やはりsuPHP_ConfigPathを使うほうが良さげ。

httpd.conf or .htaccess

php.iniの置き場所を指定。(/home/user/php.inを使う例)

suPHP_ConfigPath /home/user/
php.iniの設定

通常のphp.iniのようにname = value の形式で設定する。

追記

後で思ったが、こんなことしなくてもcgi版のphpバイナリをinstallして、Action(mod_action)と組み合わせれば良いのか?

追記2

あー思い出したわ。環境によっちゃmod_actionよりmod_suphpのほうが良いこともあるか。あとでまとめよう。