👾

AJP連携でapacheがアプリを動かせない

2024/08/02に公開

経緯

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からの引用です


エラーメッセージから判断すると、**ProxyPassProxyPassReverseディレクティブにLocationディレクティブ内でパスが指定されているために構文エラーが発生しています。ProxyPassProxyPassReverseLocation**ディレクティブ外で設定する必要があります。

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