Sun が Oracle に買われて以降、Solaris がどうなるのかハッキリしない状態が続いていたので、新しいバージョンがリリースされた事は良かったと思います。OpenSolais の体制のままで新バージョンがリリースされていれば最高だったんですけどね。
リリースはされましたが、Oracle Solaris 11 Express は snv_151 で、OpenSolaris 2009.06 の snv_111b からは大きく変わっているらしく、一回でアップグレードはできません。一度 snv_134b(キャンセルされていた OpenSolaris 2010.06 になるはずだったバージョンですね)に上げた後で、パッケージリポジトリ(パブリッシャ?)を変更して再度アップグレードを行う必要があるようです。
最終的に Oracle Solaris 11 Express(毎回書くのは長いな、略称は何だろ?)を使うか、OpenIndiana を使うようになるかは分かりませんが、どちらにしろ 134b にアップデートしておく必要はあるみたいです。
アップデートはpkg image-updateコマンドで行いますが、先に SUNWipkg パッケージを更新しておく必要があるみたいです。
pfexec pkg install SUNWipkg pfexec pkg image-update -v --be-name snv_134b
いろいろとパッケージをインストールして遊んでいたので、2時間くらいかかりました。
本番環境をアップグレードする前に VirtualBox に OpenSolaris 2009.06 をインストールして、アップデートの実験は何度もしていたので、この手順自体は問題なく終わりました。svcsコマンドでサービスの起動状況を確認して、maintenance になっているものも無かったので、アップグレードは無事終わったかと思っていましたが、ブログを表示させようとするとこんな感じになっていました。
お使いのサーバーの PHP では WordPress に必要な MySQL 拡張を利用できないようです。
php-cgi コマンドが正常に動いていないのか、と思い直接実行してみると
# /usr/php/bin/php-cgi -v PHP Warning: PHP Startup: Unable to load dynamic library '/usr/php/5.2/zts-modules/apc.so' - ld.so.1: php-cgi: 重大なエラー: 再配置エラー: ファイル /usr/php/5.2/zts-modules/apc.so: シンボル compiler_globals_id: 参照シンボルが見つかりません。 in Unknown on line 0 PHP Warning: PHP Startup: Unable to load dynamic library '/usr/php/5.2/zts-modules/bz2.so' - ld.so.1: php-cgi: 重大なエラー: 再配置エラー: ファイル /usr/php/5.2/zts-modules/bz2.so: シンボル core_globals_id: 参照シンボルが見つかりません。 in Unknown on line 0 PHP Warning: PHP Startup: Unable to load dynamic library '/usr/php/5.2/zts-modules/curl.so' - ld.so.1: php-cgi: 重大なエラー: 再配置エラー: ファイル /usr/php/5.2/zts-modules/curl.so: シンボル core_globals_id: 参照シンボルが見つかりません。 in Unknown on line 0 PHP Warning: PHP Startup: ftp: Unable to initialize module Module compiled with module API=20060613, debug=0, thread-safety=1 PHP compiled with module API=20060613, debug=0, thread-safety=0 These options need to match in Unknown on line 0 (略) PHP 5.2.12 (cgi-fcgi) (built: Apr 5 2010 20:00:17) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
マルチスレッドでない PHP のプロセスから、マルチスレッドを有効にしたモジュールを読み込もうとして失敗しているようです。php コマンドは正常に動作していましたが、nginx は CGI を使えない。そもそも zts-modules なんてディレクトリは php.ini で指定していないのに、どこから出てきたのかがわかりません。
しばらく悩みましたが、phpinfo() の出力を見て、ようやく気がつきました。
Loaded Configuration File /etc/php/5.2/nsapi/php.ini
これまでは/etc/php/5.2/php.ini を読んでいたのが、バージョンアップ時に変わってしまっていたようです。NSAPI 用の php.ini ならスレッドセーフのモジュールを読むのは自然です。(NSAPI が現役なのかは知りませんが。自分で最後に NSAPI モジュールを書いたのは13年くらい前か。)
原因は分かれば修正は簡単で、/etc/php/5.2/nsapi/php.ini を以下のように修正して問題解決。
543c547 < extension_dir=/usr/php/5.2/zts-modules --- > extension_dir = "/usr/php/5.2/modules:/var/php/5.2/modules"]]>
前回(と言っても1年半前か) までで nginx と PHP の fast-cgi のビルドと設定が終わったので、OS の起動時に自動的に起動するようにサービスとして登録を行います。
OpenSolaris ではサービスの管理に SMF という仕組みを使用しています。SMF はサービスの依存関係を記述できたり、サービスの起動を監視して自動的に再起動してくれたりと、Linux などで使われている /etc/init.d の rc スクリプトに比べるとメリットがありますが、コマンドが独自だったり、自分で SMF にサービスを登録するには manifest と呼ばれる XML ファイルを書く必要があるので、慣れるまではハードルがあります。(この辺は Mac OS X の launchd と似ている。)
以下が、私が nginx を管理するために作成した nginx.xml です。
<?xml version='1.0'?> <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> <service_bundle type='manifest' name='export'> <service name='network/nginx' type='service' version='0'> <create_default_instance enabled='true'/> <single_instance/> <dependency name='fs' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/system/filesystem/local'/> </dependency> <dependency name='net' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/network/loopback'/> </dependency> <exec_method name='start' type='method' exec='/usr/local/sbin/nginx -c /usr/local/conf/nginx.conf' timeout_seconds='60'> <method_context working_directory='/usr/local/logs'> <method_credential user='root' group='root'/> <method_environment> <envvar name='PATH' value='/usr/bin:/bin:/usr/local/bin'/> </method_environment> </method_context> </exec_method> <exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'> <method_context/> </exec_method> </service> </service_bundle>
このファイルを以下のように SMF に登録します。
# svccfg -v import nginx.xml
同様に PHP の FastCGI のプロセスも SMF に登録します。
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <service_bundle type="manifest" name="php-fcgi"> <service name="network/php-fcgi" type="service" version="0"> <create_default_instance enabled="true"/> <single_instance/> <dependency name="net" grouping="require_all" restart_on="none" type="service"> <service_fmri value="svc:/network/loopback"/> </dependency> <exec_method name="start" type="method" exec="/usr/local/sbin/php-fcgi.sh" timeout_seconds="60"> <method_context working_directory="/usr/local/www"> <method_credential user="php" group="webservd" privileges="basic,net_privaddr"/> <!--method_credential user="root" group="root" /--> <method_environment> <envvar name="PATH" value="/usr/php/5.2/bin:/usr/local/sbin:/usr/bin:/bin" /> </method_environment> </method_context> </exec_method> <exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'> <method_context/> </exec_method> </service> </service_bundle>
この xml も同じように svccfg コマンドで登録します。
起動用の shell スクリプトはこちらのサイトのものを、ほぼそのまま使っています。
#!/bin/bash LC_ALL=ja_JP.UTF-8 #FastCGI Webserver path FCGI_WEB_SERVER_ADDRS="127.0.0.1" ## ABSOLUTE path to the PHP binary PHPFCGI="/usr/php/bin/php-cgi" ## tcp-port to bind on FCGIPORT="9000" ## IP to bind on FCGIADDR="127.0.0.1" ## number of PHP children to spawn PHP_FCGI_CHILDREN=5 ## number of request before php-process will be restarted PHP_FCGI_MAX_REQUESTS=1000 # allowed environment variables sperated by spaces ALLOWED_ENV="PATH" ## if this script is run as root switch to the following user USERID=webservd ################## no config below this line ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_CHILDREN" ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS" ALLOWED_ENV="$ALLOWED_ENV FCGI_WEB_SERVER_ADDRS" if test x$UID = x0; then EX="/bin/su -m -c \"$PHPFCGI -q -b $FCGIADDR:$FCGIPORT\" $USERID" else EX="$PHPFCGI -b $FCGIADDR:$FCGIPORT" fi echo $EX # copy the allowed environment variables E= for i in $ALLOWED_ENV; do E="$E $i=${!i}" done # clean environment and set up a new one nohup env - $E sh -c "$EX" &
サービスが SMF に登録できれば、svcadm コマンドで起動停止を切り替える事ができます。
# svcadm enable nginx # svcadm enable php-fastcgi
# svcadm disable nginx # svcadm disable php-fastcgi]]>
CVS(やSubversion)をバージョン管理システムに使っていた頃はリポジトリの情報を見るのにViewVCを使っていましたが、ViewVCはMercurialをサポートしていません。Mercurial にはウェブ用の管理画面(hgweb/hgwebdir)が付属しているので、別のツールを使うニーズが少ないんでしょうね。
Mercurial のリポジトリ毎に対応する Redmine のプロジェクトが存在するので、そちらを見ればおおよその事は分かるのですが、Redmineのリポジトリブラウザはブランチを意識して作られていないので不便といえば不便です。
hgwebの事は Mercurial への移行を検討していたときにも調べていたんですが、Django, flup, setuptools, ez_setup.py, easy_install, .. とPythonに不慣れな人間にはなじみのない単語が続々と出てきたので、ちょっと敬遠していましたが、ちょっと時間が取れたのでチャレンジしてみました。
hgwebdir のセットアップをする前に必要なソフトウェアのインストールを行います。環境は OpenSolaris 2009.06 で、可能な限り pkg を使ってインストールしていきます。インストールしたのは以下のパッケージです。
SUNWPython26 SUNWPython26-extra SUNWpython26-setuptools
OpenSolaris 2009.06 のパッケージ管理システムにも Mercurial はありますが、バージョンが 1.1.2 と古く、クライアントの環境と合わないので、最新バージョンを easy_install からインストールします。
$ pfexec easy_install Mercurial $ hg --version Mercurial Distributed SCM (version 1.4.2) Copyright (C) 2005-2009 Matt Mackall <mpm@selenic.com> and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
次に flup が必要だそうなのでインストールします。
$ pfexec easy_install flup
hgwebdir を FastCGI で動作させるのにはいろいろな方法があるらしいのですが、Python特有のやり方はよく分からないので、lighttpd の spawn-fcgiを使いました。インストールは以下の通り簡単です。
$ wget http://www.lighttpd.net/download/spawn-fcgi-1.6.3.tar.gz $ gzip -dc spawn-fcgi-1.6.3.tar.gz | tar xvf - $ cd pawn-fcgi-1.6.3 $ ./configure $ make $ pfexec make install
ここまででようやく下準備がおわりました。
hgwebdir.fcgi は /usr/demo/mercurial/hgwebdir.fcgi をコピーして使っています。
UTF-8 で表示するために、HGENCODING の設定を行う部分のコメントをはずしています。
os.environ["HGENCODING"] = "UTF-8"
hgweb.config は単純です。
[paths] / = /path/to/repos/*
これを以下のようなスクリプトで起動しています。
#!/bin/sh LANG=ja_JP.UTF-8 export LANG FCGI=/opt/local/bin/spawn-fcgi exec $FCGI -s /tmp/.fcgi_hgwebdir -G webserved -M 0660 ./hgwebdir.fcgi
nginx の設定ファイルは以下のようになりました。
初めて try_files を使ってみましたが、設定がとてもシンプルになりますね。
hgwebdir は PATH_INFO を利用してブラウズするリポジトリを探すようなので、その部分の置き換えにちょっと手を入れています。
server { listen 80; server_name hg.example.com; root /path/to/public; index index.html; access_log /var/log/nginx/hg-access.log main; location / { try_files $uri @hgweb; } location @hgweb { fastcgi_pass unix:/tmp/.fcgi_hgwebdir; fastcgi_read_timeout 5m; set $path_info ""; if ($fastcgi_script_name ~ "^/(.*)$") { set $path_info $1; } fastcgi_param PATH_INFO $path_info; } }]]>
nginx のバージョン 0.7 系が stable になっていたので、サーバソフトウェアのアップデートを行いました。(久しぶりのブログの更新は OpenSolaris 2009.06 について書こうと思ってたんですが、これはまた後で。。。)
インストールしたのは nginx 0.7.59 です。リリースのアナウンスが 25 May 2009 なので、2週間くらい前に出たばかりだったようです。 0.6系と0.7系の間の変更点についてまとまっている資料を探したのですが、見つかりませんでした。
Change Log を見るとかなりの修正箇所があるようですが、大きくまとめると以下の機能が増えているようです。
*) caching of proxied and FastCGI servers; *) "try_files" directive; *) the "location" and "server_name" directives support captures in regular expressions; *) XLST and image filters; *) a preliminary IPv6 support; *) nginx/Windows.
WindowsサポートとIPv6、あまり関係なさそう。。。
try_filesはファイルを探す順番を指定するディレクティブで、例えば「あるファイルが存在する場合はメンテナンス画面を表示する」ような場合、今までは if 文をいくつか書いて条件分岐させていたのをすっきりと記述することが出来るようです。設定例を見るといろいろな応用が出来るようです。
インストールはいつもの通り
./configure --with-http_stub_status_module --with-http_gzip_static_module --with-cc-opt='-O3' make make install
だけで大丈夫でした。
ただ、私の環境ではなぜか configure が途中で失敗していて、しばらくはまりました。結局は .bash_profile で環境変数 CC と CFLAGS を指定していたのが原因でした。nginx の configure スクリプトは autoconf で作られたものでは無いので、予想もつかないところが問題になるなぁ。
nginx 0.6 系で使用していた nginx.conf で起動させたところ、2点ほど問題がありました。
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
0.6系では上のような設定で問題ありませんでしたが、0.7 では以下の警告が出ます。
duplicate MIME type “text/html” in /etc/nginx/nginx.conf
text/html は暗黙的に設定されているようなので、以下のように修正。
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
WordPress のログインページを BASIC 認証をさせるために、以下のような設定をしていました。
location /wordpress/wp-login.php { auth_basic "secret"; auth_basic_user_file htpasswd; }
nginx 0.6 系では BASIC 認証後に wp-login.php が実行されていましたが、0.7系では BASIC認証はされるものの、PHPファイルが実行されずにソースファイルがそのまま転送されてきました。
どのように修正すべきか分からなかったので、以下のように fastcgi の設定を入れて ad hoc に修正しました。
location /wordpress/wp-login.php { auth_basic "secret"; auth_basic_user_file htpasswd; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; include fastcgi_params; }
こういうケースでは今後は try_files ディレクティブを使えって事なんでしょうね。
nginxからphpを利用するには、FastCGIを有効にしてphpをビルドしておく必要があります。
php-5.2.6 を以下のようにビルドしました。
./configure --with-curl=/usr --enable-fastcgi --enable-mbstring --enable-zend-multibyte --enable-mbregex --with-mysql --with-mcrypt --with-mhash --with-openssl --with-gd --enable-gd-native-ttf --enable-gd-jis-conv --with-jpeg-dir=/usr --with-xpm-dir=/usr --with-freetype-dir=/usr make make install
メールで記事を投稿する為に openssl と gd の関係のオプションを追加してます。
openssl は gmail に対して POP で接続する為に、gd はKtai Entryで画像を添付したメールを処理するのに必要でした。
FastCGIのプロセスを以下のように起動します。
/usr/local/bin/php-cgi -q -b 127.0.0.1:9000
127.0.0.1:9000 は FastCGI の接続を待ち受ける IPアドレスとポート番号です。
この値は環境に合わせて別の物に変更する事が可能です。
続いて nginx 側の設定ファイルを作成します。
前回の記事で基本的な設定は nginx.conf に書いてあるので、ここでは VirtualHost の設定だけを記述します。
phpをFastCGIで実行するのに最低限必要な設定はこれだけです。
server { listen 80; server_name bluegold.me blog.bluegold.me; root /var/www/blog; index index.php index.html index.htm; <p> location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www/blog/$fastcgi_script_name; include fastcgi_params; } }
127.0.0.1:9000 の部分は FastCGI のプロセスのオプションと同じ値を設定します。
]]>