apache2にて特定パスへのアクセスをproxyでWebrickに繋ぐ のバックアップ(No.3)

更新


公開メモ

概要

これ、思った以上に苦労しました。以下は、

  • ruby 1.9.3p194
  • Rails 4.0.4
  • Webrick 1.3.1
  • apache2 2.2.22-13+deb7u1

での調査結果です。

やりたいことは、

  • Webrick で rails アプリケーションを動かす
  • http://myserver.com/myapp へのアクセスを、apache2 の mod_proxy で上記 Webrick へ転送する

なのですが、これと同時に、

という問題も解決しなければなりません。

そもそも

Webrick の性能はそれほど高くないため、 大量のアクセスが見込まれるアプリケーションでは fast_cgi などを入れる方が良いです。

http://thinkit.co.jp/article/117/4/page/0/1

一方、開発中サイトのレビューなどには Webrick をそのまま外部へ公開 (パスワード等で保護しつつ)できると便利なので調べてみたのでした。

Webrick を http://myserver.com:3000/myapp で動かす

これ、結構ややこしいです。Web上でも情報が錯綜している感じでした。 https://github.com/rails/rails/issues/5122 でもまだ open のままだし。

参考:http://quickhack.net/nom/blog/2012-09-19-rails-with-relative-url-root.html

まず、普通に

LANG:console
$ rails server -p 3000

とすれば http://myserver.com:3000/ で myapp のトップページにアクセスできることを確認しましょう。

で、これを変更して http://myserver.com:3000/myapp へのアクセスでトップページを表示する準備として、

LANG:console
$ rm -r tmp/cache/assets/
$ RAILS_RELATIVE_URL_ROOT=/myapp rails server -p 3000

とします。

これでもう一度 http://myserver.com:3000/ へアクセスすれば、html ソース上における css や js, image など、assets へのリンクが /assets/* から /myapp/assets/* に書き換えられていることを確認できます。

このとき、キャッシュがクリアされずに css 内のリンクが古いままになることがあるため、 起動前にキャッシュをクリアするのが無難です。
参考:https://github.com/rails/sprockets-rails/issues/108

本来であればこれで完璧であって欲しいところなのですが、 なぜか、rails のルーティングが RAILS_RELATIVE_URL_ROOT を無視するため、 config.ru を編集して、次のようにする必要があります。

config.ru

LANG:ruby
# run Rails.application

map ActionController::Base.config.relative_url_root || "/" do
  run Rails.application
end

これで Webrick サーバーを再起動すれば、

LANG:console
$ rm -r tmp/cache/assets/
$ RAILS_RELATIVE_URL_ROOT=/myapp rails server -p 3000

http://myserver.com:3000/myapp でアプリケーションが動くようになっているはずです。

注意点

config.ru の記述を見ると、
RAILS_RELATIVE_URL_ROOT を設定しないのと、
RAILS_RELATIVE_URL_ROOT=/ とは同じ意味になりそうな気がしますが、 実はそうではありません。

assets へのリンクの書き換えは config.ru の指定とは別に行われていて、 そちらでは RAILS_RELATIVE_URL_ROOT=/ は //assets/* への誤ったリンクを生成してしまいます。

逆に、RAILS_RELATIVE_URL_ROOT に空文字列 "" を指定すると、 config.ru で map "" do ... end を呼ぶことになり、 これも paths need to start with / (ArgumentError) となってうまく行きません。

そういう意味では、

config.ru

LANG:ruby
# map ActionController::Base.config.relative_url_root || "/" do
url_root = ActionController::Base.config.relative_url_root || "/"
url_root = "/" if url_root == ""
map url_root do

のようにして、空文字列 "" が指定されたら "/" に置き換える方が安全かもしれません。

Webrick をデーモンとして起動する

ただ単に

LANG:console
$ RAILS_RELATIVE_URL_ROOT=/myapp rails server -p 3000

としたのでは、ログアウト時にサーバーが止まってしまうので、 Webrick をデーモンとして動かすために、

LANG:console
$ RAILS_RELATIVE_URL_ROOT=/myapp rails server -p 3000 -d

とします。

止めるときは、

LANG:console
$ kill -KILL `cat tmp/pids/server.pid`

です。

参照: http://qiita.com/ginpei/items/7a3b230a51e9dbd1aa72

環境を指定して Webrick を動かす

当然、本番環境であれば

LANG:console
$ RAILS_RELATIVE_URL_ROOT=/myapp rails server -p 3000 -e production -d

ですね。

サーバー起動・停止用スクリプト

一時的なサーバー起動・停止用には、

bin/server-start

LANG:ruby
#!/usr/bin/ruby

if ARGV[0]
  ENV['RAILS_RELATIVE_URL_ROOT'] = ARGV[0]
end

system 'rm -r tmp/cache/assets/*'
exec 'rails server -p 3000 -e production -d'

bin/server-stop

LANG:sh
#!/bin/sh
kill -KILL `cat tmp/pids/server.pid`

を作っておけば、

LANG:console
$ bin/server-start /myapp
$ bin/server-stop

のように操作できますね。

サーバーの再起動時にも自動的に立ち上げるには、 /etc/init.d や /etc/rc.* への設定をすることになりますが、 そこまでちゃんと動かすのであれば fast_cgi にした方が良いのだと思います。

apache2 経由で Webrick へアクセスする

mod_proxy と mod_proxy_http を入れます。Debian なら、

LANG:console
$ sudo a2enmod proxy
$ sudo a2enmod proxy_http

でOKです。

転送の設定には、 /etc/apache2/sites-enabled/001-myapp のようなファイルを作って、

<VirtualHost *:80>

  ProxyRequests Off
  ProxyPreserveHost On
  <Proxy *>
    AddDefaultCharset off
    Order deny,allow
    Allow from all
  </Proxy>

  ProxyPass /myapp http://localhost:3000/myapp
  ProxyPassReverse /myapp http://localhost:3000/myapp

</VirtualHost>

とします。

特にこの "ProxyPreserveHost On" がくせ者で、 これがないと "Not Found: /myapp" などと言って怒られ、 とりつく島が無くてうろうろすることになります・・・

参考:http://d.hatena.ne.jp/craccho/20071212/1197487724

コメント・質問





Counter: 8527 (from 2010/06/03), today: 1, yesterday: 1