AJP連携でapacheがアプリを動かせない
経緯
TomcatとApacheをAJP連携でポート80のアクセスをTomcatの8080に渡すアプリケーションを構築していたところ、「特定のIPアドレス以外にBasic認証を追加する」という要件が追加されたため、下記のようにapacheの設定ファイルを修正しました。
問題発生個所
Basic認証追加(問題のあるコード)
/etc/httpd/conf.d/proxy-ajp.conf
<Location />
AuthType Basic
AuthName "Require Auth"
AuthUserFile "/etc/httpd/.htpasswd"
<RequireAny>
Require ip 1xx.xxx.xxx.xx2
Require ip 5xx.xxx.xxx.xx9
Require valid-user
</RequireAny>
ProxyPass /phpmyadmin/ !
ProxyPass ajp://127.0.0.0:8009/
ProxyPassReverse ajp://127.0.0.0:8009/
</Location>
上記の通り設定後にapacheを再起動するとこのようなエラーが発生するようになりました。
AH00526: Syntax error on line 10 of /etc/httpd/conf.d/proxy-ajp.conf:
ProxyPass|ProxyPassMatch can not have a path when defined in a location.
ProxyPassの位置を変えて試行錯誤するも、うまく動きません。
ChatGPTを頼りに修正を試みます。
以下、ChatGPTからの引用です
エラーメッセージから判断すると、**ProxyPass
やProxyPassReverse
ディレクティブにLocation
ディレクティブ内でパスが指定されているために構文エラーが発生しています。ProxyPass
とProxyPassReverse
はLocation
**ディレクティブ外で設定する必要があります。
Locationの中に書くと不具合が発生するようなので下記のように修正します。
ProxyPassを書く場所を修正
/etc/httpd/conf.d/proxy-ajp.conf
<Location />
AuthType Basic
AuthName "Require Auth"
AuthUserFile "/etc/httpd/.htpasswd"
<RequireAny>
Require ip 1xx.xxx.xxx.xx2
Require ip 5xx.xxx.xxx.xx9
Require valid-user
</RequireAny>
</Location>
ProxyPass /phpmyadmin/ !
ProxyPass / ajp://127.0.0.0:8009/
ProxyPassReverse / ajp://127.0.0.0:8009/
先ほどとは異なるエラーが発生しました。
AH00526: Syntax error on line 11 of /etc/httpd/conf.d/proxy-ajp.conf:
ProxyPass|ProxyPassMatch needs a path when not defined in a location
解決策
悩んで試行錯誤したものの、うまく動かないので再度ChatGPTに質問してみました。
正しく動作するコード
/etc/httpd/conf.d/proxy-ajp.conf
<Location />
AuthType Basic
AuthName "Require Auth"
AuthUserFile "/etc/httpd/.htpasswd"
<RequireAny>
Require ip 1xx.xxx.xxx.xx2
Require ip 5xx.xxx.xxx.xx9
Require valid-user
</RequireAny>
</Location>
ProxyPass /phpmyadmin/ !
ProxyPassMatch ^/(.*\.php(/.*)?)?$ ajp://127.0.0.0:8009/$1
ProxyPass / ajp://127.0.0.0:8009/
ProxyPassReverse / ajp://127.0.0.0:8009/
以下、ChatGPTから引用です。
ProxyPassMatch
ディレクティブは正規表現に基づいてパスをマッチングし、対応するリバースプロキシ先を指定します。具体的には、次のような意味があります。
-
^/(.*\\.php(/.*)?)?$
: これは正規表現で、以下のように解釈されます。-
^
: 行の先頭から始まることを示します。 -
/
: スラッシュが続きます。 -
(.*\\.php(/.*)?)?
: 0回または1回、任意の文字列 +.php
+ 0回または1回、任意の文字列をマッチします。 -
$
: 行の終わりを示します。
-
この正規表現は、.php
が含まれるパスにマッチするものです。例えば、/path/to/file.php
や/path/to/directory/file.php
に対応します。
-
ajp://127.0.0.0:8009/$1
: マッチしたパスをAJPプロトコルを使用してTomcatのポート8009にリバースプロキシすることを指定します。$1
は正規表現中の1番目のキャプチャグループにマッチした部分を示します。
このProxyPassMatch
ディレクティブ全体は、.php
が含まれるパスに対してAJPでTomcatにリバースプロキシするためのものです。例えば、PHPファイルが存在する場合はApacheではなくTomcatが処理するようになります。
原因の考察
apacheはProxypassから除外された/phpmyadmin/がリバースプロキシを介さないでアクセスしていると判定するようです。
- リクエストされた/phpmyadmin/はAJP連携でTomcatサーバにリダイレクトされていないためapacheが処理をしますが、ProxyPassReverseで参照できないディレクトリになるので構文エラーが発生するのではないかと推測しています。
検証
ProxyPassReverseから/phpmyadmin/ディレクトリを除外しても動作するのではないかと思い、このように修正しました。結果、やはり正しく動作するようでした。
<Location />
AuthType Basic
AuthName "Require Auth"
AuthUserFile "/etc/httpd/.htpasswd"
<RequireAny>
Require ip 1xx.xxx.xxx.xx2
Require ip 5xx.xxx.xxx.xx9
Require valid-user
</RequireAny>
</Location>
ProxyPass /phpmyadmin/ !
ProxyPass / ajp://127.0.0.0:8009/
ProxyPassReverse /phpmyadmin/ !
ProxyPassReverse / ajp://127.0.0.0:8009/
まとめ
- ディレクティブでLocationを記載するときはディレクティブ内でパスを指定するとエラーになります。
ディレクトリパスを指定する場合は、Locationの外に記載しましょう。 - ProxyPassで除外するパスは、ディレクティブごとに除外設定が必要です。
今回はProxyPassReverseにも除外するパスを指定したことでうまく動作するようになりました。
Discussion