LoginSignup
8
9

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-12-15

これは 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 さんによる「生成コストの高いオブジェクトを共有するための基本」です!

8
9
0

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
  3. You can use dark theme
What you can do with signing up
8
9