mod_proxy_ajp
Apache 側で標準で含まれていたり?
モジュールの読み込み
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
モジュール識別子: proxy_ajp_module
ソースファイル: mod_proxy_ajp.c
互換性: version 2.1以降で利用可能
概要
このモジュールには mod_proxyのサービスが必要です。Apache JServ プロトコル version 1.3 (以下 AJP13) のサポートを提供します。 したがって、AJP13プロトコルを処理できるようにするには、サーバにmod_proxyとmod_proxy_ajpが存在している必要があります。 table:警告
サーバーが保護されるまで、proxyを有効にしないでください。オープンプロキシサーバーは、あなたのネットワークと
インターネットの両方にとって危険です。
使用方法
このモジュールは、AJP13 プロトコルを使用してバックエンド アプリケーション サーバー (Apache Tomcat など) にリバース プロキシするために使用されます。使用方法は HTTP リバース プロキシと似ていますが、ajp://プレフィックスを使用します。
code:簡易リバースプロキシ
ProxyPass "/app" "ajp://backend.example.com:8009/app"
Tomcat の secret オプション (Tomcat 8.5.51 および 9.0.31 以降ではデフォルトで必須) などのオプションは、ProxyPass または BalancerMember の末尾に別のパラメータとして追加できます。このパラメータは、Apache HTTP Server 2.4.42 以降で使用できます。
code:secretオプション付き簡易リバースプロキシ
ProxyPass "/app" "ajp://backend.example.com:8009/app" secret=YOUR_AJP_SECRET
バランサーも使用できます
code:バランサーリバースプロキシ
<Proxy "balancer://cluster">
BalancerMember "ajp://app1.example.com:8009" loadfactor=1
BalancerMember "ajp://app2.example.com:8009" loadfactor=2
ProxySet lbmerthod=bytraffic
</Proxy>
ProxyPass "/app" "balancer://cluster/app"
通常、ProxyPassReverse ディレクティブは不要であることに注意してください。AJP リクエストにはプロキシに渡された元のホスト ヘッダーが含まれており、アプリケーション サーバーはこのホストを基準とした自己参照ヘッダーを生成することが予想されるため、書き換えは必要ありません。
主な例外は、プロキシ上の URL パスがバックエンドの URL パスと異なる場合です。この場合、リダイレクト ヘッダーは、元のホスト URL (バックエンドの ajp:// URL ではない) を基準にして書き換えることができます。次に例を示します。
code:Proxy経由Pathの書き換え
ProxyPass "/apps/foo" "ajp://backend.example.com:8009/foo"
ただし、通常は、この方法を採用するよりも、プロキシと同じパスにあるバックエンド サーバーにアプリケーションをデプロイする方が適切です。
環境変数
名前にプレフィックス AJP_ を持つ環境変数は、AJP 要求属性として配信元サーバーに転送されます (キーの名前から AJP_ プレフィックスが削除されます)。
プロトコルの概要
AJP13 プロトコルはパケット指向です。パフォーマンス上の理由から、より読みやすいプレーン テキストではなくバイナリ形式が選択されたと考えられます。Web サーバーは、TCP 接続を介してServlet コンテナと通信します。Socket作成のコストのかかるプロセスを削減するために、Web サーバーはServlet コンテナへの永続的な TCP 接続を維持し、複数の要求/応答サイクルで接続を再利用しようとします。
接続が特定の要求(request)に割り当てられると、request処理サイクルが終了するまで、他のrequestには使用されません。つまり、requestは接続を介して多重化されません。これにより、接続の両端のコードが大幅に簡素化されますが、同時に開かれる接続の数が増えます。
Web サーバーがサーブレット コンテナへの接続を開くと、接続は次のいずれかの状態になります。
Idle(アイドル)
この接続で処理されているリクエストはありません。
Assigned(割り当て済み)
接続で特定のリクエストが処理されています。
特定のリクエストを処理するために接続(connection)が割り当てられると、基本的なリクエスト情報 (HTTP ヘッダーなど) が非常に凝縮された形式で接続を介して送信されます (一般的な文字列は整数としてエンコードされます)。その形式の詳細については、下の「リクエスト パケット構造」を参照してください。リクエストに本文がある場合 (コンテンツ長 > 0)、その直後に別のパケットで送信されます。
この時点で、サーブレット コンテナはリクエストの処理を開始する準備ができていると考えられます。処理を開始すると、次のメッセージを Web サーバーに送り返すことができます。
SEND_HEADERS
一連のヘッダーをブラウザーに送り返します。
SEND_BODY_CHUNK
本文データのチャンクをブラウザーに送り返します。
GET_BODY_CHUNK
リクエストからまだすべてのデータが転送されていない場合は、さらにデータを取得します。パケットの最大サイズは固定されており、リクエストの本文に任意の量のデータを含めることができるため、これが必要です (たとえば、アップロードされたファイルの場合)。(注: これは HTTP チャンク転送とは無関係です)。
END_RESPONSE
リクエスト処理サイクルを終了します。
各メッセージには、異なる形式のデータ パケットが付随します。詳細については、以下の応答パケット構造を参照してください。
基本パケット構造
このプロトコルには XDR の遺産が少しありますが、多くの点で異なります (たとえば、4 バイトのアラインメントはありません)。
AJP13 は、すべてのデータ型にネットワーク バイト順序を使用します。
プロトコルには、バイト、ブール値、整数、文字列の 4 つのデータ型があります。
Byte
1 バイト。
Boolean
1 バイト、1 = true、0 = false。他の 0 以外の値を true として使用すると (つまり、C スタイル)、場所によっては機能する場合がありますが、他の場所では機能しません。
Integer 整数
0 から 2^16 (32768) の範囲の数値。上位バイトを先頭にして 2 バイトで格納されます。
String 文字列
可変サイズの文字列 (長さは 2^16 で制限されます)。長さを最初に 2 バイトにパックしてエンコードし、その後に文字列 (終了の '\0' を含む) が続きます。エンコードされた長さには末尾の '\0' が含まれないことに注意してください。これは strlen に似ています。これは Java 側では少し混乱を招きます。Java 側では、これらの終端文字をスキップするための奇妙な自動増分ステートメントが散在しているからです。これが行われた理由は、サーブレット コンテナが送り返す文字列を C コードがさらに効率的に読み取れるようにするためだと思います。終端の \0 文字により、C コードは参照をコピーせずに 1 つのバッファに渡すことができます。\0 がない場合、C コードは文字列の概念を取得するためにコピーする必要があります。
Packer Size パケット サイズ
コードの大部分によると、最大パケット サイズは 8 * 1024 バイト (8K) です。パケットの実際の長さはヘッダーにエンコードされています。
Packet Headers パケット ヘッダー
サーバーからコンテナーに送信されるパケットは 0x1234 で始まります。コンテナーからサーバーに送信されるパケットは AB (A の ASCII コードの後に B の ASCII コードが続く) で始まります。最初の 2 バイトの後には、ペイロードの長さを示す整数 (上記のようにエンコード) があります。これは、最大ペイロードが 2^16 になる可能性があることを示唆しているかもしれませんが、実際には、コードによって最大値が 8K に設定されています。
table:Packet Format (Server -> Container)
Byte 0 1 2 3 4 ... (n+3)
内容 0x12 0x34 データ長 (n) データ
table:Packet Format (Container -> Server)
Byte 0 1 2 3 4 ... (n+3)
内容 A B データ長 (n) データ
ほとんどのパケットでは、ペイロードの最初のバイトでメッセージの種類がエンコードされます。例外は、サーバーからコンテナーに送信されるリクエスト ボディ パケットです。リクエスト ボディ パケットは標準のパケット ヘッダー (0x1234 とパケットの長さ) とともに送信されますが、その後にプレフィックス コードは付きません。
Web サーバーは、サーブレット コンテナーに次のメッセージを送信できます。
table:Web Server messages
Code Packet型 意味
2 Forward Request 次のデータでリクエスト処理サイクルを開始します
7 Shutdown Web サーバーはコンテナにシャットダウンを要求します。
8 Ping Web サーバーはコンテナに制御権を取得するよう要求します (セキュア ログイン フェーズ)。
10 CPing Web サーバーはコンテナに CPong で迅速に応答するよう要求します。
none Data サイズ (2 バイト) と対応する本体データ。
基本的なセキュリティを確保するため、コンテナは、リクエストがホストされているマシンと同じマシンから送信された場合にのみ、実際にシャットダウンを実行します。
最初のデータ パケットは、Web サーバーによる転送リクエストの直後に送信されます。
サーブレット コンテナは、次の種類のメッセージを Web サーバーに送信できます。
table:Container messages
Code Packet型 意味
3 Send Body Chunk
4 Send Headers
5 End Response
6 Get Body Chunk
9 CPong Reply
設定
code:example
ProxyPass /example/ ajp://tomcat:8009/example/
または
<Location /example/>
ProxyPass ajp://tomcat:8009/example/
</Location>
ProxyPassReverse /example/ ajp://tomcat:8009/example/
ProxyPassReverse は Redirect の Location などを書き換える場合に必要
オプション
secret= TomcatのConnectorのsecret