自宅でルーターとして使っていた安物の無線LAN AP の調子が悪く、頻繁に落ちるようになったので、新しい物に買い替えました。
EAP-TLS の実験もしたかったので、今回は AirMac Extreme にしてみました。
AirMac Extreme はアップル製だけあって設定は簡単で、802.1X EAP-TLS で認証をさせても安定しているようです。それはいいのですが。。。
アップルの製品は設定が簡単でいいのですが、設定項目が少なく、アップルの想定している使い方からちょっとでも外れるとどうにも出来なくなる事があります。
今回も2点ほど困った点があったので、メモしておきます。
AirMac Extreme をルーターとして使用する場合、ローカル側の IPアドレスが 192.168.0.1 のように末尾が 1 に固定されていて、変更することができません。
ローカルのIPアドレスを設定できないネットワーク機器なんてあるはずないと思い、方法を探してみましたが、解決策は無いようでした。
うちのネットワークは、これまで 192.168.0.254 のように 254 で終わるアドレスをデフォルトゲートウェイにしていたので、このアドレスが変わると固定アドレスを持っているたくさんのサーバーたちの設定も変更する必要が出てきてめんどくさいんですよね。
しかたないので、常時起動している Linux に 254 のアドレスを割り当てて、ICMP redirect で正しいデフォルトゲートウェイのアドレスを通知するようにしました。(ついでにキャッシュ用のネームサーバーも立てました。)
最初は OpenSolaris に ICMP redirect を投げさせようとしたんですが、なぜか出来なかった。。。
他の人とデータのやり取りをする為に ftp サーバーを立てていますが、標準のポートで起動させておくと勝手にログインしてこようとする人たちがたくさんいます。パスワードとログの管理がめんどくさいので、これまではルーターで標準以外の別のポートから NAT させていました。
AirMac Extreme でも同様の設定をしてみたのですが、接続できません。
アップルのフォーラムでも同様に困っている人はたくさんいるのですが、やはり解決策は無いようでした。
いろいろと試してみた結果をまとめると
実験中に OpenSolaris で動かしている ftpサーバーのポートを変えようとしたが、inetadm ではポートを変更する方法がなかった。。。
しかたがないので、/etc/services を修正して対応。。。
Mac OS X 10.7 Lion で EAP を使う場合の設定方法がものすごくシンプルになりました。
どこかで見た事あるなぁ、と思ったら iOS と同じになったみたいです。
]]>WordPress はユーザ数が多いだけに、必要なものはたいていプラグインとして用意されている非常に使いやすいCMSだと思いますが、毎回動的にしかページを作れないという点にはちょっと不満を持っていました。
nginx や Vernish などのプロキシサーバを別に立ててキャッシュさせる方法を試そうと思っていたのですが、はまりポイントが多いらしく躊躇していました。そんな時に Really Static というプラグインを見つけたときから、今回の話は始まります。
Really Static プラグインは、ブログの記事の HTML を PHP の curl 関数でダウンロードして static フォルダの中に置いておき、それ以降は PHP で動的に HTML を作るのではなく、静的な HTML ファイルを返す、といった事をしてくれるプラグインです。ちょうど、Ruby on Rails のページキャッシュみたいなイメージですね。
インストールも設定も難しくなく、HTML のダウンロードも WP-cron で少しずつ行われるため、完全に WordPress 内に閉じた環境で実現できるすぐれたプラグインだと思いますが、(私にとっては)ひとつだけ大きな欠点がありました。
それは、Really Static プラグインがサイトの構造(URL)を変えてしまうことでした。
例えば、http://blog.bluegold.me/sample という URL の記事に対して、Really Static の導入後にアクセスすると http://blog.bluegold.me/static/sample.html に 301 redirect されてしまいます。
さらには他のページに書かれたリンクも静的ファイルの URL を直接さすように変更されてしまうので、一度導入してしまうと、後で使うのをやめるときに元に戻すのが難しくなってしまうのではないかと思いました。
最初は Really Static プラグインに手を入れて、リンクの URL を変更させないようにしようと思ったんですが、コードを読むと仕組みは意外と単純だったので、Wordpress に統合することを考えなければ、nginx の try_files だけで、似たようなことが出来ることに気がつきました。
nginx の try_files はリクエストを処理する際に実際のファイルを探す順番を記述する nginx に固有の設定項目で、Apache では mod_rewrite の複雑なルールを駆使して実現できるようなことをシンプルなルールで記述できるようにしたものです。
現在のこのブログの nginx.conf には以下のような記述がされています。
location { gzip_static on; # try_files /system/maintenance.html /static/$uri/index.html $uri /index.php?q=$uri&$args; try_files /system/maintenance.html /static/$uri/index.html$args $uri /index.php?q=$uri&$args; }
具体的な設定は WordPress のパーマリンクの設定で変わります。
$uri にはリクエストされた URL のパスの部分が入っています。リクエストを処理する際は以下を順番に調べていって、最初に見つかったものを返します。
※ 2011/01/30 追記 静的HTML化した投稿を表す /static/$url/index.html には $args も付けておかないと、プレビューが出来ませんでしたので修正しました。
この設定だけで静的なHTMLファイルの配信は出来るようになります。
あとはブログの各記事を HTML としてダウンロードするだけです。
$ wget -r --follow-tags=a http://blog.bluegold.me
(あくまでも例なので、自分のサイト意外にはやらないでくださいね。)
静的HTMLに変換しておくことで、このくらい速くなりました。(それぞれ3回試行)
平均 | 最速 | 最遅 | |
---|---|---|---|
WordPressのみ | 0.544s | 0.385s | 0.832s |
静的HTML | 0.086s | 0.084s | 0.088s |
実はこのブログは WPtouch プラグインも使っているので、このままでは iPhone 用の画面が表示されません。
この対処法はまた次回。
Mac OS X の Finder では先頭が ‘.'(ドット) で始まるファイル名や不可視属性の着いているファイルは表示されませんが、これらの隠しファイルを「開く/保存」ダイアログで表示するショートカットが Snow Leopard で追加されました。
「Command」キー+「Shift」キー+「 . 」(ピリオド)
これだけだと短すぎるので、不可視属性の設定方法もメモ
SetFile -a V filename
逆に不可視ファイルを表示させるには V を v にします。
]]>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"]]>
RSA 鍵で作成した証明書の場合、証明書内の公開鍵と秘密鍵は同一のモジュロ(Modulus)を持っているので、これを比較します。
openssl x509 -noout -modulus -in certificate_file.pem
openssl rsa -noout -modulus -in private_key.pem
openssl req -noout -modulus -in cert_request.pem
これらの実行結果として表示されるモジュロはかなり長くなるので、更に MD5 ダイジェストを計算した法が比較は簡単になります。
openssl x509 -noout -modulus -in certificate_file.pem | openssl md5 openssl rsa -noout -modulus -in private_key.pem | openssl md5 openssl req -noout -modulus -in cert_request.pem | openssl md5]]>
URLの切替には自作のプラグインを使っています。記事にした当時は stylesheet_uri と template_directory_uri の置き換えをするだけのものでしたが、今は WP_PLUGIN_URL も置換えて、プラグインが追加するスタイルや画像も CloudFront から配信しています。
ここまではわりと簡単に実装できていたのですが、メディアライブラリ(uploads ディレクトリ)に置いた画像ファイルは記事の中身を書き換える必要があるため、なかなか手を出せずに1年くらい放置していましたが、最近、WordPress Amazon S3 Plugin というものがあるのを知り、さっそく試してみました。
このプラグインのセットアップは簡単で、plugins ディレクトリに置いて有効化したあとで、Amazon S3 の認証情報と画像を置くバケツ名を指定するだけです。
設定が完了した後はしばらく待っていると、wp-cron の仕組みを使い、誰かがアクセスしてきた時にバックグラウンドで画像ファイルを Amazon S3 にアップロードしていきます。(アップロードする画像はキューに入れられ、順番に処理されていくようです。)
画像ファイル毎に Amazon S3 へのアップロード状況が記録され、正常に保存された画像ファイルの URL は次回に表示される時から Amazon S3 の URL に置換えられます。
非常に簡単に使えて効果の高いプラグインなのですが、このブログの環境ではいくつか問題がありました。
このプラグインでは画像ファイルへの URL が http:// から始まる完全 URL で書かれている事を想定しているのですが、当ブログでは、ある記事では完全 URL、別の記事ではルート相対URL、という感じで記事ごとに画像の URL の書き方がバラバラでした。
このため、画像への URL を探す正規表現にマッチしない画像がたくさん出てきてしまいました。
メディアライブラリから画像を「投稿に挿入」していれば、完全URLで書かれるので普通に使っていれば問題は無かったはずなんですが。。。
しかたがないので、これはプラグインのソースに手を入れてルート相対URLでも書き換えられるように修正しました。
このプラグインは画像ファイルのURLを http://>バケツ名<.s3.amazonaws.com という場所に変更するのですが、私のデータは Amazon S3 の中でも北米東海岸のサーバに置かれているため、ファイルの送信にちょっと時間がかかります。どうせなら国内の CloudFront のサーバから配信したいので、以下のようにソースを修正しました。wp-cdn.bluegold.me はヂストリビューションに付けた CNAME です。
*** 212,218 **** if (file_exists ( $mediaInfo [ 'cache' ] ) === TRUE) { $fileContents = file_get_contents ( $mediaInfo [ 'cache' ] ); if ($fileContents == 'done') { ! $cdnUrl = "http://{$this->s3BucketName}.s3.amazonaws.com/" . $mediaInfo [ 'path' ]; $the_content = str_replace ( $mediaInfo [ 'url' ], $cdnUrl, $the_content ); } } else { --- 214,221 ---- if (file_exists ( $mediaInfo [ 'cache' ] ) === TRUE) { $fileContents = file_get_contents ( $mediaInfo [ 'cache' ] ); if ($fileContents == 'done') { ! // $cdnUrl = "http://{$this->s3BucketName}.s3.amazonaws.com/" . $mediaInfo [ 'path' ]; ! $cdnUrl = "http://wp-cdn.bluegold.me/" . $mediaInfo [ 'path' ]; $the_content = str_replace ( $mediaInfo [ 'url' ], $cdnUrl, $the_content ); } } else {
このプラグインは非常に簡単に使えるので、Amazon S3 のアカウントを持っている人にはお勧めできますね。
]]>前回(と言っても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]]>
VeriSign のAuthenticode用の証明書を使っています。 これは .exe や .cab ファイルなどにコードサイニングを行うためのマイクロソフトの仕様に沿った証明書で、昔は ActiveX 専用なイメージでしたが、最近は IE がファイルをダウンロードする時にも検証されるので、それなりに重要なものだったりします。
基本的に証明書の有効性は証明書自身の有効期間の間しか確認できません。(その為の有効期間なわけですから当然ですが) しかし、例えばインストーラを作成してウェブに公開するような時に、コードサイン用証明書の有効期限が切れて更新するたびに、公開している全てのファイルに対して署名をやり直すのは大変です。
こういった事にならないように、通常は署名時にタイムスタンプを付けておきます。タイムスタンプは「あるファイルがタイムスタンプをつけた時点で存在し、タイムスタンプをつけてからは変更されていない」事を証明するためのサービスで、デジタル署名にタイムスタンプがついている場合は、署名した証明書の有効期限が過ぎた後も、有効性を確認することができます。
ただ、タイムスタンプ自身も電子署名の一種なので、証明書の有効期限が存在します。この有効期限を過ぎるとタイムスタンプの有効性が確認できなくなるので、有効期間の残りが少なくなってくると意味がなくなってしまいます。
ようやく本題。
VeriSign でも http://timestamp.verisign.com/scripts/timstamp.dll というURLでタイムスタンプサーバを 公開していているのですが、そこでタイムスタンプの署名に使われる証明書の有効期限は以下のようになっています。
真ん中の画像の「VeriSign Time Stamping Services Signer – G2」がタイムスタンプ用の証明書で、有効期限は 2007/06/05 から 2012/06/15 までとなっています。
これを書いているのが、2010/07/31 なので、もう残りが2年ない。。。
有効期限の残りが2年を切る前に流石に更新されるか、少なくともロードマップのアナウンスがあるかと思ってたんですが、何もなかったんですよね。
元から有効期限が5年しかないので、毎年更新するくらいでちょうどいいと思うんですが。
]]>ActiveX や ToolBar(Browser Object) のデバッグを行うさいは、IE をデバッギー(debugee)としてVisual Studio からアタッチするのですが、今日久しぶりにやってみたら設定したブレークポイントで止まってくれません。
Visual Studio の設定ミスかと、しばらく試行錯誤しているうちに iexplore.exe のプロセスが複数いることに気がつきました。そこで、ようやく IE8 からタブごとに別プロセスで実行されることを思い出しました。
「じゃあ、自分がデバッグしたいプロセスを探してアタッチすれば。。。」と思ったのですが、毎回そんなことをやるのはさすがにめんどくさいので、Google先生に聞いてみました。
で、このサイトで解決策を発見。
IE8 がタブごとに独立したプロセスを生成しないようにレジストリの値を変更します。
Windowsネタを書くのははじめてなのか。。。
]]>sudo ifconfig en0 alias 192.168.0.1 255.255.255.0
sudo ifconfig en0 -alias 192.168.0.1
ついでに Linux と OpenSolari での設定方法もメモ。
# /sbin/ifconfig eth0:1 192.168.0.1/24
# /sbin/ifconfig eth0:1 down
pfexec ifconfig gbe0:1 plumb pfexec ifconfig gbe0:1 192.168.0.5 netmask 255.255.255.0 up
pfexec ifconfig gbe0:1 down pfexec ifconfig gbe0:1 unplumb
Snow Leopard のやり方のほうが、何個目のエイリアスなのかを考えなくてもいいので楽なのかなぁ。
エイリアス単位でインターフェースの UP/DOWN はできなそうだけど。
正確には Redmine が原因なのかどうかは判明していませんが、OpenSolaris 上に構築した Redmine が起動後何時間かすると500 Internal Errorを返すようになってしまいました。
Redmine は以下のような環境で動かしています。
Ruby は /opt/sunstudio12.1/bin/cc(Sun Studio Express 12)でビルドしています。
OpenSolaris に付属の /usr/bin/ruby を使っていた時には問題なく動作していたんですが、Redmine 0.9.3 にバージョナップした所、致命的な問題が発生したため、Ruby を自分でビルドするように変更していました。
落ちているの気がついたら手動で再起動をしていたのですが、さすがにメンドウになってきたのでスクリプトを書きました。
#!/bin/sh while `/bin/true` do http_code=`curl --insecure -w "%{http_code}" -s -o /dev/null https://redmine/login` ts=`date +"%Y/%m/%d %H:%M:%S"` if [ $http_code -eq 200 ]; then echo $ts OK sleep 300 continue fi cd /var/www/redmine pid=`cat tmp/pids/unicorn.pid` kill -USR2 $pid sleep 5 kill $pid echo $ts unicorn $pid reloaded. done exit 0
手順としては、5分おきに curl で HTTP のステータスコードのみを受け取り、200 OKが帰ってこない場合は再起動、という流れです。
Unicorn は SIGUSR2 を送ると自分自身を fork() してから終了するはずなのですが、終了せずに残るので子プロセスの起動を待ってから SIGTERM を送っています。
とりあえずは、これで気にはならなくなりましたが。。。
そのうち、God あたりに切り替えよう。
Xenのディスクイメージファイルは以下のように固定ディスクをそのままファイルに移したような構造になっています。
# file test.img test.img: x86 boot sector; partition 1: ID=0x83, active, starthead 1, startsector 63, 208782 sectors; partition 2: ID=0x82, starthead 0, startsector 208845, 2104515 sectors; partition 3: ID=0x83, starthead 0, startsector 2313360, 18651465 sectors, code offset 0x48
なので、基本的にはループバック・デバイスとしてマウントする事が可能です。
ただし、ディスクイメージはパーティションに区切ってあると思いますので、その分にひと手間ひつようです。
基本的な作業の流れは以下のとおり。
losetup -fコマンドで空いているループバック・デバイスを探して、そのデバイスにイメージファイルを割り当てます。
# losetup -f /dev/loop0 # losetup /dev/loop0 /var/lib/xen/images/test.img # losetup -a /dev/loop0: [0900]:153944114 (/var/lib/xen/images/test.img)
ループバック・デバイスに割り当てた仮想ディスクにパーティションの状況をfdiskコマンドで調べます。
# fdisk /dev/loop0 このディスクのシリンダ数は 1305 に設定されています。 間違いではないのですが、1024 を超えているため、以下の場合 に問題を生じうる事を確認しましょう: 1) ブート時に実行するソフトウェア (例. バージョンが古い LILO) 2) 別の OS のブートやパーティション作成ソフト (例. DOS FDISK, OS/2 FDISK) コマンド (m でヘルプ): p Disk /dev/loop0: 10.7 GB, 10737418240 bytes 255 heads, 63 sectors/track, 1305 cylinders Units = シリンダ数 of 16065 * 512 = 8225280 bytes デバイス Boot Start End Blocks Id System /dev/loop0p1 * 1 13 104391 83 Linux /dev/loop0p2 14 144 1052257+ 82 Linux swap / Solaris /dev/loop0p3 145 1305 9325732+ 83 Linux コマンド (m でヘルプ): q
3つのパーティションが存在することが確認できます。
kpartx -aでそれぞれのパーティションをデバイスファイルに割り当てます。
/dev/mapperディレクトリの下に新たなデバイスファイルが作成されます。
# kpartx -a /dev/loop0 # ls -l /dev/mapper/ 合計 0 crw------- 1 root root 10, 62 2月 24 00:07 control brw-r----- 1 root disk 253, 0 3月 5 22:07 loop0p1 brw-r----- 1 root disk 253, 1 3月 5 22:07 loop0p2 brw-r----- 1 root disk 253, 2 3月 5 22:07 loop0p3
仮想ディスクでLVMを使っているとここから先がめんどくさいので、私はXenの仮想ディスクではLVMは使いません。
あとは通常のディスクと同じようにマウントするだけです。
# mount -t ext3 /dev/mapper/loop0p1 /mnt/tmp # ls -l /mnt/tmp -rw-r--r-- 1 root root 952782 11月 4 08:46 System.map-2.6.18-164.6.1.el5xen drwxr-xr-x 2 root root 1024 11月 9 15:51 grub -rw------- 1 root root 2383144 11月 9 15:51 initrd-2.6.18-164.6.1.el5xen.img drwx------ 2 root root 12288 6月 17 2009 lost+found -rw-r--r-- 1 root root 80032 3月 13 2009 message -rw-r--r-- 1 root root 107413 11月 4 08:47 symvers-2.6.18-164.6.1.el5xen.gz -rwxr-xr-x 1 root root 817164 11月 4 09:53 xen-syms-2.6.18-164.6.1.el5 -rw-r--r-- 1 root root 375762 11月 4 06:11 xen.gz-2.6.18-164.6.1.el5
必要なくなった仮想ディスクを開放するには、逆の手順で行います。
# umount /mnt/tmp # kpartx -d /dev/loop0 # ls -l /dev/mapper/ 合計 0 crw------- 1 root root 10, 62 2月 24 00:07 control # losetup -d /dev/loop0 # losetup -a # losetup -f /dev/loop0]]>
私の構築したステージング用のサーバにデザイナーさんの作ったコンテンツを置いてもらう必要があったので、「sftp でいいですか?」と聞いたら「ftpの方がいい」と言われたので、急遽 ftp サーバの用意をすることになりました。
軽く「いいよ」と答えたものの、自分で最後に ftpd をたてたのはもう10年近く前のことで何も覚えてません。
Solaris なのでSMFで管理されているftpdがあるだろうと思い、試してみると
$ pfexec svcadm enable ftp $ svcs -l ftp fmri svc:/network/ftp:default name FTP server 有効 true 状態 online next_state none state_time Tue Feb 23 02:02:15 2010 リスタータ svc:/network/inetd:default contract_id
無事に起動できました。簡単簡単。
念のため、ファイアウォール越しに ftp コマンドで接続テストを行い、passive mode が on でも off でも問題がなかったので、使ってもらいました。
しかし、しばらくすると「FTPサーバに接続は出来たけど、ファイルが何も表示されない」との報告が。。。
使っている ftp のクライアントソフトはFFFTPだという事なので、同じトラブルにあっている人がいるだろうと思いGoogleに聞いてみたところ、このページで原因と思われる記述を発見しました。
「タイムスタンプに含まれる日本語文字列の処理の問題」
ftpコマンドで接続して確認すると、ファイルの更新日付が確かに日本語で返ってきています。これなら in.ftpd のロケールを変えてあげれば問題は解決しそうです。
また、Googleに聞いてみるとこのページに回答がそのまま書いてありました。
SMF なので svccfg を使うのかと思ったら、in.ftpd は inetd に管理されているので、inetadmというコマンドを使うんですね。初めて知った。
以下のコマンドで、FFFTPでも正常にファイル一覧が表示されるようになりました。
$ pfexec inetadm -m ftp inherit_env=FALSE $ pfexec svcadm restart ftp]]>
TLSやSSLを使ったウェブサーバーでは一般的には仮想ホストは使えない、という事になっています(何事にも例外はありますが。)仮想ホストは HTTP のリクエストヘッダの Host フィールドの値を元に振り分けられますが,HTTPのリクエストを出すよりも手前の TLS/SSL のハンドシェイク時にサーバ証明書の検証が行われるので,クライアントが接続しようとしているホスト名とサーバ証明書のホスト名が異なってしまい,不正な証明書と表示されてしまいます。
SNIは接続しようとしているホスト名を、クライアントからサーバに伝えるための仕様です。(ホスト名はハンドシェイク前に伝えないと行けないので、平文で送られる事になりますが。。。)これ自体は素晴らしいのですが,Windows XP の IE がサポートしていないので今ひとつ広まっていません。
まずは SNI を使わないで仮想ホストを設定する場合の例です。
ssl_certificate server_cert.pem; ssl_certificate_key server_cer.key; server { port 443; ssl on; server_name host1.example.com; } server { port 443; ssl on; server_name host2.example.co.jp; }
サーバ証明書は1枚しか指定できないので,server_cert.pem には host1.example.com と host2.exacmple.co.jp の双方が記述されている必要があります。ホストが同一のドメインに存在する場合はワイルドカード証明書を使う方法もありますが,例のようにドメインが異なる場合は双方のホスト名をCNもしくはsubjectAltNameに記述します。この方法では仮想ホストが増える場合は証明書を発行し直す必要があります。
次に SNI を使う場合の例です。
server { port 443; ssl on; ssl_certificate host1.example.com.pem; ssl_certificate_key host1.example.com.key; server_name host1.example.com; } server { port 443; ssl on; server_name host2.example.co.jp; ssl_certificate host2.example.co.jp.pem; ssl_certificate_key host2.example.co.jp.key; }
仮想ホスト毎に証明書が指定する事ができるようになります。
実際に SNI をサポートしている Firefox などのブラウザでアクセスすると、それぞれ異なる証明書を持つ事が確認できます。
ただ、現在の nginx に固有の問題かもしれませんが,仮想ホスト毎にクライアント証明書による認証の有無を切り替えるのは出来ないみたいです。ssl_verify_client off;な設定の仮想ホストが1つでもあると,クライアント認証を行う仮想ホストに対してもクライアント証明書が送られません。
クライアント認証が必要ない仮想ホストに対してもssl_verify_client optional;を指定すると大丈夫なようですが。(Nginx の Wikiの説明ではoptional ではなく、askになっているので注意が必要です。)
]]>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.65)がリリースされていたので,バージョンアップしてみました。
しばらく前に見つかっていたSSLの脆弱製の実験をやろうと、久しぶりに SSL を有効にしたバイナリを作ろうとしたのですが,オプションの設定の仕方を忘れていて苦労しました。また、忘れても大丈夫なようにメモ。
OpenSolaris 2009.06 に含まれるOpenSSLは 0.9.8a と古いので、現時点での最新バージョンであるopenssl-0.9.8lをダウンロードしてきて使いました。今回はSNI(Server Name Indication)を有効にしたいのでenable-tlsextオプションを渡しています。
./config --prefix=/usr/local no-shared enable-tlsext make pfexec make install
これだけでもビルドは出来るのですが,OpenSolaris 2009.06 のデフォルトの GCC 3.2.3 ではなく新しい /usr/bin/gcc-4.3.2 を使いたいので,少し手を入れています。
export CC=/usr/bin/gcc-4.3.2 export CFLAGS='-DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -march=native -O3 -Wall -DL_ENDIAN -DMD32_REG_T=int -DOPENSSL_BN_ASM_MONT -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM' ./Configure --prefix=/usr/local no-shared enable-tlsext solaris64-x86_64-gcc make pfexec make install
export CC=/usr/bin/gcc-4.3.2した後にconfigスクリプトを実行すると,solaris64-x86_64-gcc-4.3.2 みたいな os:compiler になってエラーになってしまうんですよね。回避方法を探すのに手間取ってしまいました。
次に nginx のビルドですが,普通に configure を実行すると 32bit のバイナリが出来てしまいますので、gcc に渡すオプションも configure に渡します。
./configure --prefix=/usr/local --with-http_stub_status_module --with-http_gzip_static_module --with-http_ssl_module --with-cc=/usr/bin/gcc-4.3.2 --with-cc-opt='-m64 -march=native -O3 -I/usr/local/include ' --with-cpu-opt=amd64 --with-ld-opt='-m64 -L/usr/local/lib -L/usr/lib/amd64' make pfexec make install
ビルドした内容を確認
$ file /usr/local/sbin/nginx /usr/local/sbin/nginx: ELF 64-bit LSB executable AMD64 Version 1, dynamically linked, stripped $ /usr/local/sbin/nginx -V nginx version: nginx/0.7.65 built by gcc 4.3.2 (GCC) TLS SNI support enabled configure arguments: --prefix=/opt/local --with-http_stub_status_module --with-http_gzip_static_module --with-http_ssl_module --with-cc=/usr/bin/gcc-4.3.2 --with-cc-opt='-m64 -march=native -O3 -I/usr/local/include' --with-cpu-opt=amd64 --with-ld-opt='-m64 -L/usr/local/lib -L/usr/lib/amd64'
SNIも有効になっています
]]>3ヶ月ほど前に、10年以上使い続けたCVSからMercurialにソース管理を移行しました。(Subversion は手になじまなかった。)
移行して不便に感じるのはViewVCが使えなくなった事くらいで、普段はあまり違いは感じていませんが、1つだけ直感的にやり方が分からなくて困る事があります。
ワーキングディレクトリで作業中に誤って必要なファイルを削除してしまった場合、例えば
$ ls -l total 8 -rw-r--r-- 1 user staff 1345 Jan 16 22:33 Makefile drwxr-xr-x 5 user staff 170 Jan 16 22:45 help/ drwxr-xr-x 5 user staff 170 Jan 16 22:33 tutorial/ $ rm Makefile
としてしまった場合、必要なファイルが存在しない事は hg status コマンドで調べる事ができます。
$ hg status ! Makefile
CVS(やSubversion)では、誤って削除したファイルはcvs update(svn up)で元に戻すことができますが、Mercurial ではそうはいきません。
$ hg update ファイル状態: 更新数 0、マージ数 0、削除数 0、衝突未解決数 0 $ ls -l total 0 drwxr-xr-x 5 user staff 170 Jan 16 22:45 help/ drwxr-xr-x 5 user staff 170 Jan 16 22:33 tutorial/
このように削除されたファイルはそのままです。
Mercurial では update コマンドはワーキングディレクトリのリビジョンを変更するコマンドなので、この動きで正しいらしいのですが、CVS等から乗り換えてくるとちょっとビックリします。
このような場合はhg revertを使うのが正しいらしいです。
$ hg revert Makefile $ ls -l total 8 -rw-r--r-- 1 user staff 1345 Feb 2 02:41 Makefile drwxr-xr-x 5 user staff 170 Jan 16 22:45 help/ drwxr-xr-x 5 user staff 170 Jan 16 22:33 tutorial/]]>
WireSharkを使ってダンプを解析するためのキャプチャファイルをtcpdumpで保存するためのオプションを毎回忘れてしまうのでメモ。
tcpdump -n -i en0 -s 0 -w dumpfile.cap [filter]
tcpdump -w filenameだけでも、キャプチャファイルは作れるが、デフォルトではキャプチャ用のバッファ(snaplen)が 68バイトと小さく(TCP のヘッダー分のサイズらしい)、あふれたデータを取りこぼしてしまいます。tcpdump で見ている分には必要の無いデータですが、WireShark で「Follow TCP Stream」を見ようとした時に壊れていたりします。
そこでオプション ‘-s’ を指定して snaplen のサイズを大きく設定しています。(0は無制限、と言っても65535バイトくらいしか見た事ない)
(Open)Solarisの場合は悩む事無く、以下のように普通にファイルに保存するだけで大丈夫です。
snoop -r -d bge0 -o dumpfile.cap [filter]]]>
仕事のほうも、しばらくは自宅で開発作業を行うので、今までよりはブログに時間をかけられるんじゃないかなぁ。
自宅に仕事の環境を整えるために、年末年始は4台のPC(PCサーバ2台を含む)のセットアップを行っていました。4台といっても中身は Xen, Solaris Zone, VirtualBox で仮想化してるので時間はかかりました。
OpenSolaris でファイルサーバを作ったので、MacBook の開発環境のバックアップも定期的にそちらに残そうとcrontab -eで編集して保存したところ、意外なエラーが帰ってきました。
crontab: temp file must be edited in place
これまでも Mac で crontab の編集は行っていましたが、エラーになったのは初めてです。
メッセージからすると、vi で編集後のファイルの i-node が変わっているのが原因っぽいですが、.vimrc はもう3年くらいずっと使っているもので大きく変えたりはしていません。Google に聞いてみると以下の設定を追加すれば大丈夫だとの記述を発見しました。
set nowritebackup
が、私の環境ではこの方法ではダメでした。
次に見つけたこのサイトを参考にしたところ、crontab の編集ができるようになりました。
set backupskip=/tmp/*,/private/tmp/*
/private/tmp があるので、この人も Mac を使っているんでしょうね。
]]>今回の秋の連休は有休も使って9連休にしていました。
休み明けのボケた頭では仕事にならないので、午前中は開発用サーバたちのパッケージのアップデートをしていたところ、その中の1つにログインできませんでした。
そのホストは OpenSolaris 2009.06 の中に立てた Linux Branded Zone(BrandZ と書いた方がいいのかな)にインストールした CentOS3 でした。Solaris の Zone なので、ホストOS の方からは自由に Linux のファイルシステムに入っていけます。中のファイルを調べたところ、ログファイルの1つが46GB以上に肥大化してしまってディスクの残り容量が無くなってしまっているのが原因のようでした。
これなら、巨大化したログファイルを削除すれば問題解決だな、と軽い気持ちでrm ログファイル を実行したところ、意外な結果が戻ってきました。
cannot delete file: no space left on device.
ディスクに空き領域が無いからファイルを消したいのに、空き領域が無いからファイルを消せないと言われても。。。
ファイルシステムが壊れているのかと zpool scrub を実行してもエラーは無し。
Google 先生に質問してみたところ、zfs の既知のバグのようでした。曰く、ディスクの残り容量が無くなるとスナップショットが存在するファイルは削除できない。スナップショットの無いファイルを消して空き領域を作るか、スナップショットを削除すればよいようです。
が、zfs は使っているもののスナップショットなんて取ったことはありません。
不思議に思い zfs list -t snapshotを実行したところ、以下のように大量のスナップショットが存在していました。
rpool/ROOT/OpenSolaris-200906-090928@2009-07-10-00:41:02 17.4M - 2.85G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-10-17:54 39.5K - 6.93G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:weekly-2009-07-10-17:54 40K - 6.93G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:monthly-2009-07-10-17:54 1.11M - 6.93G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-11-00:00 3.67M - 6.94G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-12-00:00 2.86M - 7.14G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-13-00:00 5.29M - 7.14G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-14-00:00 21.1M - 7.26G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:weekly-2009-07-15-00:00 1.29M - 7.26G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-16-00:00 528K - 7.26G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-17-00:00 3.73M - 7.26G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-18-00:00 1.67M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-19-00:00 1.05M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-20-00:00 1.08M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-21-00:00 1.22M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:weekly-2009-07-22-00:00 1.35M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-23-00:00 1.35M - 7.35G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-24-00:00 5.91M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-25-00:00 5.93M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-26-00:00 5.87M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-27-00:00 6.60M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:daily-2009-07-28-00:00 6.42M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-11:00 1.73M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-12:00 1.71M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-13:00 1.93M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-14:00 1.88M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-15:00 1.79M - 7.40G - rpool/ROOT/OpenSolaris-200906-090928@zfs-auto-snap:hourly-2009-07-28-16:00 1.26M - 7.40G - ...
犯人(?)は zfs の自動スナップショット機能でした。たしかにインストール直後に試しにタイムスライダーを有効にしたことがありましたが、こんな事になるとは。
大量のスナップショットを削除するようにシェルスクリプトを作成して問題は解決しました。ただ、ググっている時に「rpool の容量がなくなるとリブートもできなくなる」のような話もあったので、タイムスライダー(自動スナップショット)はちょっと恐くて使えないなぁ。
]]>今月の頭にお客さんに収めたサーバ機のハードディスクが1週間で壊れたので、急遽ディスクのリプレースに行ってきました。今回のシステムは Linux の Software RAID で 2 本のディスクを使用して RAID1 を組んでいたのでデータ自体は無事だったのですが、手を離れたと思った瞬間のトラブルは心臓に悪いですね。
めったに行わない作業なので、自分用にメモ。
mdadm -Es > /etc/mdadm.conf
mdadm --assemble --scan
mdadm --manage /dev/md0 --fail /dev/sdb1 mdadm --manage /dev/md0 --remove /dev/sdb1 mdadm --manage /dev/md1 --fail /dev/sdb2 mdadm --manage /dev/md1 --remove /dev/sdb2
mdadm --manage /dev/md0 --add /dev/sdb1 mdadm --manage /dev/md1 --add /dev/sdb2
cat /proc/mdstat
リビルドが終わるまでの6時間を客先で待ち続けるのは辛かった。。。
]]>プログラムの移行自体は1週間ほどで完了したのですが、テストをしていてタイムゾーン関連の問題に遭遇しました。
データベースに有効期限を表すフィールドがあるのですが、1時間前から1時間後まで有効なレコードを作成して、現在が有効期間内かどうかを調べるテストが失敗したので問題に気がつきました。
Rails 2.x ではタイムゾーンが導入されたのは知っていたので、下のように設定を行っていました。
config.time_zone = 'Tokyo' config.active_record.default_timezone = 'Tokyo'
しかし、ログを見ていると JST と UTC とタイムゾーンが混ざっているようだったので、単純なアプリを作成して調べてみました。すると、以下のような結果に
c = Sample.find(:first) >> c[:created_at] => Mon, 24 Aug 2009 17:09:49 +0000 >> c.created_at => Tue, 25 Aug 2009 02:09:49 JST +09:00 >> c[:created_at].class => DateTime >> c.created_at.class => ActiveSupport::TimeWithZone
同じフィールドでも [] メソッドでデータを取得するのと、フィールド名を指定して取得するので、クラスもタイムゾーンも異なるんですね。ちょっとビックリしました。
どこかにタイムゾーンを意識しないコードがあって、この2つを混同してしまってるんだろうな。
調べるのはメンドクサイな。
新しい DVD で再インストールしたところ、それまで起動できていなかった Mail, iPhoto, QuickSilver などは正常に使えるようになりました。普段使っているアプリに関しては(いくつか対応待ちのものがあるものの)移行は問題ないかと思っていましたが、昨日FreeMindが動かないのに気がつきました。仕事の議事録等は FreeMind で書くのが習慣となっていたので、このアプリが動かないとけっこう困ります。
動かないというのは正確ではなくて、実際には以下のようなダイアログが出てきました。
インターネットに接続している状態では、下のように Rosetta のインストールを促すようです。
なので、Rosetta をインストールしてしまえば解決なのですが、せっかく Snow Leopard に移行したんだから PowerPC のバイナリの無い環境にしたいので、解決方法を調べてみました。
エラーダイアログにある通り、問題は JavaApplicationStub が Universal Binary になっていない点にあります。JavaApplicationStub は文字通り Java で書かれたアプリケーションを Mac OS X のネイティブアプリのように見せるためのスタブとなる実行ファイルです。FreeMind.app の中から JavaApplicationStub を探して調べると、以下のようになっていました。
$ file FreeMind.app/Contents/MacOS/JavaApplicationStub FreeMind.app/Contents/MacOS/JavaApplicationStub: Mach-O executable ppc
やはり、ppc のバイナリしか入っていません。
Universal Binary な JavaApplicationStub も存在するはずなので、HDD の中を調べたところ以下の場所にありました。
$ file /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub: Mach-O universal binary with 3 architectures /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub (for architecture x86_64): Mach-O 64-bit executable x86_64 /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub (for architecture i386): Mach-O executable i386 /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub (for architecture ppc7400): Mach-O executable ppc
このファイルで FreeMind.app/Contents/MacOS/JavaApplicationStub を上書きしたところ、Rosetta 無しで起動するようになりました。
]]>今までは新しいバージョンがでる度に Mac を買い替えていたので、OS のアップグレードは初めてですが、インストールは何回か行った事があるので、それほど心配はしていませんでした。
OSのアップグレードなので、何があっても大丈夫なように Time Machine でバックアップを取ります。それから SIMBL や MenuMeters などの怪しそうなソフトを止めてから、Snow Leopard の DVD を挿入してインストールを開始しました。
インストールが始まって「残り45分」と表示されたので、本でも呼んで時間をつぶしてようと思ったのですが、2分ほどでエラーが表示されて止まりました。
メッセージは以下の通りです。
install DVDが読み込めませんでした。 注意してディスクを清掃してから、もう一度インストールしてみてください。
DVDを取り出して見ても(新品なんだから当然だが)汚れなんかは付いていない。再度インストールを試してみても、やはりエラーで終了。DVDドライブの調子が悪いのかと別のDVDを入れてみてみても問題なし。
DVDから起動してみたら何か変わるかと思い、インストールログを表示させながら試したところ、何個かの pkg ファイルのコピーに失敗しているのが分かりました。何回か同じ手順でやってみたところ、エラーになるファイルは毎回異なっているようでした。
なら、プリンタドライバや言語等のパッケージを選択せずに、可能な限り少ないパッケージ数でインストールすれば大丈夫かも、と考えやってみたところ、無事にインストールが完了しました。
この時点で夜中の2時を回っていたので、そのまま寝てしまいました。
Google先生で調べてみると、同じような問題は「ファミリーパック問題」として、たくさん報告されているようです。うちはファミリーパックではなくて、ふつうのパッケージでしたが。私と同じようにパッケージ数を絞ってインストールに成功している人も多いようです。
「インストールに苦労しても、使えればいいや」と思っていたのですが、問題がたくさん見つかりました。やはり正常にはインストールできていなかったようです。今のところ気がついている問題点は
くらいかな。
いくつかのアプリが起動しない原因は同じで、DAVKit.framework の読み込みに失敗して起動できない。
実際のエラーメッセージは以下の通り。
Dyld Error Message: Library not loaded: /System/Library/PrivateFrameworks/DAVKit.framework/Versions/A/DAVKit Referenced from: /System/Library/Frameworks/CalendarStore.framework/Versions/A/CalendarStore Reason: image not found
たしかに、この場所にはファイルが存在していないです。
CalendarStore とも書いてあるので、iCal の CalDAV 関連にフレームワークなのかな、と想像しています。iCal が丸ごと消えているので、このパッケージのインストールに失敗したんでしょう。
DVD から iCal.pkg を取り出して展開して個別にファイルを置いてあげれば大丈夫かと考えてみましたが、iCal.pkg の読み取りはエラーになってしまいました。
月曜日にまたアップルストアに行って交換してくるしか無いかなぁ。
]]>「政府機関及び金融機関のSSLサーバ暗号設定に関する調査結果について」という講演で興味深い調査結果が発表されていました。
https でサービスを提供している政府系や金融系のWebサーバーに関して、「サポートしている暗号アルゴリズム」と「実際に使用される暗号アルゴリズム」を調査したとの事ですが、ちょっと驚く結果になっていました。
曰く、調査したWebサーバのうち7割以上が新しいアルゴリズムである AES256-SHA をサポートしていますが、XP 上の IE7 では9割弱のサーバに対して比較的古くて問題の見つかっている RC4-MD5 で接続してしまうそうです。Firefox では AES256-SHA が最も多く、Vista の IE7 では AES128-SHA が最も多い結果となっていました。(Vistaでの結果も謎で AES256 が有効でも AES128 を優先して使う。)
SSL(TLS)では、サーバとクライアントがそれぞれ自分がサポートしている暗号アルゴリズムのリストを相手に示して、お互いにサポートしているアルゴリズムの中から実際に使用するものを決定します。このネゴシエーションでは「互いにサポートするアルゴリズムのうち最も暗号強度の高いアルゴリズム」が選択されるものだとばかり思っていたので、実際にはアルゴリズムの優先順位は暗号の強度とは無関係に決まっているみたいです。(IE の場合。Firefox では暗号強度の高い順になっている。)
Windows XP 用の CNG を用意しなかったマイクロソフトの判断は、今となっては間違っていたって事なんでしょうね。(2010年問題はネットブックには影響しないからいいのかな。)
もう一つ驚いたのが、SSL2.0 をサポートするサーバの数で、金融系では3割程度ですが(それでも予想よりはずっと多い)、政府系では6割程度がまだサポートしている、と。
昨年仕事で関わったサーバがユーザーの強い希望で SSL 2.0 を有効にしたのをちょっと思い出してしまいましたが、半年前の調査との比較で「AESを有効にしたらSSL 2.0も有効になった」サーバがかなりあるそうなので、誰も深く考えていないだけなのかもしれません。
]]>「動かない」と言われた時は「後で書いておくよ」と軽い気持ちで答えてしまっていましたが、よく考えると XCache の管理ページなんてインストールした時に表示させただけで、その後はすぐに munin での監視を始めてしまったので、あまり記憶に残っていません。nginx 側で BASIC 認証を設定していたのが原因だったかで、うまく動かなくて苦労した記憶はあるのですが。(munin の設定については後述)
前に書いた記事で php.ini の設定を載せましたが、管理者の設定が抜けていました。
[xcache.admin] xcache.admin.auth = On xcache.admin.user = "admin" ; xcache.admin.pass = md5($your_password) xcache.admin.pass = "d41d8cd98f00b204e9800998ecf8427e"
パスワードは MD5 でハッシュを計算しておく必要があります。
コードとしては下のような簡単なものですが、このURLでハッシュを計算するものを作ってみました。
<!-- http://blog.bluegold.me/pass.php?password=XXXX XXX の部分にパスワードを入力します --> xcache.admin.pass = "<?php echo md5($REQUEST["password"]); ?>"
php.ini に管理者の設定を行った後で XCaxhe に付属の管理ページ(xcache.php)を開くと、パスワード認証をした後で管理ページが表示されると思います。
XCacheに付属の管理ページではキャッシュされているスクリプトや、使用メモリ、キャッシュヒットやキャッシュミスの回数などの基本的な情報を調べることはできますが、得られる情報はあくまでも「その時点」での情報でしかないので、キャッシュミスが増えているか等は分かりません。
このサイトでは munin を利用して XCache のキャッシュ状況をモニターしています。munin はサーバなどをモニタリングして統計画像を作るためのソフトで、この種のソフトとしては非常に簡単に設定を行うことができます。監視用のプラグインは比較的用意に作ることができ、既に多くのソフトウェアに対応しています。
XCache用のプラグインは標準ではインストールされていないので、ここから munin_xcache-0.2.tar.bz2 をダウンロードします。インストールは他のプラグインと同様に出来ますが、このプラグインは少し変わっていて「監視される側の php ファイル(munin_xcache.php)」 も一緒に入っています。こちらはウェブサーバーから見える場所においておく必要があります。
しばらくすると、このようなグラフが出来てきます。
6/16 の晩に WordPress 2.8 にアップグレードしたので、そこからキャッシュミスが多くなってきています。
]]>画像をアップロードしようとしたところ「Flashアップローダー」のボタンが表示されていないので、おかしいなと思い他のページも見ていくと Akismet や WordPress.com Stats の統計も見れなくなっていました。
Safari4 ではプラグインが別プロセスになったので、その関係で Flash に影響が出てるのかな、と思い Google で調べてみましたが、同じような症状の人がいないみたいでした。
自分の環境特有の問題のようなので、設定とかプラグインを見ていくと SafariStand を外したところで、Flash が見れるようになりました。
原因が分かったので、開発元のサイトから Safari4 用のプラグインをダウンロードしてきて、無事解決しました。
他にも同じ現象になる人がいるかもしれないのでメモしておきます。
]]>Google Developer Days 2009に参加してきました。
最近、仕事でクラウド関連の調査や開発が多くなってきているので、Google App Engineについての話を聞きにいったんですが、さすがにGoogleだけあって面白そうなセッションがたくさんあって、結局はいろいろと聞いてきてしまいました。
開発用 Android 携帯プレゼントは、予想してなかったんでちょっとうれしい。ただ、新しい iPhone を買うつもりだったので、あまり使わないだろうなぁ。(やっぱりというか、もうYahoo オークションで売ってる人もいるみたい。)
以下のセッションを聞いてきました。
どのセッションも興味深い内容でしたが、既に公開されている情報も多かったですかね。Chromeの開発体制とかの話はたいへん面白かったですが。今回、なにより印象に残ったのがAndroidのセッションに並んでいる人の多さでした。Chrome のセッションが終わってセッションルームから出ると、次の Android のセッションのために廊下をずっと人が並んでいました。去年のこの時期はWWDCに行っていたので、iPhoneに関しては熱気を肌で感じていたんですが、Androidもこんなに多くの人が参加しようとしていたとは。
今まであまり興味の無かったAndroidやOpenSocialについての概要について聞けたのは良かったかな、と思っています。特に OpenSocial はなんとなく OpenSolaris と読み間違えて、OpenSolaris の話だと思いながら記事を読んでガッカリした事が多く、意図的に無視してきた感があるので。
Google Wave のベータプログラムのアカウントをもらえたのが、今回一番うれしかったかも。
「昼食は有名なGoogleの社食のごはんがでるかも」とひそかに期待して行ったので、何もなくてがっかりしたのはココだけの話。
]]>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 ディレクティブを使えって事なんでしょうね。
複数の WordPress を1つのホストで稼働させる際に XCache Object Cache Plugin for WordPress 2.5+ を使用すると、オブジェクトキャッシュが混ざってしまうようです。
このサイトではhttp://blog.bluegold.me用とhttp://mama.bluegold.me用に2つの WordPress を稼働させています。それぞれ専用のデータベースを持つ独立したブログになっていますが、双方でオブジェクトキャッシュを有効にしたところ、しばらくして blog.bluegold.me 側の WordPress の管理コンソール(wp-admin)にログインできなくなりました。
XCache をインストールしてからは時間が経っていたので関係しているとは全く思わずに、MySQL 側でパスワードを何度も更新してログインを試みたり、WordPress 2.7.2 2.7.1 にバージョンを上げたばかりだったので、仕様が変わったのかと調べてみたりしたものの原因は分かりませんでした。
管理コンソールいろいろなIDとパスワードを入力しているうちに、blog.bluegold.me のユーザ名(bg)を入力すると「ユーザ名が違います」を表示されるのに、mama.bluegold.me 側のユーザ名(papa)を入力すると「パスワードが違います」と表示される事に気がつきました。ありえない事が起きているのが分かってきたので、試しにpapa の正しいパスワードを入力してみたところログインに成功し、bgのダッシュボードが表示されました。
ここでキャッシュが悪さをしている事がわかったので、オブジェクトキャッシュの使用を止めて、キャッシュをクリアするために PHP の FastCGI のプロセスを再起動しました。
調べてみると、やはり同じような問題を抱えている人はいるようで、以下のサイトに詳しく書かれていました。ユーザ情報が混在するのは仕様なんですかね...
http://jamescoletti.com/multiple-wordpress-installs-and-object-cache-collision
このブログは今のところ自宅に置いてあるサーバで運用しています。
手直にあるので管理は簡単なのですが、自宅の回線はアップストリームの帯域幅が大きくないので、ページを表示するさいの画像読み込みの遅延が以前から気になっていました。
このサイトでは以下のように nginx を設定することで、可能な限り静的なコンテンツの使用する帯域幅を小さくしようとしていますが、それでもファイル転送量のほとんどは画像ファイルになっています。
location / { if (-f $request_filename) { expires 30d; break; } } location ~* ^.+\.(html|css|txt|tar|bmp|rtf|js)$ { gzip_static on; expires 30d; }
以前から画像を外部のサイトに置いて転送負荷を減らそうと考え、一部の画像をflickrに置いたりしていますが、これはという解決策がありませんでした。
最近、仕事関係で Amazon のウェブサービスについて調べていてAmazon CloudFrontというサービスがあるのを知り、WordPress のテーマの画像を置いてみたらどうなるのかを調べてみました。
Amazon CloudFront は Amazon の提供するウェブサービスの1つで、いわゆるCDNです。Amazon S3に保存したファイルをインターネット上に分散配置されたキャッシュサーバに置く事で、静的なコンテンツを高速に配信する事ができるようになっています。
有料のサービスなので利用には Amazon Web Service のアカウントが必要になりますが、以下のように安価な価格設定になっているので費用対効果は高いと思います。
Amazon S3 の使い方はいろんな場所で説明されているので省きます。使用しているテーマのディレクトリから画像や css, js ファイルを CloudFront に配備してください。
S3 に置いたファイル(オブジェクト)に対して Everyone の Read 権限を与える必要がある点だけ注意してください。
Firefox のプラグイン S3OrganizerはCloudFront にも対応しているのでお勧めです。
CloudFrontに置いたファイルをWordPressから参照する方法はテーマファイル次第ですが、私のサイトで作ってもらったテーマでは bloginfo(‘template_directory’); と bloginfo(‘stylesheet_url’); の2つの値を変更するだけで大丈夫そうでした。
私はWordPressもPHPも詳しくなく、この二つの値を変更する「正しい方法」が分からなかったため適当にプラグインを書いてみました。
(こうやって野良プラグインが増えていくんだろうな)
プラグインのソースは以下の通りです。
<?php /* * Plugin Name: CloudFront * Plugin URI: http://blog.bluegold.me/cloudfront * CloudFront plugin is a plugin designed to help you drastically speed up your blog's load time by loading content onto Amazon CloudFront. * Version: 0.1 * Author: Blog Bluegold.me * Author URI: http://blog.bluegold.me * */ $cdn_base = "__EDIT_HERE__"; function filter_cdn_css($url) { global $cdn_base; return $cdn_base . "/style.css"; } function filter_cdn_template_dirctory($url) { global $cdn_base; return $cdn_base; } add_filter('stylesheet_uri','filter_cdn_css'); add_filter('template_directory_uri','filter_cdn_template_dirctory'); ?>
これを WordPress の wp-content/plugins/cloudfront/cloudfront.php という名前で保存するだけです。
]]>年末にGPGMailのRelease 1.2.0(v56)が出ていたので、さっそくアップデートしました。ベータの取れた正式版としては初めてLeopardをサポートするバージョンだと思います。
GPGMailは暗号化メールの送受信をおこなうといった意味では必要な機能を備えています。しかし、鍵管理などはGnuPGの機能をそのまま使っているため、GnuPG自体の知識が必要となります。各ユーザの鍵に関してはMacGPGプロジェクトのGPG Keychain Accessを利用すればGUIから管理することができるようになりますが、メーリングリストのアドレスに複数の鍵を対応させるような設定はGUIからはできません。
日本語での情報がほとんど無いようなのでメモしておきます。
GnuPGでメーリングリスト宛てのメールを暗号化する場合の考えたかにはいくつかあるとは思いますが、基本的には「メーリングリストのアドレス専用の鍵で暗号化する」か「メーリングリストに参加している個々のアドレスの鍵で暗号化する」かのどちらかです。前者は送る側も受け取る側も通常のメールアドレス用の鍵と同じように扱えるため非常に簡単ですが、メーリングリストのメールを受け取る全てのユーザが同一の鍵を共有する事になるのでセキュリティ上の問題があります。通常は後者を選択する事になると思います。
この方法ではメールの送信者(つまりメールを暗号化する側)が、メーリングリストに参加している各ユーザの実際のメールアドレスをあらかじめ gpg.conf に設定しておく必要があります。
たとえば、ml@example.com というアドレスがメーリングリストで、実際には user1@example.com, user2@example.com の2つのメールアドレスに配信される場合、~/.gnupg/gpg.conf に以下のような記述を行います。
group ml@example.com = user1@example.com user2@example.com
アドレスはスペース区切りです。アドレスの数が多くて1行に書ききれないような場合は、以下のように複数の行にわけて記述する事ができます。
group ml@example.com = user1@example.com user2@example.com ... group ml@example.com = user20@example.com user21@example.com
この設定はMacGPGの GPGPreferences でも設定可能と言えば可能ですが、gpg.conf を直接編集するのと難易度はあまり変わらないように思います。
]]>ただ、このままだとGmailが「迷惑メール」と判断したメールがMail.appでは未読メールとして表示されたり、Mail.appでメールを削除した際にGmailのゴミ箱に移動されずに「Deleted Messages」ラベルが付けられる、などの問題が発生します。そこで、Gmail側の「迷惑メール」フォルダなどにMail.appで「メールボックスの用途」を設定しました。これでメール管理をMail.app側に統合化する事ができ、便利に使えるようになりました。
POP3でメールを読んでいた頃はPOPFileを利用して、迷惑メールのフィルタやメールの振り分けを行っていました。Gmailには迷惑メールのフィルタ機能が元から備わっていますが、メールの振り分けをPOPFileほどは柔軟に設定できません。たとえば、会社のメールアドレスには誰かが全員用のエイリアス用に購読したNikkei BPやキーマンズネットのニュースがたくさん送られてくるのですが、単純なルールでこれらをまとめて「ニュース」フォルダに振り分けるのは(ほぼ)不可能です。
そこで、POPFileをIMAP4の環境で使用する方法について調べてみました。
POPFileのIMAPモジュールはPOPモジュールと異なりプロキシではありません。そのため、POPFileを利用するのにメールクライアントの設定を変更する必要はありません。これは良いことですが欠点もあります。プロキシとして動作しない為に、サブジェクトを変更したりX-Text-Classificationヘッダを付加する事ができません。
IMAPモジュールはメールクライアントの動作とは無関係に定期的にIMAPサーバに接続し、メールの本文の内容を判断して適切なフォルダ(Gmailの場合はラベル)に振り分けます。IMAPモジュールはいったん設定を行うと後は自動的に処理を続けるロボットのようなプログラムなので、クライアントPCで動作させるよりは常時稼働しているサーバの上で動かした方が良いのかもしれません。
IMAPモジュールの使い方は公式サイトの説明にある通りですが、Leopard(Mac OS X)で使用するには注意する点がいくつかあります。(POPFile v1.1.0 を使用しています。)
POPFile コントロールセンターの「設定」ページの「IMAPサーバー ホスト名」にGmailのIMAPサーバ名、imap.gmail.com を入力しても接続できずに、以下のエラーがログに残ります。
2008/12/25 23:48:08 10142: IMAP-Client: 136: IO::Socket::SSL error: IO::Socket::SSL: bind: Address family not supported by protocol family 2008/12/25 23:48:08 10142: imap: 1624: Could not CONNECT to server. 2008/12/25 23:48:08 10142: imap: 1493: Could not connect to server.
エラーメッセージをGoogleで検索すると、IPv6が関係しているエラーのようです。Leopard に固有の問題のようですが、「imap.google.com の AAAA レコードが見つかる為に IO::Socket::SSL がサポートしていない IPv6 で接続しようとしている」ためにエラーになっているらしい。将来のバージョンで修正されると思いますが、それまでのワークアラウンドを考えます。
要は、imap.gmail.com の AAAA レコードが見つかることが原因なので、たとえば、imap.gmail.com の(IPv4の)IPアドレスを調べて、それをIMAPサーバーのホスト名に設定したり、そのIPアドレスを逆引きして得られる実サーバのホスト名を設定すれば、とりあえず使用できるようになります。(今、私の環境から調べるとrv-in-f111.google.comです。)ただ、imap.gmail.comを構成する多数のサーバの中の1台にしか接続できなくなるため、そのうち接続出来なくなるかもしれません。
IMAPモジュールではPOPFileのバケツ毎に振り分けるIMAPのフォルダを設定する必要があります。この設定はPOPFile コントロールセンターの「設定」ページから行いますが、このページは日本語の IMAPフォルダ名に対応していません。たとえば、「迷惑メール」フォルダは「&j,dg0TDhMPww6w-」と表示されます。これは modified UTF-7 というエンコーディングだそうですが、このままでは振り分けるべきフォルダがどれなのかが分かりません。
これも将来のバージョンで修正されると思いますが、当面は以下のような方法で調べるしかないようです。
$ irb -rnet/imap irb(main):001:0> %w(迷惑メール 下書き 送信済みメール ゴミ箱).each {|key| puts "#{key} -> [Gmail]/#{Net::IMAP.encode_utf7(key)}"} 迷惑メール -> [Gmail]/&j,dg0TDhMPww6w- 下書き -> [Gmail]/&Tgtm+DBN- 送信済みメール -> [Gmail]/&kAFP4W4IMH8w4TD8MOs- ゴミ箱 -> [Gmail]/&MLQw33ux-]]>
今日はちょっと時間があったので文字化けの原因について調べてみました。
日本語の文字を含んだ広告を作成してWPAdsのデータベースを直接見てみたところ正常に保存されているようなので、原因は管理ページの表示部分にあると予想して wpads-options.php を見たところ、以下のようなコードになっていました。
<tr> <td valign="top">Description</td> <td> <input name="banner_description" type="text" size="50" value="<?php echo htmlentities($banner->banner_description);?>" /><br /> Any text that helps you identify this banner </td> </tr> <tr> <td valign="top">HTML Code</td> <td> <textarea name="banner_html" rows="6" cols="80"><?php echo htmlentities($banner->banner_html);?></textarea><br /> Copy and paste the HTML code to show the ad (for example, the Google AdSense code) </td> </tr>
どうもhtmlentities()によるエスケープ処理で日本語が化けてしまっているようです。htmlentities() は文字コードを省略されると ISO-8859-1 として処理されるようなので、正しく処理するように ‘UTF-8’ を渡します。(ついでに XSS の問題がありそうなので ENT_QUOTES オプションを追加。)
修正後のソースは以下のようになります
<tr> <td valign="top">Description</td> <td> <input name="banner_description" type="text" size="50" value="<?php echo htmlentities($banner->banner_description, ENT_QUOTES, 'UTF-8');?>" /><br /> Any text that helps you identify this banner </td> </tr> <tr> <td valign="top">HTML Code</td> <td> <textarea name="banner_html" rows="6" cols="80"><?php echo htmlentities($banner->banner_html, ENT_QUOTES, 'UTF-8');?></textarea><br /> Copy and paste the HTML code to show the ad (for example, the Google AdSense code) </td> </tr>
patch: wpads-utf8.patch
]]>計測方法は以下のコードを footer.php に追加するだけです。
<?php if (is_user_logged_in()) { ?> <?php echo get_num_queries(); ?> queries in <?php timer_stop(1); ?> seconds. <?php } ?>
結果は以下のようになりました。
トップページを3回表示させた時の時間です。
24 queries in 0.540 seconds. 24 queries in 0.545 seconds. 24 queries in 0.550 seconds.
WordPressで24 queriesは多いのか少ないのかは分かりませんが、1ページ作るのに 0.5 秒は非力なこのマシンでもちょっと遅いか。
そこで、MySQLのクエリキャッシュを有効にする事にしました。
このブログのサーバ機はメモリが256MBしかないので、いままでは無効にしていました。
my.cnfの具体的な設定値は以下の通り。
query_cache_limit=1M query_cache_min_res_unit=4k query_cache_size=16M query_cache_type=1
同じようにトップページを3回表示させたところ、若干の速度向上がありました。
微妙と言えば微妙ですが。。。
24 queries in 0.512 seconds. 24 queries in 0.510 seconds. 24 queries in 0.510 seconds.]]>
たとえば script/console を実行すると以下のようなメッセージが出てきます。
$ script/console Gem::SourceIndex#search support for String patterns is deprecated ./script/../config/boot.rb:20 is outdated Loading development environment. Gem::SourceIndex#search support for String patterns is deprecated ./script/../config/../config/boot.rb:20 is outdated >>
このアプリは Rails を使っているのでとうぜんWeb用のアプリなのですが、管理用に独自のコマンドラインシェルを用意しています。こちらのコマンドの実行時にも同様のメッセージが出てきてしまっています。「Rails 2.2 系に上げるいい時期かな」とも思わないでもないのですが、製品として提供している物なので、今期末にいくつか控えている納品を終えるまではバージョンを上げるわけにもいきません。
仕方がないのでクイックハック
script/console の最初で stderr を /dev/null に捨てるようにしました。
#!/usr/bin/env ruby $stderr.reopen('/dev/null') require File.dirname(__FILE__) + '/../config/boot' require 'commands/console'
deprecated なメッセージを簡単に抑制する設定とかもあるんだろうか。。。
]]>クラッシュした時のメッセージを良く読んでみたら、原因が書いてありました。
アプリケーション Mail は予期せず終了しました。この問題は GPGMail プラグインが原因である可能性があります。
GPGMailは Mail.app用の GnuPG のフロントエンドで、会社でやり取りするメールの暗号化に使っています。アップデートを探しに開発元のSen:TEのサイトを見てみた所、
IMPORTANT: You need at least GPGMail d55 since MacOS X 10.5.6; previous versions of GPGMail will crash Mail.
と、とっくに対応されていました。
最新の GPGMail に入れ替えたところ、Mail.app が正常に起動するようになりました。
]]>HiGash.Netの中の人にWordPressのキレイなテーマを作ってもらったので、last.fmの「最近聴いたトラック」を表示するプログラムを作りました。
last.fm の公式のウィジェットを使用すれば簡単にブログに貼付ける事ができますが、公式の物はFlashを使っていて自分でデザインを変更できないので、自分で作ってみました。last.fmはaudioscrobblerというAPIを用意しているので、このAPI経由で情報を取得します。今回は Ruby の scrobbler gemを利用しています。
scrobbler gem のインストールは以下のように簡単です。
$ sudo gem install scrobbler
scrobblerのドキュメントを見ながら、プログラムを書いていきます。
手順はだいたい次のようになります。
scrobblerライブラリを使うと簡単で、last.fmのユーザ名を指定してScrobbler::Userのオブジェクトを作成するだけです。
user = Scrobbler::User.new('bluegold') recent_tracks = user.recent_tracks
Scrobbler::User#recent_tracks の戻り値はScrobbler::TrackのArrayになっています。Scrobbler::Track は再生した曲の情報を表すオブジェクトで、曲のアルバム名やアーチスト名、last.fmのURLなどの情報を保持しています。last.fmの URLは、たとえば Sheryl Crow の Real Goneの場合はこのページの事です。
最近再生したトラックを表示するだけなら、ここまでで終わりです。
Scrobbler::Track のオブジェクトにもimageやthumbnailなどのattributeは存在するのですが、これらは’only seems to be used on top tracks for tag’とのことでScrobbler::User#recent_tracksでは値が設定されていません。そこでトラックのアーチスト名とアルバム名からScrobbler::Albumのオブジェクトを作成して、そこからアルバムアートワークを取得します。Scrobbler#Trackのオブジェクトから得られるアルバム名は(アーチスト名も?)エスケープされていて、そのままでは正しくデータを取得出来ない場合があったので、CGI#unescapeHTML を利用して元に戻しています。
track = recent_tracks.first album = Scrobbler::Album.new( track.artist, CGI.unescapeHTML(track.albumname) ) image_url = album.image(:small)
上のコードで1曲分のアートワーク画像へのURLが得られるので、表示したい曲数分繰り返します。
あとは好きなようにHTMLを書いてスタイルを設定するだけです。完成した結果はこのブログのフッターに表示されている通りです。
]]>PHPアクセラレータにはeAcceleratorやAPCなどいろいろとあるようですが、今回は使った事のないXCacheを使ってみます。XCacheはバイトコードのキャッシュの他にPHPの変数をキャッシュする機能があるので、この機能をWordPressで使うように設定も行います。
XCacheのビルドは以下の通り簡単に行うことができます。
wget http://xcache.lighttpd.net/pub/Releases/1.2.2/xcache-1.2.2.tar.gz gzip -dc xcache-1.2.2.tar.gz | tar xvf - cd xcache-1.2.2 ./configure --enable-xcache make make install
php.ini ファイルにXCacheの設定を記述します。
ソースに付属しているサンプルの xcache.ini からあまり変えていません。
[xcache-common] zend_extension = /usr/local/lib/php/extensions/no-debug-non-zts-20060613/xcache.so [xcache] xcache.shm_scheme = "mmap" xcache.size = 22M xcache.count = 1 xcache.slots = 8K xcache.ttl = 86400 xcache.gc_interval = 600 xcache.var_size = 2M xcache.var_count = 1 xcache.var_slots = 8K xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 300 xcache.test = Off xcache.readonly_protection = Off xcache.mmap_path = "/dev/zero" xcache.coredump_directory = "" xcache.cacher = On xcache.stat = On xcache.optimizer = On
xcache.size は使用するアプリケーションの種類によって調整した方がよいと思います。XCacheはeAcceleratorなどと違い、キャッシュは全てメモリ上に持つようなので大きめに設定しておいた方が良いかもしれません。
バイトコードのキャッシュは以上の設定でphpのFastCGIを再起動するだけで使用出来ますが、変数のキャッシュを利用するにはアプリケーション側で対応する必要があります。WordPressにはXCache for WordPressというプラグインがあるようですが、最近のバージョンのWordPressでは動作しないようなので、XCache Object Cache Plugin for WordPress 2.5+を使用する事にしました。
インストールは簡単ですが、XCache Object Cache Plugin for WordPressは通常のWordPressのプラグインとはインストールするパスが異なるので注意が必要です。プラグインのファイルは object-cache.php 1つだけで、これをWordPressのコンテントディレクトリ(通常は xp-content ディレクトリ)に置きます。私も最初は説明を読まずに他のプラグインと同じように xp-content/plugins ディレクトリに置いて、しばらく悩みました。
このようにバイトコードと変数の双方がキャッシュされている事を確認出来ます。これだけで体感出来る程度には速度が向上するので、導入する価値はあると思います。
]]>
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 のプロセスのオプションと同じ値を設定します。
]]>前回紹介したnginx.conf についてもう少し掘り下げて説明します。
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '"$status" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" "$gzip_ratio"'; access_log /var/log/nginx/access.log main;
nginx は良い所のたくさんあるソフトウェアですが、新しいだけに nginx のデフォルトのログフォーマットのままではAWStatsなどのログ解析ソフトに読み込ませる事ができません。そこで Apache の combind フォーマットと同じになるように設定しています。
この設定はGoogleで検索して見つけたのですが、nginx のバージョンが違うのかそのままでは AWStats や Webalizer でエラーになった為、多少変更しています。$request と $status をダブルクォーテーションで囲む必要がありました。
nginxの設定はとても簡単で、単純な VirtualHost の設定は以下のような少ない記述だけで十分です。
# error catch server { listen 80; server_name _; root /var/www/temp; index index.html; access_log /var/log/nginx/temp-access.log main; }
root を DocumentRoot, index を DirectoryIndex と読み替えれば、Apacheの設定ができる人にはほぼ説明がいらないくらいだと思います。”server_name _;”は全てのリクエストを受け付けるVirtualHostで Host: ヘッダの指定されていないリクエストなどの他の VirtualHost が処理しないリクエストがこの VirtualHost に回ってきます。当然、サービスを提供する VirtualHost には適切な server_name を設定しておきます。
脆弱製のあるサーバを探しているスキャナの多くは IP アドレスを手がかりにサーバに接続してくるので、このような設定にしておく事で、スキャナのリクエストを「何も無い VirtualHost」に閉じ込めてしまう事ができます。実際にこのホストにも phpMyAdmin や xampp の管理画面を探すリクエストが来ています。
この設定は、codered が流行した頃に大量のアタックのログを本来のサービスのログから分離する為に始めたんですが、あまり一般的じゃないのかな。
]]>gmail と uuencode をキーワードに Google で検索した所、mutt を使うのが一般的らしい。
↓のように ‘-a’ キーワードで添付するファイルを指定するだけで添付ファイルとして扱ってくれます。
mutt -a name.afz -a mysql_name.afz -s "name backup `date`" to_address
複数の添付ファイルにも対応しているので、この方法で問題ないかとも思ったのですが、1つだけ問題がありました。mutt では Envelope From を引数で変更することが出来ず、muttrc/.muttrc に別途設定する必要があります。
なんかめんどくさそうな感じがしたので、結局は Ruby でフィルタプログラムを書くことにしました。
以下のような物になりました。
#!/usr/bin/env ruby # # sendmail.rb</p> require 'rubygems' require 'tmail' require 'net/smtp' require 'nkf' require 'etc' require 'socket' require 'optparse' def usage( status, msg = nil ) output = (status == 0 ? $stdout : $stderr) output.puts msg if msg output.print(<<EOS) Usage: cat msg | #{File.basename $0} [-j|--ja] [-s <subject>] [-f <from>] <to> -s,--subject=sbj subject of the message. (default=(none)) -f,--from=from from address. -a,--attachment=file attachment -j,--ja handle japanese message. (default=off) EOS exit status end def main(args) subject = nil from = guess_from_address() to = [] attachments = [] ja_locale = false OptionParser.new do |opt| opt.banner = "Usage: #{$0} [options]" opt.on('-s', '--subject=subj', 'subject of the message. (default=(none))') do |arg| subject = arg end opt.on('-f', '--from=from', 'from address.') do | arg| from = arg end opt.on('-j', '--ja', 'handle japanese message. (default=off)') do ja_locale = true end opt.on('-a', '--attachment=file', 'attachment') do |arg| attachments << arg end to = opt.parse!(args) end usage(1) if to.empty? setup_mail(from, to, subject, $stdin.read, ja_locale, attachments) end def setup_mail( from, to, subject, body, ja_locale, attachments ) mail = TMail::Mail.new mail.date = Time.now mail.from = from mail.to = to mail.subject = subject if subject mail.mime_version = '1.0' # 本文の処理 if attachments.empty? message = mail else message = TMail::Mail.new message.transfer_encoding = '7bit' end if ja_locale message.body = <span class="caps">NKF.</span>nkf('-j', body) message.set_content_type 'text', 'plain', 'charset' => 'iso-2022-jp' else message.body = body message.set_content_type 'text', 'plain' end # 添付ファイルの処理 unless attachments.empty? mail.parts.push(message) attachments.each do |filepath| body = nil File.open(filepath) { |f| body = f.read } rescue nil next if body.nil? attachment = TMail::Mail.new filename = File.basename(filepath) encoded_body = [body].pack('m').chomp.gsub(/.{76}/, "\\1\n") attachment = TMail::Mail.new attachment.body = encoded_body attachment.transfer_encoding = 'base64' attachment.set_content_type('application', 'octet-stream', 'name' => filename) attachment.set_content_disposition('attachment', 'filename' => filename) mail.parts.push(attachment) end mail.write_back end puts mail.encoded mail end def guess_from_address user = getlogin() unless user $stderr.puts 'cannot get user account; abort.' exit 1 end if domain = (Socket.gethostname || <span class="caps">ENV</span>['HOSTNAME'] || <span class="caps">ENV</span>['HOST']) user + '@' + domain else user end end def getlogint begin require 'etc' Etc.getlogin rescue LoadError <span class="caps">ENV</span>['LOGNAME'] || <span class="caps">ENV</span>['USER'] end end main(ARGV)
TMail のサンプルの sendmail.rb をほぼそのまま使っています。
引数 ’-a’ で添付ファイルを指定出来るように変更しました。(getopts が deprecated になっていたので optparse で書き直しています。)
バックアップの作成に使用した afio には、バックアップ対象のファイルを個別に圧縮する機能があります。圧縮に使用する外部プログラムは引数で変更出来るので、これを利用して暗号化を行います。
まずは、下のような暗号化用のフィルタを作成します。
#!/bin/sh # encrypt_filter.sh opt="-pass env:FILTER_PASSWORD" if [ -r /etc/wp_backup_password ]; then opt="-pass file:/etc/wp_backup_password" fi gzip -c | openssl enc -e -aes-256-cbc $opt
次に afio に -P オプションでフィルタプログラムを使用させます。
afio -ovz -Z -U -P encrypt_filter.sh backup.afz
これでバックアップファイルが作成される際に個別のファイル毎に暗号化されるようになります。
/etc/wp_backup_password ファイルが暗号鍵になります。このファイルはバックアップを元に戻す時に必要になるので安全な場所に保管しておかないといけません。パスワードファイルの中身はなんでも構わないので、うちのサイトでは以下のようにしてランダムに作成しています。
dd if=/dev/urandom of=/etc/wp_backup_password bs=256 count=1
このファイルはバックアップを行うアカウント以外からは読み込めないようにパーミッションを設定しておく必要があります。
]]>暗号化とかは後で考えるとして、とりあえず下のようなスクリプトを書いてみました。
#!/bin/sh AFIO=/usr/local/bin/afio MYSQLHOTCOPY=/usr/bin/mysqlhotcopy SENDMAIL=/usr/sbin/sendmail WORKDIR=/var/tmp WWWDIR=/var/www LOGDIR=/var/log if [ -f /etc/wp_backup ]; then . /etc/wp_backup fi if [ ${MYSQL_USER:-nothing} = "nothing" ]; then exit 1 fi if [ ${MAIL_FROM:-nothing} = "nothing" ]; then exit 1 fi function cleanup() { rm -rf $WORKDIR/mysql rm -f $WORKDIR/$name.afz rm -f $WORKDIR/mysql_$name.afz } trap "cleanup" EXIT name=${1:-blog} if [ ! -d $WORKDIR/mysql ]; then mkdir $WORKDIR/mysql fi ( echo "BACKUP START: `date`" # backup mysql $MYSQLHOTCOPY -u $MYSQL_USER -p $MYSQL_PASSWORD $name $WORKDIR/mysql cd $WORKDIR/mysql find $name | $AFIO -ovz -Z -U $WORKDIR/mysql_$name.afz # backup wordpress cd $WWWDIR find $name | $AFIO -ovz -Z -U $WORKDIR/$name.afz echo "BACKUP FINISHED: `date`" ) >> $LOGDIR/wp_backup.log 2>&1 # send the backup files ( cat <<__END__ From: $MAIL_FROM To: $MAIL_TO Subject: $name backup `date` blog name: $name date: `date` `uuencode $name.afz < $WORKDIR/$name.afz` `uuencode mysql_$name.afz < $WORKDIR/mysql_$name.afz` __END__ ) | $SENDMAIL -f $MAIL_FROM -t $MAIL_TO exit 0
バックアップを Gmail に送信する事はできたので問題は解決したかと思ったんですが、Gmail は uuencode の添付ファイルを認識しないんですねぇ。手元の Apple Mail でも認識していないので単に時代遅れなだけか。
もう少し考えねば
]]>せっかく自宅にサーバを構築するので、会社では触らないソフトを使用してみる企画。
第一回はWebサーバとしてnginx を取り上げます。
nginx(えんじん えっくす)はロシアの人が作っているWebサーバで、軽量高速が特徴らしい。 WordPressの本家 でも使っているようなので、相性も良いだろうと言う事で。
tarball を取ってきて普通に configure, make, make install だけです。
tar zxvf nginx-0.6.32.tar.gz cd nginx-0.6.32 ./configure --with-openssl=/usr --with-http_stub_status_module make sudo paco -D make install
nginx.conf というファイルを編集します。nginx には Apache の .htaccess に相当する設定ファイルは無いようなので、基本的には全ての設定はこのファイルに書く事になります。シンプルと言えばシンプルですが、複数の Virtual Host の設定を1つのファイルに記述すると見通しが悪くなるので、設定ファイルを複数のファイルに分けて nginx.conf から include する事もできるようになっています。
試行錯誤した結果、このサイトの現在の nginx.conf は下のようになっています。
user nobody; worker_processes 3; error_log /var/log/nginx/error.log info; pid /var/run/nginx.pid; events { worker_connections 1024; use epoll; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '"$status" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" "$gzip_ratio"'; access_log /var/log/nginx/access.log main; rewrite_log on; gzip on; gzip_http_version 1.0; gzip_comp_level 2; gzip_proxied any; gzip_min_length 1100; gzip_buffers 4 8K; gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; sendfile on; tcp_nopush on; tcp_nodelay off; keepalive_timeout 65; client_max_body_size 10M; # error catch server { listen 80; server_name _; root /var/www/temp; index index.html; auth_basic "secret"; auth_basic_user_file /var/www/htpasswd; access_log /var/log/nginx/temp-access.log main; } # load the virtual server settings include /usr/local/nginx/conf.d/*.conf; }
細かい設定の話は次回
]]>