nmtysh.log

Tech系のネタや日々の独り言などを書いています。

Apache単体でリバースプロキシを行う

Squidなどを使わずにApacheのみでリバースプロキシを行います。

mod_rewriteのRewriteRuleで proxy を指定することで、Apacheが内部で別サーバーへリクエストを行ってくれますが、そのままだと色々と不便のため、取得したコンテンツに修正を行います。

Apache 2.2 以上です。

httpd.conf(抜粋)

LoadModule ext_filter_module modules/mod_ext_filter.so

RewriteEngine on

#1
RewriteCond %{REQUEST_URI} ^/gw/192\.168\.0\.[0-9]{1,3}/
RewriteRule ^/gw/(.*) /gw/http://$1 [R,NS,L]

#2
RewriteCond %{REQUEST_FILENAME} !/\.ht.* [NC]
RewriteCond %{REQUEST_URI} ^/gw/https?[:/]+192\.168\.0\.[0-9]{1,3}/
RewriteRule ^/gw/(https?)[:/]+(.*) $1://$2 [P,L,NS]

#3
Header edit Location ^(https?)[:/]+(.*) /gw/$1://$2

#4
ExtFilterDefine fixurl mode=output cmd="/bin/bash /var/www/bin/url_rewrite.sh"
SetOutputFilter fixurl


まず #1 ですが一部の携帯電話では http://(proxyホスト)/gw/http://192.168.0.xxx/ なアドレスを上手く認識出来ないため、http://(proxyホスト)/gw/192.168.0.xxx/ でもアクセス出来る用にしています。

次に #2 で実際のリバースプロキシを行っています。このときに .htaccess などへのアクセスは除外しています。

その次の #3 ですが、Locationヘッダーの書き換えを行っています。
これを行わないと、元コンテンツ内でリダイレクトを行った時に、プロキシサーバー経由では無いアドレスにリダイレクトしてしまうためです(プロキシ先から見ればプロキシ経由も普通のアクセスと同じなので)

最後の #4 ですが、ここで呼び出しているシェルスクリプトの中で、コンテンツ内のURLを書き換えています。

#4 で呼び出している url_rewrite.sh です。

#!/bin/bash

host=$(echo ${DOCUMENT_URI} | sed -e 's|^/gw/\(https\?\)[:/]\+\([^/]*\)/.*|/gw/\1://\2/|g')

/bin/sed \
    -e "s%\(href\|src\|action\)=\"/\([^\" <>\n]*\)\"%\1=\"${host}\2\"%g" \
    -e "s%\(url: *['\"]\)/\([^'\"]*['\"]\)%\1${host}\2%g" \
    -e "s%\"\(https\?\)[:/]\+\(192\.168\.0\.[0-9]\{1,3\}\)/%\"http://${HTTP_HOST}/gw/\1://\2/%g" \
    -e "s%localhost/%${HTTP_HOST}${host}%g"


ここで localhost などのURLをプロキシサーバー経由に書き換えています。
ただ、すべてのurlを対象にしていないため、jQueryなどでの呼び出しが上手くいかない場合があります。
当然ながら、このスクリプトApacheがアクセスでき、かつ実行権限が付与されている必要があります。

参考:
リバースプロキシ - Wikipedia
mod_rewrite - Apache HTTP Server(英語ページ)