LoginSignup
9

More than 5 years have passed since last update.

posted at

updated at

[mod_mruby] 静的リソースをリバースプロキシで配信する

これは mod_mruby ngx_mruby Advent Calendar 2014 の16日目(12/16)の投稿です。

今回は mod_mruby でのリバースプロキシして、Amazon S3 上の静的リソース(JavaScipt/CSS/HTML/画像)を配信する方法について書きます。S3 の WEBホスティングに対して HTTP でリソースを取得しにいっているので、S3 でなくても別にどのサーバに対しても、向き先をかえれば応用できます。

前提となる環境は、アドベントカレンダーの3日目に書きましたので、何かあればそちらを参照ください。
mod_mruby を Amazon EC2、Apache2.4 へ導入する
⇒ Apache のバージョンは 2.4.10、mod_mruby のバージョンは 1.9.7 です。

また、Apache へのディレクティブ設定、および、mod_mruby スクリプトのちょっとした例については 10日目に書きました。
mod_mruby の可能性とディレクティブ設定/スクリプトの例

実現する構成

図にするとこんな感じです。

スクリーンショット 2014-12-16 21.55.22.png

最初からクライアントのデバイスから S3 の URL を参照しておけばいいじゃんという意見があるかもしれませんが、この構成は次のようなメリットがあると思っています。

  • ① WEBサーバが複数ある場合に、静的リソースを S3 で一元管理できる。
    • 静的なリソースのデプロイはアプリケーションと切り離して S3 だけで完結する。
  • ② リリース後でも、クライアントへのインタフェースはそのままに、後から素材の場所(S3 から S3 以外へ)を変更したり、例えば 画像以外は やっぱりWEBサーバに置く、画像だけ別のサーバに置く、というような変更ができる。
  • ③ 上記①と被るかもですが、HTTP レスポンスヘッダ Last-Modified および Etag の値をどの WEBサーバへのリクエストでも同じものにすることができる。
    • クライアントブラウザにキャッシュさせるときに重要。
    • WEBサーバへデプロイする際に揃えるという方法もあるにはある。
  • ④ URL のドメインを WEBサーバ(APIサーバ)と 静的リソースで同じにできる。
    • 気分や管理の問題もありますが、それ以外には JavaScript アプリケーションでクロスオリジン(クロスドメイン)対策する必要がなくなる。

本当は プロキシした静的リソースに対して、mod_mruby で画像変換や JavaScript/CSS ファイルの縮小(minify)や結合(concat)、gzip 圧縮、WEBサーバへのキャッシュなどまでできれば強力なのですが、それは別の機会にということで.. (gzip や キャッシュは mod_deflate や mod_cache と組み合わせれば何となくいけそう。)

自分の職業柄、スマホ向けの通信の最適化などは意識している分野なので。通信の最適化については、こちらのアドベントカレンダーに書きました。
モバイルフロントエンドで通信を削減する戦略についての考察

悪用すれば、任意のWEBサイトの静的リソースを勝手に(厳密には動的 API も)自ドメインから配信できてしまうのですが^^; それはやらないでください。

また今回の構成だと静的リソースのみリバースプロキシしていますが、自サービスのバックエンドの動的 API にもリバースプロキシは可能です。

Apache での設定方法

とっても簡単です。

まず前提として、Apache で HTTP プロトコルの Proxy が使えるようにしておきます。下記がコメントアウトされていたら(デフォルトでは恐らくコメントアウトされている)、コメントアウトを外します。

***.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

適当な名称で mod_mruby スクリプトを書きます。リクエストされたファイルの拡張子を見て、該当するものであればリバースプロキシします。ソースはこれだけ。

/usr/local/apache2/mruby/proxy.rb
REMOTE_HOST = 'http://s3-hoge.amazonaws.com'
r = Apache::Request.new

if /\.(css|js|gif|jpe?g|png)$/ =~ r.filename
  r.reverse_proxy REMOTE_HOST + r.uri
end

Apache::return(Apache::OK)

書いた mod_mruby スクリプトを .conf ファイルで Apache の処理フェーズにフックさせます。

***.conf
mrubyFixupsLast /usr/local/apache2/mruby/proxy.rb

cache オプションつけた方が良いかも。

mrubyTranslateNameMiddle フェーズにフックだと、Proxy の設定がキャッシュされてしまう?感じだったので mrubyFixupsLast フェーズにフックしています。

あとは Apache を再起動したら終わりで、この設定を WEBサーバの台数分やります。すると例えば S3 の http://s3-hoge.amazonaws.com/hoge.js の JavaScript ファイルが http://自ドメイン/hoge.js で取得できます :smaile:

ただアクセスが多いサイトだと、どこかの層にキャッシュをもった方が良いので、例えば WEBサーバの前段に CroutFront を置くか、もしくは S3 の前段でも良いかと。もしくは上記の mod_mruby スクリプトに追加で実装するか、または mod_cache と組み合わせるとか。

まあ順当に考えて、WEBサーバの前段に CroudFront が手軽かな。ネットワーク帯域がもったいないし。1分のキャッシュでも強力に効くと思います。

おわりに

リバースプロキシを使いこなすと、色々たのしく便利なことが実現できるので、是非チャレンジしてもらえればと思います。明日は @matsumotory さんによる「生成コストの高いオブジェクトを共有するための基本」です!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9