Nginx仮想ホスト+fastcgiのHHVM+Ubuntu13.10

タグ: Nginx   Laravel3   Laravel4   Ubuntu  

ドキュメントサイトのバックアップサイトをDigitalOceanで作成しようとしています。さほどアクセスがあるわけでもないので、一番小さな512MBのドロップレットを作成するつもりでした。

メモリが小さくて心配ですので、NginxとHHVMを使用することにしました。Nginxは試しに立てたことがあるだけで、まともに使ったことはなかったのも選択した理由です。

すったもんだし、結局HHVMがPHPのバージョン5.5以上に相当する構文解析を行うため、一部のメソッド名が引っかかり、Laravel3で使っているドキュメントサイトは動きませんでした。しかし、Laravel4やそれ以外のCMS、フレームワークをこの構成で試したい人もあるでしょう。そのため、ヒントとして残しておきます。

Ubuntuのバージョン

可能であれば、12.04を使用したかったのですが、今回の構築時点で、ネットの情報によると必要なパッケージの一部が削除されているようで、HHVMがインストールできません。

ビルド済みのパッケージをバイナリで落とすこともできるし、makeすることもできますが、この先修復されるのか不明です。メンテが面倒なので諦めました。もうすぐ、次のLTSがリリースされますので、それを待って挑戦するほうが懸命かも知れません。(ちなみに、挑戦し始めた最初の日まではうまくインストールされていました。そのため、何か自分に間違いがあるだろうと、ミスを見つけるのに時間を費やしました。結局、同様な現象に対する質問が存在していたり、PuPHPetで作成したVagrantfileを使用し、Vagrant経由でプロビションを行ってもエラーになるところから、自分の間違いではないと分かりました。)

上記の理由から、今回はUbuntu13.10を使用しました。

最初にヒント

  • できれば最初は、マルチコア構成でメモリに余裕がある環境で試したほうが、余計なトラブルが起きずに簡単でしょう。パワー不足のまま学習の初段階でトラブルと、何をするにも時間がかかって嫌になります。(下記の点も、もしかしたら、パワー不足が関係しているかも知れません。最近は開発機でも4コア、16G以上も当たり前のようですから、最低限度のリソースでうまく動作するかなんて、テストされていない部分も多いでしょう。)
  • サービス(サーバー)の起動・停止・再起動などの動作はserviceコマンドで行うように統一されてきているようです。通常はreloadで環境を再読込してくれるのですが、うまく行かない時は、(存在しているなら)force-reloadやstop/start、restartなどを試してください。(hhvm-fastcgiに関しては起動はかかりますがstopは動きません。今のところkillし、startをかけるしかないようです。)
  • hhvm-fastcgiのサービスが2つ立ち上がっており、反応が返ってこないことがありました。serviceコマンドで思った通りの動作をしない時は、確認しましょう。
  • 設定を読み込むためにはreloadやforce-reloadを使用しますが、読み込み時はコンソールメッセージが出力されます。このメッセージが表示されない場合は、stopし、プロセスが死んでいるのを確認、続いてstartし、動作していることを確認のように、毎回状態をチェックするほうが確実です。(stopしたからと言ってプロセスが死ぬわけではありませんが、完全に一度殺したほうが設定の反映は確実でした。ただし、処理の途中で殺してしまうと厄介なことが起きる可能性があるため、実運用時には避けましょう。)
  • 余り悩まずに、ログを見ましょう。Nginxのログ、HHVMのログを確認します。ただし、上記のserviceコマンドで再読込されているはずが、されていなかったり、当然ながら起動されていない場合は、ログされません。逆にログされていない状況では、プロセスがまともに動いていないと考え、再起動を試して見ましょう。起動時にエラーを表示してくれることがあります。

以下にログの表示方法を紹介しますが、パスはデフォルト時のものです。

Nginxアクセスログの確認

tail -n 5 /var/log/nginx/access.log

Nginxエラーログの確認

tail -n 5 /var/log/nginx/error.log

HHVMログの確認

tail -n 5 /var/log/hhvm/error.log

HHVMのエラーはPHPの文法エラーなどのログです。

上記の要素が絡まり、やたら時間がかかりました。上の点を理解した上で行うなら、極めて簡単に準備できます。(読んだ通りにそのままやったのでは、トラブルに対処できないという、単純なことですね。)

Nginxのインストール

標準でリポに入っています。簡単です。

インストール直後、もしくはインスタンスやドロップレットを最初に起動したときは、リポの更新とアップグレードを忘れずに!

環境により、sudoが必要です。以降、ルート前提で紹介します。

apt-get update
apt-get upgrade

Nginxを起動します。

apt-get install nginx

最初のハマりどころは、apache2とは異なり、サービスがインストール後に起動されないことです。自分で起動します。

service nginx start

ブラウザからアクセスし、動作しているか確認しましょう。

HHVMのインストール

標準リポには入っていないため、リポを指定し、インストールします。

HHVMのリポには、hhvm、hhvm-fastcgi、hhvm-nightlyの3つがあります。hhvmはサーバー、デーモン、コマンドで利用できる汎用的なもの、hhvm-fastcgiは名前が示す通りの使い方、nightlyは最新のビルドです。

echo deb http://dl.hhvm.com/ubuntu saucy main | sudo tee /etc/apt/sources.list.d/hhvm.list
sudo apt-get update
sudo apt-get install -y --force-yes hhvm hhvm-fastcgi

なお、hhvm-fastcgiのパッケージが用意されていないディストリビューションであっても、HHVMをfastcgiのデーモンとして動作させることができます。

hhvm --mode daemon -vServer.Type=fastcgi -vServer.Port=9000

Nginxのディレクトリー構成

/etc/nginxです。

apache2と似せてあるようです。sites-available下に設定ファイルを用意し、有効にするにはsites-enableへシンボリックリンクを張ることで有効にします。apache2に用意されているa2ensiteなどのコマンドはありません。a2xxxxコマンドは、リンクを張るだけのコマンドですので、普通にシンボリックリンクを張ることで代用しましょう。

hhvm.confというファイルが作成されます。通常、confファイルはconf.dディレクトリー下に配置しますが、そうしてしまうとNginxがエラーを吐きます。このファイルは、以下のように修正し、仮想ホストごとの設定で読み込むものだと理解しましょう。

location ~ \.php$ {
    fastcgi_keep_conn on;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    include        fastcgi_params;
}

上記で読み込んでいる、fastcgi_paramsファイルには、パラメーターがまとめて定義されています。以下のように修正してください。

fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
fastcgi_param   CONTENT_TYPE            $content_type;
fastcgi_param   CONTENT_LENGTH          $content_length;

fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   PATH_INFO               $fastcgi_path_info;
fastcgi_param   PATH_TRANSLATED         $document_root$fastcgi_path_info;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;

fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

fastcgi_param   REMOTE_ADDR             $remote_addr;
fastcgi_param   REMOTE_PORT             $remote_port;
fastcgi_param   SERVER_ADDR             $server_addr;
fastcgi_param   SERVER_PORT             $server_port;
fastcgi_param   SERVER_NAME             $server_name;

fastcgi_param   HTTPS                   $https;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

Nginxの仮想ホスト設定

/etc/nginx/sites-available下に設定ファイルを作成しましょう。ファイル名にドメイン名をつけると管理しやすくなります。

server {
    server_name kore1server.com;
    root /home/hiro/kore1server.com/public;
    index index.php index.html;
    try_files $uri $uri/ /index.php?q=$uri&$args;

    include hhvm.conf;
}

理解しやすいように最低限に絞っています。当サイトを動かす場合のサンプルです。

前記で修正したhhvm.confファイルを読み込んでいます。server_nameにドメイン名、rootにドキュメントルートを指定しています。indexはファイル名を指定されない場合にアクセスするファイルの順序です。

try_filesがapacheで言うところの、URLリライトの部分です。上記は、Laravelやその他のPHP製CMSとフレームワーク向きの設定です。index.phpへ渡すようになっています。(実用的には、cssや画像などが渡らぬように、locationを指定したほうが良いかと思われます。それとも、Nginxがやってくれているのかも知れません。そこら辺まで調べてはいません。Nginxが紹介され始めた頃に読んだ覚えがあるのですが、内容は思い出せません。)

include文でphpをfastcgiへ渡すlocation定義を読み込んでいます。

Laravelは動くのか?

このサイトは、現在PHPフレームワークのLaravelをメインに取り扱っています。

HHVMはPHP5.5相当の構文解析を行うようです。Laravel3のyieldメソッドが、5.5の予約語とかち合うため、動作しません。(yieldの使用はLaravelのほうが先だったようです。)

Laravel4の本体は、ほぼ動作するようです。ただし、HHVMがLaravel4のテストをオールグリーンにしたからと言っても、テストに入っていない部分では、不具合があるようです。

例えば、Artisanコマンドのoptimizeを--forceで実行すると、fileが存在しないというエラーが出ます。(Laravel本体自体はHHVM上で完全に動かそうとしているようです。このバグをどこへ連絡したらよいかつぶやいたら、Laravelの開発者のTaylorさんが調べ、バグ対応は済んでいるが、リポにタグは打っていないとのことでした。リポにタグを付けていなくても、master-devで読み込むと最新版が取れるのですが、この最新版はcomposerでエラーになるので、私の方では修正されているかは未確認です。)

また、composerで取り込む追加パッケージが動く保証があるわけでもありません。まだ、未対応な部分があり、エラーが発生することがあります。各パッケージの開発者が対応してくれるまで、使用できないものがあるでしょう。(もしくは、HHVMが完全に対応してくれるのを待つことになります。)

そのため、現状(2014年3月)では、まだ実用レベルに到達していないと考えておきましょう。