こんにちは、Re:Qの中川(晴)と申します。
「Apacheによるリバースプロキシサーバ構築」をテーマにお話しさせて頂きます。
まず執筆にあたっての想いです。
「ネットワークは専用ハードウェア機器で構成する」
これは実績があり「当たり前」と言われてきたソリューションです。
ネットワークに限りませんが、こうした「当たり前」はシステム構成検討の上で、
時として「前提条件として構成決定」されてしまうことがあります。
お客様に安心して無難に提供できる面もあるからです。
ただし、お客様から見ると「高額なハードウェア購入/保守費が必要」という点は、
必ずしも最適なソリューションではない場合もあるのではないでしょうか。
近年、OSS、仮想化などの技術進歩により、要件によっては、
同等機能をよりコストを抑え実現可能な選択肢が増えてきています。
私たちはエンジニアは「当たり前」という固定概念にとらわれない柔軟性をもち、
よりお客様が喜ぶソリューションを追及することが、大切な使命であると考えます。
このような想いもあり、ハードウェアに依存しないソリューションに関連した記事を執筆致します。
では長くなりましたが、本題に入らせて頂きます。
まず簡単に"リバースプロキシとは" から始め、
次にご紹介する設定例の構成、ポイントと続き、最後に設定ファイル例をご紹介致します。
**************************************
◆リバースプロキシとは
**************************************
リバースプロキシは、クライアントからのリクエストを代理で受け中継するプロキシの1つです。
通常のプロキシ(以降フォワードプロキシと記載)との違いは以下のとおりです。
▼フォワードプロキシは、
・「クライアント側の拠点」に設置され、
・「不特定多数のサイト宛」のリクエストを中継します。
一言でいうと「クライアント側のリクエスト要求代理」のイメージです。
(オフィスからインターネットする際にブラウザで設定するプロキシはこちらです)
一方、
▼リバースプロキシは、
・「アクセス先WEBサイト側の拠点」に設置され、
・「バックエンドの特定サーバ宛」のリクエストを中継します。
一言でいうと、フォワードプロキシとは逆で、
「WEBサイト側のリクエスト受付代理」のイメージです。
クライアントからのアクセス先窓口は、リバースプロキシ宛になりますので、
実際にコンテンツを返すWEBサーバにはクライアントから直接アクセスしません。
このことから、システム構成にもよりますが、
セキュリティ性やバックエンドサーバの負荷軽減等のために、主に利用する機能となります。
**************************************
◆ご紹介する構成イメージ
**************************************
そのリバースプロキシサーバを、ミドルウェア「Apache」で構築する際の設定ですが、
要件として、単純に「ユーザリクエストを中継し特定のWEBサーバに受け流す」だけならば、
ごくシンプルに数ラインのApache設定で実装されますが、
今回はリバースプロキシサーバ要件として以下も取り込み構成をしてみたいと思います。
▼今回取り込むリバースプロキシサーバ要件:
①負荷分散したい
(バックエンドに複数台WEBサーバがあり、リクエストを負荷分散したい)
②Sticky Sessionが必要
(毎回違うWEBサーバにアクセスするともちろんセッションが切れてしまうため、
セッション確立後、同一セッションは毎回同じWEBサーバにアクセスさせたい)
③WEBサーバ不通時はSorryページに飛ばしたい
(現在通信できない旨をブラウザのエラーメッセージではなく任意WEBページで表示する)
トラフィック量に応じて、ロードバランサ構築など最適な実現方法はあると思いますが、
今回はApache内で完結したい場合を例に示します。
構成イメージは以下図になります。
**************************************
◆設定のポイント
**************************************
ポイントは、上記要件②の「Sticky Sessionをどう実現するか」です。
今回はWEBサーバ側設定(JSESSIONIDをキーとする等)に依存せずとも動作するように、
apacheのmod_proxyモジュールで定義された以下環境変数を利用し実現します。
<変数>
・BALANCER_WORKER_ROUTE・・・当該セッションの振り分け先(下記設定例④~⑤のroute値)
・BALANCER_ROUTE_CHANGED・・・新規リクエストの場合に値に1が入る。(厳密にはSESSION ROUTEとWORKER ROUTEが一致しない場合)
本実現方法は、パッケージ製品を利用しており保守上できる限り設定を変えたくない等、
WEBサーバ側の設定変更が難しいケースに特に有効です。
▼その他注意点
・リバースプロキシとして使用する場合は、ProxyRequestsディレクティブは必ずOFFにします。
Onとするとフォワードプロキシとなり、逆に踏み台となり、システムに潜入される恐れがあります。
・転送先のWEBサーバアドレスですが、WEBサーバがレスポンスするLocationヘッダに合わせ
指定しないと、ブラウザにレスポンスする際にリバースプロキシサーバから返却されたように
見せるヘッダ書き換えが有効とならない場合があります。
(つまり、ユーザは次リクエスト時にバックエンド宛にアクセスを試みてしまいます)
**************************************
◆httpd.conf設定例(抜粋)
**************************************
Apache設定(httpd.conf)の内、ポイント部を抜粋し以下に設定例を記載致します。
--------------------------------------------------------------------------------
ProxyRequests Off
//今回は特段アクセス制限は設けておりません
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED・・・①Cookie設定
ProxyPass / balancer://webap/ lbmethod=byrequests stickysession=ROUTEID・・・②プロキシ設定
ProxyPassReverse / balancer://websv/・・・③リバースプロキシ設定
<Proxy balancer://websv/>
BalancerMember http://webserver1/ loadfactor=10 route=web01・・・④振り分け先のWEBサーバ1
BalancerMember http://webserver2/ loadfactor=10 route=web02・・・⑤振り分け先のWEBサーバ2
#SorryServer
BalancerMember http://sorryserver1/ loadfactor=10 status=+H ・・・⑥Sorryサーバも設定できます。
</Proxy>
--------------------------------------------------------------------------------
**************************************
◆設定例の説明
**************************************
簡単な箇条書きになりますが設定例について補足説明します。
注)私の個人解釈も含まれておりapacheの厳密な内部フローとは異なる場合があります
1) 新規リクエストがきた際、
初回振り分け先を、設定例②のlbmethod=byrequests(リクエスト回数判断)で決定します。
※参考になりますが、lbmethod(分散方法)は他にbytraffic(=転送byte量)、bybusynes(=空きworker優先)があります。
2) 振り分け先にリクエストを受け流します(設定例④~⑤。不通時は⑥)
3) 新規リクエストの場合は、
設定例①で、CookieにBALANCER_WORKER_ROUTE(変数ROUTEID)を書いておきます。
4) 同一セッションで再度リクエストがきた際、
CookieのBALANCER_WORKER_ROUTE(変数ROUTEID)を参照し同一のrouteに振り分けます。
**************************************
◆参考
**************************************
・Apache モジュール mod_proxy_balancer
http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html
ご紹介は以上となります。参考にして頂けたら幸いです。
ありがとうございました。