Apache のリバースプロキシの設定方法
本日は Google Gears 関連のもうひとつのネタを書こうと思ったのですが、間に合わなかったので最近仕事で使った Apache のリバースプロキシ機能の設定方法などをご紹介します。リバースプロキシは、特定のディレクトリ以下へのリクエストを他の Web サーバーに中継する機能です。 LAN 内の複数のマシンで稼動している Web サイトをひとつのグローバル IP で公開したり、 Apache 以外の Web サーバー(Rails でよく使われる mongrel とか)を Apache の Web サイトに統合したりとかが簡単にできます。
Web サイトを柔軟に構築するために、覚えておくと便利ですよ。
前提条件
Apache のリバースプロキシ機能を利用するためには、 mod_proxy を組み込んだ Apache が必要です。通常の Linux ディストリビューションなどではデフォルトで有効になっていますので、たいていは問題ないと思います。
基本的な設定
Apache の mod_proxy 関連の設定方法は公式ドキュメントにあります。けっこうたくさんのディレクティブがありますが、この中でリバースプロキシに使うのは ProxyPass, ProxyPassReverse, ProxyPassReverseCookieDomain, ProxyPassReverseCookiePass の 4 つだけです。それぞれ個別にご紹介していきます。
ProxyPass
リクエスト URL のマッピングを指定するディレクティブです。これを指定しないとはじまりません。書式は以下のとおりです。
ProxyPass 公開パス 転送先URL
例として "proxy/" 以下へのリクエストを "http://www.example2.com/" に転送する設定は以下のようになります。
ProxyPass /proxy http://www.example2.com
例えば Apache サーバーの URL が "http://www.example1.com/" の場合、 "http://www.example1.com/proxy/foo.html" へのリクエストは "http://www.example2.com/foo.html" に転送されます。 Apache 2.1 からはコネクションプール関連のオプションが多数追加されましたが、それらの詳細は公式ドキュメントを参照してください。
ProxyPassReverse
HTTP レスポンスの Location, Content-Location, URI-header を書き換えるためのディレクティブです。主にリダイレクト先 URL を正しくマッピングするために使用されます。書式は ProxyPass とまったく同じです。
ProxyPassReverse 公開パス 転送先URL
ProxyPass の例と同じ条件なら以下のようになります。
ProxyPassReverse /proxy http://www.example2.com
こうすると、 "http://www.example2.com/bar.cgi" が "http://www.example2.com/foo.html" へのリダイレクトを返した場合に、リダイレクト先が "http://www.example1.com/proxy/foo.html" に書き換えられます。ただし、書き換えに使うドメイン名は UseCanonicalName ディレクティブの設定に影響されるので注意してください。
ProxyPassReverseCookieDomain
こちらは、 Set-Cookie ヘッダのドメインを書き換えるためのディレクティブです。ドメインを明示して Cookie を作成している場合などに必要になります。書式は以下のとおりです。
ProxyPassReverseCookieDomain 書き換え前のドメイン 書き換え後のドメイン
例えば、 "www.example2.com" への Set-Cookie を "www.example1.com" にマップしたい場合、以下のように指定します。
ProxyPassReverseCookieDomain www.example2.com www.example1.com
ドメインの並び順が ProxyPass とは逆になるので注意してください。もっとも、 Set-Cookie のドメイン指定は省略することが多いので、その場合はこのディレクティブを記述する必要はありません。
ProxyPassReverseCookiePath
ProxyPassReverseCookieDomain と同様に、 Set-Cookie のパスを書き換えるためのディレクティブです。書式もほぼ同じです。
ProxyPassReverseCookiePath 書き換え前のパス 書き換え後のパス
例えば、 "/" (ルート)への Cookie を "/proxy/" にマップする場合は以下のようになります。
ProxyPassReverseCookiePath / /proxy/
パス限定の Cookie はドメイン指定よりさらにレアケースなので、たいていは必要ないと思います。
注意点
非常に便利なリバースプロキシ機能ですが、いくつか注意すべき点もあるようです。とりあえず私が気付のは以下の 3 点。
転送先URLのスキームは "http" のみです。つまり、転送先と SSL 通信を行うことはできません。SSLProxyEngine というものを使えばできるそうです。コメント欄で教えてくださった ura さん、ありがとうございます!- ProxyPass ディレクティブによるマッピングは単純な前方一致しか指定できません。代わりに RewriteRule ディレクティブを使うことで、より複雑な指定も可能です。
- HTML 中のリンクなどは補正されません。相対パスを使うなどの工夫が必要です。
SSL 通信ができないのはちょっと残念ですね。素人考えでは特に問題ないような気がするんですが、なにか理由があるんでしょうか。証明書が正しくないときの対処とかかな。
設定例
最後にいくつか代表的な設定を挙げておきます。
単純なマッピング
まずはディレクティブの説明で使った例をまとめておきます。 "http://www.example1.com/proxy/" 以下を "http://www.example2.com/" にマッピングします。
ProxyPass /proxy http://www.example2.com ProxyPassReverse /proxy http://www.example2.com ProxyPassReverseCookieDomain www.example2.com www.example1.com ProxyPassReverseCookiePath / /proxy/
バーチャルホストを他の Web サーバーにマッピング
次は、バーチャルホストを他の Web サーバーに中継する例です。 "http://www.example1.com/" を "http://localhost:8080/" に、 "http://www.example2.com/" を "http://localhost:8081/" に、それぞれ転送します。
<VirtualHost *:80> ServerName www.example1.com ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/ # その他の設定... </VirtualHost> <VirtualHost *:80> ServerName www.example2.com ProxyPass / http://localhost:8081/ ProxyPassReverse / http://localhost:8081/ # その他の設定... </VirtualHost></pre>
Location ディレクティブ内に記述
Location セクションに ProxyPass や ProxyPassReverse を記述する場合は、公開パスの指定を省略します。 Location セクションで指定されたパスがそのまま適用されるためです。マッピングと同時にアクセス制限をかけたりするのに便利です。 ProxyPassReverseCookieDomain と ProxyPassReverseCookiePath は引数を省略できないので注意してください。
<Location "/proxy"> ProxyPass http://www.example2.com ProxyPassReverse http://www.example2.com ProxyPassReverseCookieDomain www.example2.com www.example1.com ProxyPassReverseCookiePath / /proxy/ AuthType Basic AuthName "Only for administrators" AuthUserFile /usr/local/apache/passwd/passwords Require user admin </Location>
Rails をサブディレクトリで公開
応用として、 Rails で作成した Web アプリケーションを Web サイトのサブディレクトリ以下で公開する例を挙げておきます。 Apache のサイトの "/rails/" 以下に mongrel で起動した Rails アプリケーションをマッピングすることにします。
ProxyPass /rails http://localhost:3000/rails ProxyPassReverse /rails http://localhost:3000/rails
転送先URLに公開パスと同じパスを付けてやるのがポイントです。さらに mongrel の起動時に "–prefix 公開パス" というオプションをつけて、公開パスを mongrel に教えてやります。
mongrel_rails start -d -p 3000 --prefix /rails
こうすると link_to などが出力するリンク先パスの先頭に "/rails" が付加されるようになり、リンクが正しく機能します。当然ながらヘルパーを使わずに直書きしたパスは補正されないので、相対パスを使うなどして対処してください。
このとき、 SSL 経由でのアクセスも同様に転送する設定を行えば、 SSL をサポートしていない mongrel のサイトを SSL でラップすることができます。ただし、 Rails アプリケーションでリダイレクトを使っている場合には、注意が必要です。 Apache はリダイレクト先のプロトコル部分を書き換えてくれないようで、そのままではリダイレクトした途端に http に戻されてしまいます。これを回避するには、以下のようにしてリクエストヘッダに "X_FORWARDED_PROTO" を追加すると良いようです。
<VirtualHost *:443> # SSL の細かい設定(^^; RequestHeader set X_FORWARDED_PROTO 'https' ProxyPass /rails http://localhost:3000/rails ProxyPassReverse /rails http://localhost:3000/rails </VirtualHost>
このヘッダの効果はきちんと調査していないのですが、こうすると mongrel がリダイレクト先として https://〜 の URL を返すようになり、リダイレクトが正しく行われるようです。
以上、本日は Apache のリバースプロキシの使い方をご紹介しました。複数の Web サーバーをひとつのサイトにまとめたり、暗号化されていない通信を Apache の SSL でラップするなど、いろいろ応用が考えられますね。さらに高度な指定をすればロードバランサにもなるようです。とても便利な機能だと思いますので、ぜひ活用してください!
詳しくはこちらの記事をどうぞ!
この記事にコメントする