mod_proxy: ProxyPass
リバースプロキシとは何か?
まず、リバースプロキシの概念を理解することが重要です。
- リバースプロキシ (Reverse Proxy)
クライアント(ユーザー)はリバースプロキシサーバーにアクセスしますが、実際のリクエストはリバースプロキシサーバーが内部の別のサーバー(バックエンドサーバー、オリジンサーバーとも呼ばれます)に転送し、その結果をクライアントに返します。クライアントからは、あたかもリバースプロキシサーバーがコンテンツを直接提供しているかのように見えます。 - フォワードプロキシ (Forward Proxy)
クライアント(ユーザー)が直接アクセスできない外部のインターネットリソースにアクセスするために使用されます。クライアントはプロキシサーバーを経由して外部に接続します。
mod_proxy
とは?
mod_proxy
は、Apache HTTP Serverがプロキシ機能を提供するための主要なモジュールです。これ単体では基本的なプロキシ機能しか提供しませんが、mod_proxy_http
(HTTPプロキシ用)、mod_proxy_ajp
(Tomcatなどとの連携用)、mod_proxy_balancer
(ロードバランシング用)といった関連モジュールと組み合わせて使用することで、より高度な機能を実現します。
ProxyPass
ディレクティブの役割
ProxyPass
ディレクティブは、Apacheをリバースプロキシとして機能させるために使用されます。具体的には、あるURLパスへのリクエストを、別のサーバー(バックエンドサーバー)の指定されたURLに転送する設定を行います。
構文例
ProxyPass "/path" "http://backend-server.example.com/otherpath"
この設定の意味
/path
: Apacheが受け取るリクエストのURLパスです。例えば、ユーザーがhttp://your-apache-server.com/path/something
にアクセスした場合、この設定が適用されます。http://backend-server.example.com/otherpath
: リクエストが実際に転送されるバックエンドサーバーのURLです。
具体的な動作
上記の例の場合、Apacheは以下のように動作します。
- バックエンドサーバーからの応答を受け取ったApacheは、その応答をあたかも自分が生成したかのようにユーザーに返します。
- バックエンドサーバーにリクエストを送信します。
- Apacheは内部的にそのリクエストを
http://backend-server.example.com/otherpath/foo
に変換し、 - ユーザーが
http://your-apache-server.com/path/foo
にアクセスすると、
ProxyPassReverse
との組み合わせ
ProxyPass
とセットでよく使われるのがProxyPassReverse
ディレクティブです。
ProxyPass "/path" "http://backend-server.example.com/otherpath"
ProxyPassReverse "/path" "http://backend-server.example.com/otherpath"
ProxyPassReverse
は、バックエンドサーバーからのレスポンスに含まれるリダイレクトヘッダー(Location:
ヘッダーなど)を書き換えるために使用されます。
なぜProxyPassReverse
が必要なのか?
バックエンドサーバーがリダイレクトを返す場合、そのリダイレクトURLはバックエンドサーバー自身のURL(例: http://backend-server.example.com/newlocation
)になります。しかし、クライアントはリバースプロキシサーバー(例: http://your-apache-server.com/
)にアクセスしているため、そのままではクライアントはバックエンドサーバーのURLに直接アクセスしようとしてしまい、問題が発生します。
ProxyPassReverse
は、このようなリダイレクトヘッダーを自動的にApacheのリバースプロキシのURL(例: http://your-apache-server.com/path/newlocation
)に書き換えることで、クライアントが正しくリダイレクトされるようにします。
mod_proxyとProxyPassの利用例
- SSL/TLS終端
ApacheでSSL/TLSを終端し、バックエンドサーバーへの通信はHTTPで行うことで、バックエンドサーバーのSSL/TLS設定の手間を省くことができます。 - セキュリティの向上
バックエンドサーバーを直接インターネットに公開せず、Apacheを介することで、ファイアウォールの内側にバックエンドサーバーを配置し、セキュリティを強化できます。 - URLの統合
複数の異なるサーバーで提供されているコンテンツを、一つのドメインやURLパスの下に統合して提供することができます。 - 負荷分散(ロードバランシング)
複数のバックエンドサーバーがある場合、mod_proxy_balancer
と組み合わせて使用することで、リクエストを複数のサーバーに分散させ、負荷を均等にすることができます。 - アプリケーションサーバーの公開
TomcatやNode.jsなどのアプリケーションサーバーは、通常、特定のポート(例: 8080)で動作します。Apacheをリバースプロキシとして設定することで、ポート80(HTTP)や443(HTTPS)でリクエストを受け取り、内部のアプリケーションサーバーに転送することができます。これにより、ユーザーはポート番号を意識せずにサービスにアクセスできます。
ProxyPass
ディレクティブの順序は重要です。より具体的な(長い)パスを先に記述しないと、意図しない設定が適用される可能性があります。ProxyRequests Off
を設定することをお勧めします。これはフォワードプロキシ機能で、意図しないアクセスを防ぐためです。リバースプロキシには不要です。mod_proxy
および関連モジュールをApacheの設定ファイル(httpd.conf
など)で有効にする必要があります。
mod_proxy: ProxyPass に関連するよくあるエラーとトラブルシューティング
mod_proxy
とProxyPass
を使用する際に発生する一般的なエラーと、その解決策について説明します。
モジュールが有効になっていない (Module not enabled)
エラーの症状
Apacheが起動しない、またはProxyPass
ディレクティブが認識されない。Apacheのエラーログに「Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration
」のようなメッセージが出力される。
原因
mod_proxy
および関連するプロキシモジュール(例: mod_proxy_http
、mod_proxy_ajp
、mod_proxy_balancer
など)がApacheの設定で有効になっていない。
トラブルシューティング
- モジュールの有効化
- Linux (Debian/Ubuntu系):
sudo a2enmod proxy proxy_http
- Linux (RHEL/CentOS系):
sudo yum install httpd-devel
(通常、デフォルトで有効)または設定ファイルでLoadModule
ディレクティブを確認。 httpd.conf
またはconf.d
内の設定ファイルで、以下のような行のコメントアウトを解除します。LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so # 必要に応じて他のモジュールも有効化 # LoadModule proxy_ajp_module modules/mod_proxy_ajp.so # LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
- Linux (Debian/Ubuntu系):
- Apacheの再起動/再読み込み
モジュールの有効化後、Apacheを再起動(sudo systemctl restart apache2
またはsudo systemctl restart httpd
)するか、設定を再読み込み(sudo systemctl reload apache2
またはsudo systemctl reload httpd
)します。
503 Service Unavailable (バックエンドへの接続失敗)
エラーの症状
ブラウザに「503 Service Unavailable」エラーが表示される。Apacheのエラーログに以下のようなメッセージが出力される。
[proxy_http:error] AH01114: HTTP: failed to make connection to backend: ...
[proxy:error] AH01114: HTTP: failed to make connection to backend: backend-server.example.com
[proxy:error] AH00959: ap_proxy_connect_backend disabling worker for (backend-server.example.com)
[proxy:error] AH00961: HTTPS: failed to enable ssl support for 127.0.0.1:8443 (127.0.0.1)
[proxy:error] AH00957: HTTP: attempt to connect to 127.0.0.1:8080 (127.0.0.1) failed
原因
ApacheがProxyPass
で指定されたバックエンドサーバーに接続できない場合に発生します。これは様々な理由が考えられます。
- バックエンドサーバーのIPアドレスやポート番号が間違っている。
- ネットワークの問題(DNS解決失敗、ルーティング問題など)。
- ファイアウォールがApacheとバックエンドサーバー間の通信をブロックしている。
- バックエンドサーバーが指定されたポートでリッスンしていない。
- バックエンドサーバーが起動していない。
トラブルシューティング
- バックエンドサーバーの稼働確認
- バックエンドサーバーが起動しているか確認します。
- バックエンドサーバーが指定されたポートでリッスンしているか確認します。(例:
netstat -tulnp | grep 8080
)
- Firewallの確認
- Apacheサーバーとバックエンドサーバー間のファイアウォール(iptables, firewalld, Windows Firewallなど)設定を確認し、必要なポート(例: 8080)が開いているか確認します。
telnet backend-server-ip 8080
やnc -vz backend-server-ip 8080
コマンドを使用して、Apacheサーバーからバックエンドサーバーへの接続性をテストします。
- ネットワーク接続の確認
ping backend-server.example.com
で名前解決と基本的なネットワーク接続を確認します。- もしIPアドレスで指定している場合は、IPアドレスが正しいか確認します。
- ProxyPassディレクティブの記述ミス
- URLのスペルミス、ポート番号の誤りがないか確認します。
- 末尾のスラッシュの有無が問題になる場合があります。
ProxyPass /app/ http://backend/app/
のように、両方に末尾のスラッシュを付けるか、両方とも付けないかのどちらかに統一すると良いことが多いです。
- ProxyTimeoutの設定
- バックエンドサーバーの応答が遅い場合、デフォルトのタイムアウト設定では不十分なことがあります。
ProxyTimeout
ディレクティブでタイムアウト値を増やしてみます。ProxyTimeout 300 # 300秒に設定 (デフォルトは60秒)
- バックエンドサーバーの応答が遅い場合、デフォルトのタイムアウト設定では不十分なことがあります。
- Apacheのログレベルの引き上げ
LogLevel debug
を設定すると、より詳細なプロキシ関連のデバッグ情報がエラーログに出力されます。問題を特定するのに役立ちます。
502 Bad Gateway (バックエンドからの無効な応答)
エラーの症状
ブラウザに「502 Bad Gateway」エラーが表示される。Apacheのエラーログに以下のようなメッセージが出力される。
[proxy:error] AH00992: Backend renderer read from backend failed
[proxy:error] AH00898: Error reading from remote server returned by /path
[proxy:error] AH01084: pass request body failed to 127.0.0.1:8080 (127.0.0.1)
原因
Apacheはバックエンドサーバーに接続できたものの、バックエンドサーバーからの応答が無効であるか、途中で接続が切断された場合に発生します。
- ネットワークの中断。
- バックエンドサーバーがタイムアウトし、Apacheに何も返さなかった。
- バックエンドサーバーが不完全なHTTPヘッダーを返している。
- バックエンドサーバーが内部エラーを発生させている。
トラブルシューティング
- バックエンドサーバーのログ確認
- 最も重要なステップです。バックエンドサーバー自身のアプリケーションログやWebサーバーログを確認し、エラーが発生していないか確認します。バックエンドで処理エラーが発生している可能性が高いです。
- バックエンドサーバーへの直接アクセス
- Apacheを介さず、バックエンドサーバーに直接アクセスして、正常に動作するか確認します。
- タイムアウトの設定
ProxyTimeout
を増やすことで、バックエンドサーバーが処理に時間がかかっている場合にエラーを防ぐことができます。
- KeepAliveの設定
SetEnv proxy-nokeepalive 1
を設定し、プロキシ接続でKeepAliveを無効にすることで、一部の断続的な502エラーが解決する場合があります。- または、Apacheの
KeepAlive
およびMaxKeepAliveRequests
設定と、バックエンドサーバーのKeepAlive設定を一致させることで改善する場合があります。
- 大きなファイル転送時の問題
- 大きなファイル転送中に502エラーが発生する場合、ネットワークの安定性やタイムアウト設定(
ProxyTimeout
)を見直す必要があります。
- 大きなファイル転送中に502エラーが発生する場合、ネットワークの安定性やタイムアウト設定(
404 Not Found (パスの不一致、またはバックエンドでの404)
エラーの症状
ブラウザに「404 Not Found」エラーが表示される。
原因
- バックエンドサーバーが、転送されたURLに対して404を返している。
- リクエストが
ProxyPass
にマッチせず、ApacheのDocumentRootからファイルを探してしまい、見つからない。 ProxyPass
のパス設定と、バックエンドサーバーが期待するパスが一致していない。
トラブルシューティング
- ProxyPassのパス確認
- Apache側のパスと、バックエンド側のパスが正しくマッピングされているか確認します。
例:
この場合、# Apacheで /app/ にアクセスした場合、バックエンドの /mywebapp/ に転送 ProxyPass "/app/" "http://backend-server.example.com/mywebapp/" ProxyPassReverse "/app/" "http://backend-server.example.com/mywebapp/"
http://your-apache.com/app/index.html
はhttp://backend-server.example.com/mywebapp/index.html
に転送されます。パスの末尾のスラッシュの有無が重要です。
- Apache側のパスと、バックエンド側のパスが正しくマッピングされているか確認します。
例:
- ProxyPassディレクティブの順序
- 複数の
ProxyPass
ディレクティブがある場合、より具体的なパス(長いパス)を先に記述する必要があります。短いパスが先にマッチしてしまうと、意図しない転送が行われます。# 誤った順序の例 ( /app/ が /app/foo/ より先にマッチしてしまう) ProxyPass "/app/" "http://backend1/" ProxyPass "/app/foo/" "http://backend2/" # 正しい順序の例 ProxyPass "/app/foo/" "http://backend2/" ProxyPass "/app/" "http://backend1/"
- 複数の
- バックエンドサーバーの確認
- Apacheから転送されたURLが、バックエンドサーバーで実際に存在するか、または処理されるべきパスか確認します。直接バックエンドサーバーにアクセスして、同じURLで404になるか試します。
リダイレクトがループする、または間違ったURLにリダイレクトされる
エラーの症状
ブラウザが無限リダイレクトループに陥るか、バックエンドサーバーの内部URLにリダイレクトされる。
原因
ProxyPassReverse
ディレクティブの設定が不足しているか、正しくない。バックエンドサーバーが返すLocation:
ヘッダーなどのリダイレクトURLが、リバースプロキシの外部URLに書き換えられていないため。
トラブルシューティング
- ProxyPassReverseの確認
ProxyPass
を使用している場合は、必ず対応するProxyPassReverse
ディレクティブも設定します。ProxyPass
とProxyPassReverse
のパスが一致しているか確認します。ProxyPass "/mywebapp/" "http://backend-server.example.com:8080/app/" ProxyPassReverse "/mywebapp/" "http://backend-server.example.com:8080/app/"
- バックエンドサーバーの設定
- 一部のアプリケーションサーバー(Tomcatなど)では、リバースプロキシ環境での動作を正しく行わせるために、コネクタ設定で
proxyName
やproxyPort
などの属性を設定する必要がある場合があります。これにより、アプリケーションが生成するURLが正しいものになります。 例 (Tomcatのserver.xml
):
HTTPSを使用している場合は<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" proxyName="your-apache-server.com" proxyPort="80" />
proxyPort="443"
を設定します。
- 一部のアプリケーションサーバー(Tomcatなど)では、リバースプロキシ環境での動作を正しく行わせるために、コネクタ設定で
- HTTPS終端時の問題
- ApacheでSSL/TLSを終端し、バックエンドへの接続がHTTPの場合、バックエンドアプリケーションがHTTPSでアクセスされていると認識せず、HTTPでリダイレクトを生成することがあります。
- Apacheで
RequestHeader set X-Forwarded-Proto "https"
を設定し、バックエンドにプロトコル情報を伝えることで解決できる場合があります。バックエンドアプリケーションがこのヘッダーを認識するように設定されている必要があります。
リクエストヘッダーの問題 (一部機能が動かない)
エラーの症状
リバースプロキシ経由でアクセスすると、ログインできない、セッションが維持されない、一部の機能が動作しないなど。
原因
- Cookieのパスが正しくない。
- リクエストヘッダー(Hostヘッダー、X-Forwarded-*ヘッダーなど)が正しくバックエンドに転送されていない、またはバックエンドがそれらを正しく処理できていない。
トラブルシューティング
- Hostヘッダーの転送
- 通常は自動的に転送されますが、明示的に
ProxyPreserveHost On
を設定することで、クライアントから送られてきたHost
ヘッダーをそのままバックエンドに転送できます。これがmod_proxy
の推奨される設定です。ProxyPreserveHost On
- 通常は自動的に転送されますが、明示的に
- X-Forwarded-*ヘッダー
- クライアントのIPアドレスをバックエンドに伝えるには
X-Forwarded-For
、元のプロトコルを伝えるにはX-Forwarded-Proto
を使用します。RequestHeader set X-Forwarded-Proto "https" env=HTTPS RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
- これらのヘッダーをバックエンドアプリケーションが正しく解釈するように設定する必要があります。
- クライアントのIPアドレスをバックエンドに伝えるには
- Cookieパスの書き換え
- バックエンドアプリケーションが生成するCookieのパスが、リバースプロキシのURLパスと一致しない場合に問題が発生します。
ProxyPassReverseCookiePath
ディレクティブを使用して、Cookieのパスを書き換えることができます。ProxyPassReverseCookiePath "/app/" "/mywebapp/" # バックエンドが /mywebapp/ で生成するCookieのパスを /app/ に書き換え
ProxyPassReverseCookieDomain
も同様にドメインを書き換えることができます。
ファイルのアップロード/ダウンロードが失敗する
エラーの症状
大きなファイルのアップロードやダウンロードが途中で失敗する。
原因
- ネットワークの問題。
- バックエンドサーバー側のタイムアウト設定が不足している。
- Apacheのタイムアウト設定が不足している。
- タイムアウトの調整
ProxyTimeout
を十分な値に設定します。- Apacheの
Timeout
ディレクティブも確認します。 - バックエンドサーバー(PHPの
max_execution_time
、upload_max_filesize
、TomcatのconnectionTimeout
など)のタイムアウト設定とファイルサイズ制限も確認します。
- ProxyPassのオプション
timeout=X
やconnectiontimeout=Y
をProxyPass
ディレクティブに追加することもできます。ProxyPass "/path/" "http://backend-server/" timeout=300 connectiontimeout=5
-
ログの確認が最優先
- Apacheのエラーログ (
/var/log/apache2/error.log
や/var/log/httpd/error_log
など) - Apacheのアクセスログ (
/var/log/apache2/access.log
や/var/log/httpd/access_log
など) - バックエンドサーバーのアプリケーションログ、Webサーバーログ
- システムログ (
journalctl -xe
や/var/log/messages
など) - ログレベルの引き上げ
LogLevel debug
に設定すると、より詳細な情報が得られます。問題の再現後、すぐに元に戻すようにしてください。
- Apacheのエラーログ (
-
設定ファイルの構文チェック
sudo apachectl configtest
またはsudo httpd -t
コマンドで、設定ファイルの構文エラーがないか確認します。
-
段階的なテスト
ProxyPass
設定を最小限にしてテストし、問題がどこにあるのかを切り分けます。- バックエンドサーバーに直接アクセスして、バックエンド自体に問題がないか確認します。
-
ネットワークツールの活用
ping
、telnet
、nc
(netcat) を使用して、Apacheサーバーからバックエンドサーバーへの基本的なネットワーク接続を確認します。curl -v http://your-apache-server.com/your-proxied-path
のようにcurl
コマンドに-v
オプションを付けて、HTTPヘッダーの詳細を確認します。
-
キャッシュのクリア
- ブラウザのキャッシュや、場合によってはApacheが
mod_cache
を使用している場合のキャッシュもクリアしてみます。
- ブラウザのキャッシュや、場合によってはApacheが
これらの設定は、Apacheの設定ファイル(通常はhttpd.conf
、またはconf.d/
やsites-available/
内のバーチャルホスト設定ファイル)に記述します。変更を適用するには、Apacheの再起動または設定の再読み込みが必要です。
基本的なリバースプロキシ設定
最もシンプルな設定で、特定のパスへのすべてのリクエストをバックエンドサーバーに転送します。
# mod_proxy と mod_proxy_http を有効にする必要があります
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
# ProxyRequests をオフにすることで、フォワードプロキシとしての動作を防ぎます
ProxyRequests Off
# クライアントのHostヘッダーをバックエンドに転送します
ProxyPreserveHost On
# /app/ へのリクエストを http://localhost:8080/ に転送
ProxyPass "/app/" "http://localhost:8080/"
# バックエンドからのリダイレクトURLを書き換える
ProxyPassReverse "/app/" "http://localhost:8080/"
解説
ProxyPassReverse "/app/" "http://localhost:8080/"
:- バックエンドサーバーが
Location: http://localhost:8080/login
のようなリダイレクトヘッダーを返した場合、Apacheがこれを傍受し、Location: http://your-apache-server.com/app/login
に書き換えてクライアントに返します。これにより、クライアントは正しいリバースプロキシのURLにリダイレクトされます。
- バックエンドサーバーが
ProxyPass "/app/" "http://localhost:8080/"
:- クライアントが
http://your-apache-server.com/app/
にアクセスすると、リクエストはhttp://localhost:8080/
に転送されます。 - 例えば、
http://your-apache-server.com/app/index.html
へのリクエストは、バックエンドのhttp://localhost:8080/index.html
に転送されます。 - パスの末尾のスラッシュ:
ProxyPass
の第1引数と第2引数の末尾のスラッシュの有無は重要です。- 両方にスラッシュがある場合 (
/app/
とhttp://localhost:8080/
):/app/foo
はhttp://localhost:8080/foo
に転送されます。 - 両方にスラッシュがない場合 (
/app
とhttp://localhost:8080
):/app/foo
はhttp://localhost:8080/foo
に転送されます。 - 一方にスラッシュがない場合、挙動が変わることがあります。混乱を避けるため、両方にスラッシュを付けるか、両方付けないかを統一するのが一般的です。
- 両方にスラッシュがある場合 (
- クライアントが
ProxyPreserveHost On
: クライアントがApacheに送ったHost
ヘッダー(例:www.example.com
)をそのままバックエンドサーバーに転送します。これにより、バックエンドサーバーが複数のバーチャルホストを扱っている場合でも、正しいホスト名でリクエストを受け取れます。ProxyRequests Off
: これが重要です。意図しないフォワードプロキシとしての利用を防ぎ、セキュリティを強化します。
ルートパス (/) をリバースプロキシする
Webサーバーのルートパス (/
) へのすべてのリクエストをバックエンドに転送する設定です。Apacheが静的ファイルを全く提供せず、すべてバックエンドに任せる場合に有効です。
ProxyRequests Off
ProxyPreserveHost On
# ルートパスへのリクエストを http://localhost:8080/ に転送
ProxyPass "/" "http://localhost:8080/"
ProxyPassReverse "/" "http://localhost:8080/"
注意点
この設定を行うと、ApacheのDocumentRoot
に配置された静的ファイルにはアクセスできなくなります。もし静的ファイルをApacheが提供する必要がある場合は、より具体的なProxyPass
ディレクティブを先に記述する必要があります(例: /images/
のようなパスはApacheが処理し、それ以外はバックエンドに転送するなど)。
特定のパスを除外する
一部のリクエスト(例: 静的ファイル)はApacheが直接処理し、それ以外のパスはバックエンドに転送したい場合に利用します。
ProxyRequests Off
ProxyPreserveHost On
# /images/ 以下へのリクエストはプロキシしない (Apacheが直接処理)
ProxyPass "/images/" "!"
# それ以外のすべてのリクエストを http://localhost:8080/ に転送
ProxyPass "/" "http://localhost:8080/"
ProxyPassReverse "/" "http://localhost:8080/"
解説
- ディレクティブの順序が重要: より具体的なパス(この場合は
/images/
)のProxyPass
ディレクティブを、より一般的なパス(/
)の前に記述する必要があります。Apacheは設定を上から順に評価し、最初にマッチしたディレクティブを適用します。 ProxyPass "/images/" "!"
: これは特別な記述で、「/images/
で始まるパスへのリクエストはプロキシしない」という意味になります。
HTTPS終端とX-Forwardedヘッダー
ApacheでSSL/TLS通信を終端し、バックエンドサーバーには平文のHTTPでリクエストを転送する場合に非常に役立ちます。また、クライアントの元のIPアドレスやプロトコル情報をバックエンドに伝えるためのヘッダーも設定します。
# SSL/TLS設定 (VirtualHostのSSLEngine Onなど、別途設定済みと仮定)
ProxyRequests Off
ProxyPreserveHost On
# クライアントのIPアドレスをバックエンドに伝える
# バックエンドのアプリケーションがこのヘッダーを解釈できるように設定する必要がある
RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
# クライアントがHTTPSでアクセスしたことをバックエンドに伝える
# バックエンドのアプリケーションがこのヘッダーを解釈できるように設定する必要がある
RequestHeader set X-Forwarded-Proto "https" env=HTTPS
# /app/ へのリクエストを http://localhost:8080/ に転送
ProxyPass "/app/" "http://localhost:8080/"
ProxyPassReverse "/app/" "http://localhost:8080/"
解説
RequestHeader set X-Forwarded-Proto "https" env=HTTPS
:- リクエストヘッダーに
X-Forwarded-Proto
を追加し、そこにhttps
をセットします。 - これは、クライアントがHTTPSでアクセスしてきた場合にのみ適用されます(
env=HTTPS
条件)。 - バックエンドアプリケーションが、自分にはHTTPでリクエストが来ているにも関わらず、実際はHTTPSでアクセスされていることを認識し、リダイレクトやURL生成を適切に行えるようになります。
- リクエストヘッダーに
RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
:- リクエストヘッダーに
X-Forwarded-For
を追加し、そこにクライアントのIPアドレスをセットします。 - バックエンドサーバーのアクセスログにはApacheのIPアドレスではなく、クライアントの元のIPアドレスが記録されるようになります(バックエンドアプリケーションがこれを読み込む設定が必要です)。
- リクエストヘッダーに
ロードバランシング (複数のバックエンドサーバー)
mod_proxy_balancer
モジュールと組み合わせて、複数のバックエンドサーバー間でリクエストを負荷分散させることができます。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
ProxyRequests Off
ProxyPreserveHost On
# バランサーの定義 (balancer://mycluster は任意の名前)
<Proxy balancer://mycluster>
# メンバーノードの定義
BalancerMember "http://backend1.example.com:8080"
BalancerMember "http://backend2.example.com:8080"
# バランシングアルゴリズム (デフォルトはbyrequests)
# BalancerAlgorithm bytraffic
# BalancerAlgorithm bybusyness
</Proxy>
# /app/ へのリクエストを定義したバランサーに転送
ProxyPass "/app/" "balancer://mycluster/"
ProxyPassReverse "/app/" "balancer://mycluster/"
# バランサーマネージャーへのアクセス (オプション: ロードバランサーの状態監視用)
<Location "/balancer-manager">
SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from 127.0.0.1 # 特定のIPアドレスからのみアクセスを許可
</Location>
解説
/balancer-manager
: これはオプションですが、ロードバランサーの現在の状態をWebブラウザで確認できる便利なインターフェースです。本番環境では、アクセスを制限するべきです。ProxyPass "/app/" "balancer://mycluster/"
:/app/
へのリクエストを、定義したmycluster
バランサーに転送します。BalancerAlgorithm
: 負荷分散のアルゴリズムを指定します(例:byrequests
(デフォルト、リクエスト数)、bytraffic
(トラフィック量)、bybusyness
(現在の処理中のリクエスト数))。BalancerMember
: グループ内の各バックエンドサーバー(ノード)を定義します。<Proxy balancer://mycluster>
:balancer://
スキームを使って、ロードバランシンググループを定義します。
AJP (Apache JServ Protocol) を使用したTomcatとの連携
TomcatのようなJavaアプリケーションサーバーと連携する場合、HTTPプロキシよりもAJPプロトコルを使用した方が効率的な場合があります。これにはmod_proxy_ajp
が必要です。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
ProxyRequests Off
ProxyPreserveHost On
# /app/ へのリクエストを ajp://localhost:8009/ に転送
# 8009 はTomcatのAJPコネクタのデフォルトポート
ProxyPass "/app/" "ajp://localhost:8009/app/"
ProxyPassReverse "/app/" "ajp://localhost:8009/app/"
ProxyPassReverse
のパス: ここでも、ProxyPass
の第2引数と一致させる必要があります。ProxyPass "/app/" "ajp://localhost:8009/app/"
:ajp://
スキームを使用している点がHTTPプロキシとの違いです。- Tomcatの
server.xml
でAJPコネクタが有効になっている必要があります(通常、デフォルトで有効です)。<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
ここでは、Apache HTTP Server 内での代替方法と、Apache 以外の一般的なリバースプロキシソリューションについて説明します。
Apache HTTP Server 内での代替方法
mod_proxy
以外にも、Apache HTTP Server にはリクエストの転送や処理を行うための他のモジュールやディレクティブが存在します。
mod_rewrite の [P] フラグ
mod_rewrite
はURLの書き換えに特化したモジュールですが、[P]
(Proxy) フラグを使用することで、書き換えられたリクエストを mod_proxy
に渡してプロキシさせることができます。これは ProxyPass
ディレクティブよりも柔軟なURLマッピングが必要な場合に特に有効です。
特徴
RewriteCond
と組み合わせて、リクエストヘッダー、環境変数、クライアントIPなど、様々な条件でプロキシを制御できる。- 特定の条件に基づいてプロキシ先を動的に決定できる。
- 正規表現を使った高度なURLマッピングが可能。
例
/api/v1/
で始まるリクエストを backend-api.example.com
に、/app/
で始まるリクエストを backend-app.example.com
にプロキシし、さらに特定のクエリパラメータがある場合にのみプロキシする。
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
RewriteEngine On
ProxyRequests Off
ProxyPreserveHost On
# /api/v1/ で始まるリクエストを特定のAPIサーバーにプロキシ
RewriteRule "^/api/v1/(.*)$" "http://backend-api.example.com/$1" [P,L]
# /app/ で始まるリクエストをアプリケーションサーバーにプロキシ
# ただし、特定のクエリパラメータ "debug=true" がある場合のみ
RewriteCond %{QUERY_STRING} debug=true
RewriteRule "^/app/(.*)$" "http://backend-app.example.com/$1" [P,L]
# ProxyPassReverse は RewriteRule とは直接関連しないが、
# バックエンドからのリダイレクトを処理するために別途必要
ProxyPassReverse "/api/v1/" "http://backend-api.example.com/api/v1/"
ProxyPassReverse "/app/" "http://backend-app.example.com/app/"
注意点
ProxyPassReverse
はRewriteRule
によって生成されたプロキシには自動的に適用されないため、別途記述する必要があります。RewriteRule
とProxyPass
は異なるメカニズムで動作するため、同じパスに対して両方を定義すると予期せぬ挙動になる可能性があります。通常は、RewriteRule
を使う場合はProxyPass
は使わないか、衝突しないように慎重に設定します。
mod_headers などを使ったリクエスト/レスポンスヘッダーの操作
直接的なプロキシの代替というよりは、mod_proxy
と組み合わせて使用されることが多いですが、mod_headers
を使ってリクエストやレスポンスのヘッダーを細かく操作することで、バックエンドサーバーとの連携をよりスムーズにしたり、セキュリティを強化したりできます。
例
クライアントIPアドレスをバックエンドに伝えるために X-Forwarded-For
ヘッダーを追加したり、セキュリティヘッダーを設定したりする。
LoadModule headers_module modules/mod_headers.so
# クライアントのIPアドレスをバックエンドに伝える (mod_proxy と組み合わせる)
RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
# バックエンドからのレスポンスにセキュリティヘッダーを追加
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Apache HTTP Server 以外にも、リバースプロキシとして機能する専用のソフトウェアやツールが多数存在します。これらは、特定のユースケースにおいてApacheのmod_proxy
よりも優れている場合があります。
Nginx
Nginx は、Webサーバーとしてだけでなく、高性能なリバースプロキシ、ロードバランサー、HTTPキャッシュとしても非常に人気があります。Apacheよりも軽量で、高負荷時のパフォーマンスに優れるとされています。
特徴
- キャッシュ機能が組み込まれている。
- WebSocketsのプロキシに優れている。
- ロードバランシング機能が豊富。
- シンプルな設定構文。
- イベント駆動型アーキテクチャにより、同時接続数が多い環境で高いパフォーマンスを発揮。
設定例 (Nginx)
http {
upstream backend_servers {
server 127.0.0.1:8080;
server 127.0.0.1:8081; # ロードバランシングの例
}
server {
listen 80;
server_name your-nginx-server.com;
location /app/ {
proxy_pass http://backend_servers/; # バックエンドのURIを維持
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # HTTP/HTTPSを伝える
proxy_redirect default; # バックエンドからのリダイレクトを適切に書き換え
}
# WebSocketのプロキシ例
location /ws/ {
proxy_pass http://127.0.0.1:8082;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
# 特定のパスは静的ファイルとして提供
location /static/ {
root /var/www/html;
}
}
}
Apache mod_proxy との比較
- SSL/TLSの終端処理もNginxは非常に得意です。
- 複雑なURL書き換えが必要な場合はApacheの
mod_rewrite
が強力ですが、Nginxも正規表現ベースのlocation
ブロックで柔軟な設定が可能です。 - Nginxは、特に静的コンテンツの配信とリバースプロキシの組み合わせで、Apacheよりも効率的な場合があります。
HAProxy
HAProxy は、高可用性、ロードバランシング、TCP/HTTPプロキシに特化したソリューションです。Webサーバー機能は持たず、プロキシ機能に徹することで、非常に高いパフォーマンスと信頼性を実現します。
特徴
- 設定は比較的複雑になることがある。
- TCPレベルのプロキシも可能(データベースプロキシなど)。
- セッション維持 (Sticky Sessions) の機能が充実している。
- 高度なロードバランシングアルゴリズムとヘルスチェック機能。
- 非常に高速で、大量の同時接続とスループットを処理できる。
設定例 (HAProxy)
frontend http_front
bind *:80
mode http
default_backend http_back
backend http_back
mode http
balance roundrobin # ロードバランシングアルゴリズム
server backend1 192.168.1.10:8080 check # ヘルスチェック有効
server backend2 192.168.1.11:8080 check
# HTTPS終端を行う場合
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/yourdomain.pem
mode http
default_backend https_back
backend https_back
mode http
balance roundrobin
server backend1 192.168.1.10:8080 check
server backend2 192.168.1.11:8080 check
# 統計情報インターフェース (オプション)
listen stats
bind *:8081
stats enable
stats uri /stats
stats realm Haproxy\ Statistics
stats auth admin:password
Apache mod_proxy との比較
- 高トラフィック環境での純粋なロードバランシングやプロキシ性能を求めるならHAProxyが非常に強力です。
- ApacheとHAProxyは、役割が明確に異なります。HAProxyはWebサーバー機能を持たないため、HAProxyをリバースプロキシとして使用し、その背後にApacheをWebサーバーとして配置する構成もよく見られます。
クラウドサービスのロードバランサー/API Gateway
AWS (Application Load Balancer / Network Load Balancer / API Gateway)、Google Cloud (Cloud Load Balancing / API Gateway)、Azure (Application Gateway / Azure Front Door) などのクラウドプロバイダーが提供するロードバランサーやAPI Gatewayサービスも、リバースプロキシと同様の機能を提供します。
特徴
- 複雑なルーティングルールやAPI管理機能。
- WAF (Web Application Firewall) やCDNとの統合が容易。
- 自動スケーリング、高可用性、セキュリティ機能が組み込まれている。
- フルマネージドサービスであり、インフラの管理が不要。
- 設定は各クラウドプロバイダーのコンソールやCLI/APIで行います。
- オンプレミス環境や限られたリソースでの構築ではApacheが適していますが、クラウドネイティブな環境ではマネージドサービスが運用コストやスケーラビリティの面で優位です。
- Apache 以外のソリューション
- Nginx: 軽量かつ高性能なリバースプロキシ/ロードバランサーとして非常に人気。静的ファイル配信とプロキシの組み合わせ、高同時接続数に強い。
- HAProxy: 高性能なロードバランサー/TCP/HTTPプロキシに特化。非常に高いスループットと信頼性が求められる場合に最適。
- クラウドサービスのロードバランサー/API Gateway: クラウド環境での運用に最適。マネージドサービスとして、スケーラビリティ、可用性、セキュリティ、運用負荷の低減に優れる。
- Apache HTTP Server 内での代替
mod_rewrite
の[P]
フラグ:ProxyPass
よりも柔軟なURLマッピングや条件分岐が必要な場合に強力。mod_headers
: プロキシと組み合わせて、ヘッダー操作による機能拡張やセキュリティ強化。