nginx + Passenger による Rails 環境の構築

Written by @dr_taka_n at 2011/01/29 22:20 [, , ]

リバースプロキシを必要としており、当初、Apache でいこうかとも思っていたのだが、より軽量(メモリ消費量が少ない)で、パフォーマンスの高い Web サーバがないものかと物色していた。
nginx というロシア製のエンジンがなかなかよさそうなので、しばらく使ってみることにした。ちなみに、読み方は「エンジンエックス」のようだ。

ついでに、 Apache + Passenger で運用していた環境も nginx + Passenger に変更した。その際の設定メモを残しておく。

作業の前提

ここでの作業の前提としては、

  • 既に Rails アプリケーションが動作する環境は構築されている
    • 既存 Web アプリの環境としては、Apache2 + Passenger。
  • サーバは Ubuntu 10.04 (Lucid)。Ruby は Enterprise Ruby を使用。

となる。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04.1 LTS"
$ ruby -v
ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-linux], MBARI 0x8770, Ruby Enterprise Edition 2010.02

Passenger がインストールされている必要があるので、インストールされていない場合は、インストールしておく。

nginx のインストール

nginx は、OS のパッケージ管理システム、もしくは、ソースからのビルドでもインストールを行える。

ここでは、Passenger をインストールすることで利用可能な passenger-install-nginx-module コマンドで nginx のインストールを行う。 Passenger の nginx モジュールの組み込みの為に、nginx 自体リビルドし直す必要があるので、事前に nginx がインストールされている必要はない。

# passenger-install-nginx-module
Welcome to the Phusion Passenger Nginx module installer, v2.2.14.

This installer will guide you through the entire installation process. It
shouldn't take more than 5 minutes in total.

Here's what you can expect from the installation process:

 1. This installer will compile and install Nginx with Passenger support.
 2. You'll learn how to configure Passenger in Nginx.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.

--------------------------------------------

Checking for required software...

 * GNU C++ compiler... found at /usr/bin/g++
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /usr/local/bin/rake
 * rack... found
 * OpenSSL development headers... found
 * Zlib development headers... found

--------------------------------------------

Automatically download and install Nginx?

もちろん、続ける。

Nginx doesn't support loadable modules such as some other web servers do,
so in order to install Nginx with Passenger support, it must be recompiled.

Do you want this installer to download, compile and install Nginx for you?

 1. Yes: download, compile and install Nginx for me. (recommended)
    The easiest way to get started. A stock Nginx 0.7.65 with Passenger
    support, but with no other additional third party modules, will be
    installed for you to a directory of your choice.

 2. No: I want to customize my Nginx installation. (for advanced users)
    Choose this if you want to compile Nginx with more third party modules
    besides Passenger, or if you need to pass additional options to Nginx's
    'configure' script. This installer will  1) ask you for the location of
    the Nginx source code,  2) run the 'configure' script according to your
    instructions, and  3) run 'make install'.

Whichever you choose, if you already have an existing Nginx configuration file,
then it will be preserved.

Enter your choice (1 or 2) or press Ctrl-C to abort:

ここでは、1 を選択する。

1を選択した場合、/tmp にソースがダウンロードされ、Passenger のインストーラが勝手にビルドしてくれる。 この後の質問でデフォルトのまま進めると、configure のパラメータは以下の通りとなる。

# ./configure --prefix='/opt/nginx' --add-module='/usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14/ext/nginx'

引き続き、幾つか質問に答えていくが、基本デフォルトのままで進める。

-----

Nginx with Passenger support was successfully installed.

The Nginx configuration file (/opt/nginx/conf/nginx.conf)
must contain the correct configuration options in order for Phusion Passenger
to function correctly.

This installer has already modified the configuration file for you! The
following configuration snippet was inserted:

  http {
      ...
      passenger_root /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14;
      passenger_ruby /usr/local/bin/ruby;
      ...
  }

After you start Nginx, you are ready to deploy any number of Ruby on Rails
applications on Nginx.

Press ENTER to continue.
-----
--------------------------------------------

Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a server block
to your Nginx configuration file, set its root to /somewhere/public, and set
'passenger_enabled on', like this:

   server {
      listen 80;
      server_name www.yourhost.com;
      root /somewhere/public;   # <--- be sure to point to 'public'!
      passenger_enabled on;
   }

And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

  /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14/doc/Users guide Nginx.html

Enjoy Phusion Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.

インストール完了。 これで、Passenger のモジュールを組み込んだ nginx が /opt/nginx 配下(デフォルトで進めた場合)にインストールされている。

とりあえず起動してみて、正常にインストールされているか確認する。

# /opt/nginx/sbin/nginx

確認する。

# netstat -lt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 *:www                   *:*                     LISTEN     
tcp        0      0 *:ssh                   *:*                     LISTEN     
# ps faux | head -1 && ps faux  | grep nginx | grep -v grep
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      7435  0.0  0.2   5672   692 ?        Ss   20:46   0:00 nginx: master process /opt/nginx/sbin/nginx
nobody    7438  0.0  0.4   5836  1108 ?        S    20:46   0:00  \_ nginx: worker process

上記の ps のプロセス、RSS(使用メモリ)の結果を見てもわるように、なかなか省エネな Web サーバだ。

ブラウザから確認してみると、とてもシンプルなご挨拶を確認できる。

hello nginx

一旦停止しておく。

# /opt/nginx/sbin/nginx -s stop

init script を用意する

init script を用しておく。

にある init script をそのまま使わせてもらう。

#! /bin/sh

### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
#                    see [Setup Ruby Enterprise Edition, nginx and Passenger (aka mod_rails) on Ubuntu](http://programmingzen.com/2009/11/20/setup-ruby-enterprise-edition-nginx-and-passenger-aka-mod_rails-on-ubuntu/)
### END INIT INFO

PATH=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/nginx/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
    . /etc/default/nginx
fi

set -e

. /lib/lsb/init-functions

case "$1" in
  start)
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \
        --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    ;;
  stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
        --exec $DAEMON || true
    echo "$NAME."
    ;;
  restart|force-reload)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile \
        /opt/nginx/logs/$NAME.pid --exec $DAEMON || true
    sleep 1
    start-stop-daemon --start --quiet --pidfile \
        /opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    ;;
  reload)
      echo -n "Reloading $DESC configuration: "
      start-stop-daemon --stop --signal HUP --quiet --pidfile /opt/nginx/logs/$NAME.pid \
          --exec $DAEMON || true
      echo "$NAME."
      ;;
  status)
      status_of_proc -p /opt/nginx/logs/$NAME.pid "$DAEMON" nginx && exit 0 || exit $?
      ;;
  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
    exit 1
    ;;
esac

exit 0

上記を /etc/init.d/nginx に保存する。

確認する。

# /etc/init.d/nginx status
 * could not access PID file for nginx
# /etc/init.d/nginx start
Starting nginx: nginx.
# netstat -lt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 *:www                   *:*                     LISTEN     
tcp        0      0 *:ssh                   *:*                     LISTEN     
# ps faux | grep nginx | grep -v grep
root      6866  0.0  0.2   5672   696 ?        Ss   20:23   0:00 nginx: master process /opt/nginx/sbin/nginx
nobody    6869  0.0  0.4   5836  1108 ?        S    20:23   0:00  \_ nginx: worker process
# /etc/init.d/nginx stop
Stopping nginx: nginx.
# ps faux | grep nginx | grep -v grep

OK だ。

init script として登録しておく。

# update-rc.d -f nginx defaults
 Adding system startup for /etc/init.d/nginx ...
   /etc/rc0.d/K20nginx -> ../init.d/nginx
   /etc/rc1.d/K20nginx -> ../init.d/nginx
   /etc/rc6.d/K20nginx -> ../init.d/nginx
   /etc/rc2.d/S20nginx -> ../init.d/nginx
   /etc/rc3.d/S20nginx -> ../init.d/nginx
   /etc/rc4.d/S20nginx -> ../init.d/nginx
   /etc/rc5.d/S20nginx -> ../init.d/nginx

これで service コマンドでも使用可能となる。

# service nginx start
Starting nginx: nginx.
# service nginx status
 * nginx is running

nginx の設定

※ nginx の設定については、別記事 Design Recipe 別館 Blog - Nginx の設定概要 にも記載しました。

現在 /opt/nginx が nginx のホームディレクトリになっている。

インストール直後のディレクトリ構成は以下の通り。

# pwd
/opt/nginx
# ll
total 28
drwx------ 2 nobody root 4096 Jan 28 07:23 client_body_temp
drwxr-xr-x 2 root   root 4096 Jan 28 07:06 conf
drwx------ 2 nobody root 4096 Jan 28 07:23 fastcgi_temp
drwxr-xr-x 2 root   root 4096 Jan 28 07:06 html
drwxr-xr-x 2 root   root 4096 Jan 28 07:28 logs
drwx------ 2 nobody root 4096 Jan 28 07:23 proxy_temp
drwxr-xr-x 2 root   root 4096 Jan 28 07:06 sbin

上記の conf ディレクトリ配下に、nginx のメインの(デフォルトで見に行く)設定ファイル nginx.conf が存在する。

nginx の設定ファイルへの設定の記述は、DSL チックなわかり易いシンタックスとなっている。

必要なディレクティブ(Directive)を記述し、ディレクティブ毎に用意されているシンタックスにそって必要な設定を記述する。 コアとなるディレクティブは、以下のページで確認できる。

それぞれのディレクティブ毎にシンタックス(syntax)の説明がある。nginx には、スコープ的な意味合いのコンテキスト(context)という概念があり、そのディレクティブが利用できるコンテキスト(context)もこのレファレンスでが確認できる。

よく使われるディレクティブとしては、httpserverlocation があり、http は Web サーバとして共通の設定、server はバーチャルサーバ毎の設定、location は、URI 毎の設定となり、それぞれがそれぞれのコンテキストを持つ。

Apache などの設定ファイルに慣れていれば、パッと見で分りやすいと思うが、初めて見た時に一瞬戸惑った location ディレクティブの modifier の部分についてだけメモしておく。

location ディレクティブのシンタックスは以下の通りとなっている。

location [=|~|~*|^~|@] pattern { ... }

loation ブロックには、リクエスト URI に対するパターンを指定でき、以下のような記述になる。

server {
  server_name example.com;
  location /admin/ {
    # http://example.com/admin/
  }
}

http://example.com/admin/ が URI に指定されれば、上記のブロックの中の記述が適用される。 上記の URI に対するパターンの記述の前に幾つかの modifier が指定できる。その意味は以下の通り。

  • 何も指定しない
    • 上記の例のパターン。
      /admin/ だけでなく、/admin/abc などもマッチするが、他のパターンの指定で URI により適したパターンがある場合にはそちらが優先される。
  • =
    • 定義されたパターンに完全一致する。
      パターンは文字列のみを利用可能。
      マッチするパターンが見つかった場合には、そこでパターンの検索は終了する
  • ^~
    • URI が指定したパターンで始まる場合にマッチする。
      マッチするパターンが見つかった場合には、そこでパターンの検索は終了する
  • ~
    • 指定した正規表現にマッチする。
      case-sensitive(大文字小文字を識別する)となる。
  • ~*
    • 指定した正規表現にマッチする。
      case-insensitive(大文字小文字を識別しない)となる。
  • @
    • named location block を定義する。 try_filesierror_page など他のディレクティブで参照することができる。

このパターンの指定と適用条件は若干の慣れが必要そうだ。

nginx + Passenger の設定を行う

nginx のインストール自体は問題なくいっているようなので、次に Passenger、Rails アプリとの連携部分の設定を行う。

インストール直後の conf/nginx.conf をみてみると、passenger-install-nginx-module がインストール時に必要最低限な設定を記述してくれているのが確認できる。

http {
    passenger_root /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14;
    passenger_ruby /usr/local/bin/ruby;

これに対して、Rails アプリ固有の情報を追加しておく。最低限必要な設定は以下の2つになる。

  • rails アプリの public ディレクトリを root として登録
  • passenger を有効化

nginx.conf に上記の2つの設定を追加しておくことになる。

        location / {
            root   /var/www/railsapp/public;   # rails app の public ディレクトリを指定
            passenger_enabled on;              # passenger を有効にしておく
            index  index.html index.htm;
        }

passenger-install-nginx-module コマンドが生成した nginx.conf に対して、とりあえず Rails アプリを動作させる為の必要最低限の変更を行った行った部分は以下の通りとなる。

# diff -u nginx.conf{,.org}
--- nginx.conf  2011-01-28 07:36:39.247744848 +0900
+++ nginx.conf.org      2011-01-28 07:06:32.652382472 +0900
@@ -44,8 +44,7 @@
         #access_log  logs/host.access.log  main;
 
         location / {
-            root   /var/www/railsapp/public;
-            passenger_enabled on;
+            root   html;
             index  index.html index.htm;
         }

設定を再読込する。

# /opt/nginx/sbin/nginx -s reload

これで Rails アプリが利用可能となっている。

SSL を有効にする

SSL を有効にする。 設定は、http コンテキストの中に HTTPS を受ける server のコンテキストを追加する。

    # HTTPS server
    #
    server {
        listen       443;
        server_name  localhost;

        ssl                  on;
        ssl_certificate      /etc/ssl/certs/ssl-cert-snakeoil.pem;   # サーバ証明書を指定
        ssl_certificate_key  /etc/ssl/private/ssl-cert-snakeoil.key; # サーバ証明書の秘密鍵を指定

        ssl_session_timeout  5m;

        ssl_protocols  SSLv2 SSLv3 TLSv1;
        ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
        ssl_prefer_server_ciphers   on;

        location / {
            root /var/www/railsapp/public;
            passenger_enabled on;
            index  index.html index.htm;
        }
    }

上記を nginx.conf に追記して、設定のシンタックスを確認する。

# /opt/nginx/sbin/nginx -t
[emerg]: unknown directive "ssl" in /opt/nginx/conf/nginx.conf:110
configuration file /opt/nginx/conf/nginx.conf test failed

ssl ディレクティブは使えないよ、と怒られる。標準ビルドでは、SSL のモジュールは組み込まれていない為だ。

nginx は、1つのバイナリファイルで簡潔している潔さがあり、Apache などと違い、動的なモジュールの追加を行わない。 必要なモジュールを追加する場合には、必要なモジュールを指定して、nginx をビルドし直すことになる。
(ちなみに、本運用に入った後に、モジュールを追加する場合などには、サーバ自体は止めずにモジュールの追加を行う方法は用意されているので安心。)

SSL のモジュールを追加で組み込むことにする。

Passenger の passenger-install-nginx-module コマンドでインストールした時は、以下の configure オプションとなっていた。

# ./configure --prefix='/opt/nginx' --add-module='/usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14/ext/nginx'

なので、今回は、--with-http_ssl_module を追加して configure からビルドし直す。

/tmp に先にインストールを行った先のソースが残っていることを前提にする。
(サーバのリブートをしてると消されているはずなので注意。)

再度 passenger-install-nginx-module を起動する。

# passenger-install-nginx-module
Welcome to the Phusion Passenger Nginx module installer, v2.2.14.

This installer will guide you through the entire installation process. It
shouldn't take more than 5 minutes in total.

Here's what you can expect from the installation process:

 1. This installer will compile and install Nginx with Passenger support.
 2. You'll learn how to configure Passenger in Nginx.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.


--------------------------------------------

Checking for required software...

 * GNU C++ compiler... found at /usr/bin/g++
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /usr/local/bin/rake
 * rack... found
 * OpenSSL development headers... found
 * Zlib development headers... found

--------------------------------------------

Automatically download and install Nginx?

Nginx doesn't support loadable modules such as some other web servers do,
so in order to install Nginx with Passenger support, it must be recompiled.

Do you want this installer to download, compile and install Nginx for you?

 1. Yes: download, compile and install Nginx for me. (recommended)
    The easiest way to get started. A stock Nginx 0.7.65 with Passenger
    support, but with no other additional third party modules, will be
    installed for you to a directory of your choice.

 2. No: I want to customize my Nginx installation. (for advanced users)
    Choose this if you want to compile Nginx with more third party modules
    besides Passenger, or if you need to pass additional options to Nginx's
    'configure' script. This installer will  1) ask you for the location of
    the Nginx source code,  2) run the 'configure' script according to your
    instructions, and  3) run 'make install'.

Whichever you choose, if you already have an existing Nginx configuration file,
then it will be preserved.

Enter your choice (1 or 2) or press Ctrl-C to abort: 2

前回 passenger-install-nginx-module を起動した時は、ここで 1 を選択したが、ここでは、 2 を選択する。

--------------------------------------------

Where is your Nginx source code located?

Please specify the directory: /tmp/nginx-0.7.65

--------------------------------------------

Where do you want to install Nginx to?

Please specify a prefix directory [/opt/nginx]:

--------------------------------------------

Extra Nginx configure options

If you want to pass extra arguments to the Nginx 'configure' script, then
please specify them. If not, then specify nothing and press Enter.

If you specify nothing then the 'configure' script will be run as follows:

  ./configure --prefix='/opt/nginx' --add-module='/usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14/ext/nginx'

Extra arguments to pass to configure script: --with-http_ssl_module

“Extra arguments to pass to configure script” で、--with-http_ssl_module を追加する。

--------------------------------------------

Confirm configure flags

The Nginx configure script will be run as follows:

  ./configure --prefix='/opt/nginx' --add-module='/usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.14/ext/nginx' --with-http_ssl_module

Is this what you want? (yes/no) [default=yes]: yes

configure オプションを確認して yes で続行。ビルドが行われる。

再度設定を確認する。

# /opt/nginx/sbin/nginx -t
the configuration file /opt/nginx/conf/nginx.conf syntax is ok
configuration file /opt/nginx/conf/nginx.conf test is successful

SSL モジュールを組み込んでいるので、今度は OK だ。 これで SSL も利用可能となっている。

blog comments powered by Disqus