RTMP対応リバースプロキシ(エッジサーバー)について
リバースプロキシサーバー(エッジサーバー)構築について。
ようやく要件を満たすサーバーができ、とりあえず完了しました。今回のサーバー構築あたりやや手こずった部分があるので、忘れないようメモしておきます。
RTMPの中継がうまくいかない!
ストリーミング用プロトコルのRTMP(1935)を中継するために、リバースプロキシにFMSのエッジサーバー機能を導入しました。
しかし、最初はうまく中継できませんでした。ストリーミング配信を実行する時点で通信が切れてしまう。原因を探るため、「Wireshark」でパケットをキャプチャしたところ…。
Wiresharkとは?
WiresharkはUNIX/LinuxやMac OS X、Windowsで動作するネットワークプロトコルアナライザです。コンピュータがネットワークを介して通信するパケットを収集し、その内容や送信先などを解析することができます。
クライアントのリクエストがリバースプロキシを経由しない!
クライアントが内部LAN上のAPサーバーに直接リクエストを送っている様子。本来、クライアントからの通信はリバースプロキスへ送って欲しいのに、リバースプロキシへ送っていません。
「Wireshark」でのパケットキャプチャでは、原因がよくわからないため、「Fiddler」を使って、HTTPのボディ部まで解析してみることにしました。
FiddlerはHTTPに特化したフリーのネットワークキャプチャツールです。
ネットワークとアプリケーションの間でプロキシとして動作し、ネットワークパケットの監視はもちろんのこと、パケット内のデータの変更やセッションに対してのブレークポイントの設定なども行えます。また、クライアント側だけでなく、ウェブサーバー側にFiddlerを配置してクライアントからのリクエストを調査するのにも使用できます。
そしたら、APサーバーが、自身のIP(プライベートIP)のURL(絶対パスでhttp://10.0.0.12みたいな感じ)をHTTPボディに記述して返していることが判明。
クライアントはこのHTTPボディ部のURLを参照して、そのURL宛にリクエストを送っているもよう。そのURLが「APサーバーのIPアドレスが記述されたURL」であるため、リバースプロキシではなく、APサーバーへ直接リクエストを送信しているようです。
HTTPボディ部のURLを置換する必要がある!
クライアントがリバースプロキシサーバーへリクエストを送信してくれるようにするためには…。
「サーバーからのレスポンスがリバースプロキシを経由する時点で、HTTPボディ部の値を置換する」必要があります。HTTPボディ部分に記述されるURLのうち「APサーバのプライベートIPを、リバースプロキシのグローバルIPへ置換する」のです。
ちなみに、リバースプロキシではApacheのmod_proxyを利用していますが、mod_proxyはHTTPメッセージのヘッダ部分のURLは置換できるが、ボディ部分のURLは置換できません。
mod_proxy_htmlでHTTPボディ部の「URL」を置換!
そこで、サードパーティ製の「mod_proxy_html」を使ってみます。 「mod_proxy_html」を導入したところ(導入方法は後述参照)、ボディ部のURLを置換できるようになりました。
しかし、それでもうまく通信できません。
関数の引数として、APサーバーのプライベートIPを使用!
なぜだろうと…と、さらにHTTPパケットのボディを解析していくと…。
HTTPホディ部では、URLの部分だけではなく「何かの関数の引数として、APサーバーのプライベートIPが記述されている」のを発見しました。
といことは、この関数の引数まで、リバースプロキシのグローバルIPへ置換してやればいいわけですが…。
「mod_proxy_html」ではURL形式は置換できるが、ただの文字列は置換できません。
mod_substituteでHTTPボディ部の「特定の文字列」を置換!
なので、代わりにApache 2.2.7以降で標準モジュールとして利用できる「mod_substitute」を使うことにしました。「mod_substitute」ならボディ部分の特定の文字列を置換できます。
「mod_substitute」を使って、以下の通りに置換するよう設定しました。
- Content-Typeがtext/html、text/xmlのレスポンスHTTPパケットを対象
- ボディ部分の「APサーバーのプライベートIPアドレス」を「リバースプロキシのグローバルIPアドレス」へ置換する
その結果、通信がうまく中継されるようになりました。よかったよかった!
サーバ構築の実際がわかる Apache[実践]運用/管理 (Software Design plus)
以下は、mod_proxy_htmlとmod_substituteの導入・設定手順です。
「mod_proxy_html」の導入
1) apxs(Apacheの拡張機能)の導入
標準モジュールでない、サードパーティ製や独自のDSOモジュールをコンパイルしてインストールすることが可能になる
yumが使えれば、
# yum -y install httpd-devel
リバースプロキシではyumでのインストールが出来ない環境であるため、CentOS用のRPMパッケージをダウンロードして、rpmコマンドでインストールする(リバースプロキシのOSはCentOS 5.5)。
# rpm -ivh httpd-devel-2.2.3-43.el5.centos.i386.rpm
※依存関係の都合で、先にapr-devel、apr-util-develも入れる必要がある。
# rpm -ivh apr-devel-1.2.7-11.el5_3.1.i386.rpm
# rpm -ivh apr-util-devel-1.2.7-11.el5.i386.rpm
apxsが使えるようになる。
2) libxml2の導入
リバースプロキシでは既に用意されていたので、改めて入れる必要は無いけど、一応…。
yumが使えれば、以下で、
# yum -y install libxml2
# yum -y install libxml2-devel
3) mod_proxy_htmlをダウンロード
[http://apache.webthing.com/mod_proxy_html/]からソースをダウンロード
# wget http://apache.webthing.com/mod_proxy_html/mod_proxy_html.tar.bz2
4) mod_proxy_html.tar.bz2の解凍・展開
# bzip2 -d mod_proxy_html.tar.bz2
# tar -xvf mod_proxy_html.tar
5) mod_proxy_htmlやmod_xml2encのビルド
# cd mod_proxy_html
# apxs -c -I/usr/include/libxml2 -I. -i mod_proxy_html.c
# apxs -c -I/usr/include/libxml2 -I. -i mod_xml2enc.c
どっかに(/usr/lib/httpd/modules/あたり?)にmod_proxy_html.soやmod_xml2enc.soができる。FMS付属のApacheでは、/opt/adobe/fms/Apache2.2/modules配下にモジュールをまとめているので、ここにコピー。
# cp mod_proxy_html.so /opt/adobe/fms/Apache2.2/modules/.
# cp mod_xml2enc.so /opt/adobe/fms/Apache2.2/modules/.
必要に応じて、パーミッションやオーナーを変更
6) proxy_html.confをコピー
mod_proxy_htmlディレクトリあるproxy_html.confを適当な場所へコピー
# cp proxy_html.conf /opt/adobe/fms/Apache2.2/conf/extra/.
必要に応じて、パーミッションやオーナーを変更
7) httpd.confの編集
# vi proxy_html.conf /opt/adobe/fms/Apache2.2/conf/httpd.conf
以下を追記
LoadModule headers_module modules/mod_headers.so ←コメントアウトになっていないことを確認
LoadFile /usr/lib/libxml2.so
LoadModule xml2enc_module modules/mod_xml2enc.so
LoadModule proxy_html_module modules/mod_proxy_html.soInclude /opt/adobe/fms/Apache2.2/conf/extra/proxy_html.conf
~~<omitted>~~
<IfModule mod_proxy.c>
ProxyRequests Off
~~<omitted>~~
ProxyHTMLEnable On
ProxyHTMLExtended On
SetOutputFilter proxy-html
ProxyHTMLURLMap http://10.0.0.11/ http://1.2.3.4/
RequestHeader unset Accept-Encoding
</IfModule>
9) httpdの再起動。
FMS付属のApacheは以下のコマンドで再起動できる。FMSも再起動されるが…。
# /etc/init.d/fms restart
以上の操作により、HTTPボディ部にある [http://APサーバーのIP/]が、[http://リバースプロキシのIP/]へ置換されていることを確認した。
「mod_substitute」の導入
Apache 2.2.7以降であれば、標準モジュールとして搭載しているらしい。FMS付属のApacheはデフォルトでは、このモジュールをロードしていないので、ロードするようにhttpd.confを編集する。
今回の場合、「mod_substitute」の置換で「mod_proxy_html」の置換まで補えます。そのため「mod_proxy_html」は必要なくなりました。
・httpd.confの編集
以下を追記
LoadModule substitute_module modules/mod_substitute.so
~~<omitted>~~
<IfModule mod_proxy.c>
ProxyRequests Off~~<omitted>~~
AddOutputFilterByType SUBSTITUTE text/html
AddOutputFilterByType SUBSTITUTE text/xmlSubstitute s/10.0.0.11/1.2.3.4/n
Substitute s/10.0.0.12/1.2.3.4/n</IfModule>
以上です。