Apache mod_proxy_fcgiでPHP-FPMを最適化!ProxyFCGISetEnvIf活用術

2025-05-27

mod_proxy_fcgi: ProxyFCGISetEnvIf とは

ProxyFCGISetEnvIf は、Apache HTTP Server の mod_proxy_fcgi モジュールが FastCGI バックエンドサーバー(例: PHP-FPM)にリクエストをプロキシする際に、渡される環境変数を条件に基づいて変更または設定するためのディレクティブです。

mod_proxy_fcgi は、FastCGI プロトコルを介して外部の FastCGI プロセスと通信するためのプロキシ機能を提供します。この際、Web サーバー(Apache)から FastCGI アプリケーションに、リクエストに関するさまざまな情報が環境変数として渡されます。ProxyFCGISetEnvIf を使用することで、これらの環境変数の値を細かく制御できます。

構文

ProxyFCGISetEnvIf conditional-expression [!]environment-variable-name [value-expression]

パラメータの説明

    • この式が真(true)と評価された場合に、その後の環境変数の操作が実行されます。
    • Apache の式構文 (ap_expr) を使用して記述します。これにより、リクエストヘッダー、環境変数、URLなどの情報に基づいて条件を設定できます。
    • 例: "true" (常に真、つまり無条件に適用)、"%{REQUEST_URI} =~ m|/api/(.*)$|" (URLが/api/で始まる場合にマッチ)
  1. [!]environment-variable-name (環境変数名)

    • 変更または設定したいCGI環境変数の名前を指定します(例: SCRIPT_FILENAME, PATH_INFO, PHP_ADMIN_VALUE など)。
    • 環境変数名の前に感嘆符 ! を付けると、その環境変数をFastCGIサーバーに送信しないように**解除(unset)**します。
  2. [value-expression] (値の式)

    • 指定された環境変数に設定する新しい値を指定します。
    • この値も ap_expr 構文で記述でき、他の環境変数の値や正規表現のキャプチャグループ ($1, $2 など) を参照することも可能です。
    • このパラメータを省略すると、その環境変数は空の文字列に設定されます(ただし、! を付けて解除した場合とは異なります)。

主な用途と例

ProxyFCGISetEnvIf は、特に PHP-FPM のような FastCGI アプリケーションにおいて、特定の環境変数の挙動がデフォルトでは望ましくない場合や、仮想ホストや特定のパスごとに設定を調整したい場合に非常に役立ちます。

PHP の設定を仮想ホストごとに上書きする

PHP-FPM を使用している場合、PHP_ADMIN_VALUE 環境変数を使って PHP の設定 (php.ini ディレクティブ) を動的に変更できます。

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example.com/public_html

    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/example.com/public_html/$1

    # example.com に対して open_basedir を設定
    ProxyFCGISetEnvIf "true" PHP_ADMIN_VALUE "open_basedir=/var/www/example.com/public_html/:/tmp/"
    ProxyFCGISetEnvIf "true" PHP_VALUE "memory_limit=128M"
</VirtualHost>

<VirtualHost *:80>
    ServerName another.com
    DocumentRoot /var/www/another.com/public_html

    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/another.com/public_html/$1

    # another.com に対して異なる open_basedir を設定
    ProxyFCGISetEnvIf "true" PHP_ADMIN_VALUE "open_basedir=/var/www/another.com/public_html/:/tmp/"
    ProxyFCGISetEnvIf "true" PHP_VALUE "memory_limit=256M"
</VirtualHost>

PATH_INFO の調整

mod_proxy_fcgi は、デフォルトでは PATH_INFO 環境変数を設定しない場合があります。FastCGI アプリケーションによっては、この変数を正しく解釈するために必要となることがあります。ProxyFCGISetEnvIf を使って PATH_INFO を手動で設定できます。

# URLのパスからPATH_INFOを計算して設定する
ProxyFCGISetEnvIf "%{REQUEST_URI} =~ m|^/index\\.php(/.*)$|" PATH_INFO "$1"

上記の例では、REQUEST_URI/index.php/something のような形式の場合に、PATH_INFO/something に設定します。

SCRIPT_FILENAME の調整

一部の FastCGI アプリケーションや特定の環境では、SCRIPT_FILENAME の値が期待通りの形式で FastCGI に渡されないことがあります。ProxyFCGISetEnvIf を用いて、正しいファイルパスを構築して渡すことができます。

# ドキュメントルートとリクエストされたURIを組み合わせてSCRIPT_FILENAMEを設定
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{DOCUMENT_ROOT}%{REQUEST_URI}"

これは一般的なケースですが、ProxyPassMatchProxyPass の設定によっては、FastCGI パスが内部的に処理されるため、この調整が必要ない場合もあります。

特定の環境変数を削除する

FastCGI アプリケーションに特定の環境変数を渡したくない場合、! を使用して解除できます。

# MY_CUSTOM_VAR 環境変数をFastCGIに送らない
ProxyFCGISetEnvIf "true" !MY_CUSTOM_VAR
  • デバッグ
    問題が発生した場合は、Apache のログレベルを debug に設定し、mod_proxy_fcgi の出力を確認すると、渡されている環境変数の詳細が表示され、デバッグに役立ちます。
  • 評価順序
    ProxyFCGISetEnvIf ディレクティブは、他の環境変数が初期設定された後に評価されます。そのため、条件式や値の式で既存の環境変数 (%{REQUEST_URI} など) を参照できます。
  • mod_proxy と mod_proxy_fcgi の有効化
    ProxyFCGISetEnvIf を使用するには、mod_proxymod_proxy_fcgi の両方が Apache にロードされている必要があります。


ProxyFCGISetEnvIf は非常に強力なディレクティブですが、その設定ミスはしばしば問題を引き起こします。FastCGI アプリケーション(特に PHP-FPM)が正しく動作しない場合、環境変数の渡し方が原因であることが多いです。

FastCGI バックエンド (PHP-FPMなど) との接続問題

エラーの症状

  • Apache の error_log に以下のようなメッセージが出力される:
    • [proxy_fcgi:error] AH01071: Got error 'Primary script unknown'
    • [proxy_fcgi:error] AH01071: Got error 'No input file specified.'
    • [proxy:error] AH00957: FCGI: attempt to connect to ... failed
    • [proxy:error] AH00961: FCGI: error dispatching request to ...
    • Failed to read FastCGI header
  • ブラウザに「500 Internal Server Error」が表示される。

ProxyFCGISetEnvIf との関係
これらのエラーは直接 ProxyFCGISetEnvIf の設定ミスに起因するものではありませんが、SCRIPT_FILENAMEPATH_INFO などの環境変数が正しく渡されていない場合に発生しやすいため、トラブルシューティングの際に確認するべき点です。

トラブルシューティング

  • SELinux/AppArmor
    SELinux や AppArmor などの強制アクセス制御システムが有効になっている場合、FastCGI プロセスや Apache のファイルアクセスをブロックしている可能性があります。ログを確認し、必要に応じてルールを調整します。
  • 権限の問題
    Apache の実行ユーザーと FastCGI プロセス(PHP-FPM のユーザー/グループ設定)が、対象のスクリプトファイルやディレクトリにアクセスできる権限を持っているか確認します。
  • SCRIPT_FILENAME の確認
    • ProxyPassMatch で以下のように FastCGI パスを明示的に指定している場合:
      ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/html/$1
      
      この場合、SCRIPT_FILENAME/var/www/html/ とリクエストされたファイル名 ($1) を結合したものになります。
    • もし ProxyPassMatch でパスを省略している場合(例: fcgi://127.00.1:9000)、Apache はデフォルトの SCRIPT_FILENAME を推測して送信します。この推測がアプリケーションと合わない場合、ProxyFCGISetEnvIf で明示的に設定する必要があります。
      # ドキュメントルートが /var/www/html/ で、FastCGI アプリケーションがファイル名を絶対パスで期待する場合
      ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{DOCUMENT_ROOT}%{REQUEST_URI}"
      
      または、アプリケーションによっては SCRIPT_FILENAMEREQUEST_FILENAME を使用する場合もあります。
      ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "%{REQUEST_FILENAME}"
      
    • Windows環境
      Windowsの場合、パスの区切り文字 (\/) に注意が必要です。設定ファイル内では通常 / を使用しますが、ProxyFCGISetEnvIf で環境変数に設定するパスでは、FastCGI アプリケーションが Windows のパス形式 (C:\path\to\file.php) を期待する場合、適切に変換する必要があります。
      ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "C:/path/to/www/%{REQUEST_URI}"
      
      または、ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "C:\\path\\to\\www\\%{REQUEST_URI}" のようにエスケープが必要な場合もあります。
  • ProxyPassMatch / ProxyPass のパス
    Apache の ProxyPassMatch または ProxyPass ディレクティブで指定されている FastCGI アドレスと、FastCGI アプリケーションが想定しているパス(特に SCRIPT_FILENAME のベースパス)が一致しているか確認します。
  • FastCGI バックエンドの起動状況確認
    PHP-FPM などの FastCGI プロセスが正しく起動しており、Apache が接続しようとしているポートまたはUnixソケットでリッスンしているか確認します。
    • systemctl status php-fpm (Systemdを使用している場合)
    • netstat -tulnp | grep 9000 (ポート9000でリッスンしているか確認)

環境変数が正しくFastCGIに渡されない

エラーの症状

  • アプリケーションが特定の環境変数を参照して動作するはずが、意図した通りに動作しない。
  • PHP の phpinfo()ProxyFCGISetEnvIf で設定した環境変数が表示されない、または期待しない値が表示される。

ProxyFCGISetEnvIf との関係
ProxyFCGISetEnvIf の条件式や値の式が正しくない場合に発生します。

トラブルシューティング

  • PHP_ADMIN_VALUE と PHP_VALUE
    PHP-FPM に PHP 設定を渡す場合、PHP_ADMIN_VALUE は管理者レベルの設定(php.iniPHP_INI_SYSTEMPHP_INI_PERDIR に設定されているもの)を上書きでき、PHP_VALUE はユーザーレベルの設定を上書きできます。設定したいPHPディレクティブがどちらのカテゴリに属するかを確認し、適切な環境変数名を使用します。
  • ディレクティブの配置場所
    ProxyFCGISetEnvIf<VirtualHost>, <Directory>, <Location> などのコンテキストで設定できます。特定のパスやホストに対してのみ適用したい場合、適切なコンテキストに配置されているか確認します。また、階層構造を持つ設定の場合、上位の設定が下位の設定によって上書きされる可能性があります。
  • ap_expr 構文の理解
    Apache の式構文 (ap_expr) のルールを正確に理解しているか確認します。特に文字列の連結、エスケープ、変数参照の方法に注意が必要です。
  • 値の式の確認
    value-expression で参照している変数 (%{REQUEST_URI} など) や正規表現のキャプチャグループが正しい値を持っているか確認します。
  • 条件式の確認
    conditional-expression が意図した通りに真(true)と評価されているか確認します。
    • 単純なテストとして、ProxyFCGISetEnvIf "true" MY_TEST_VAR "Hello" のように無条件で設定してみて、その変数が FastCGI アプリケーションで取得できるか確認します。
    • 正規表現を使用している場合、その正規表現が正しくマッチしているか、キャプチャグループ ($1 など) が意図した通りに機能しているかを確認します。
  • LogLevel debug または trace
    Apache のログレベルを一時的に LogLevel debug または LogLevel proxy_fcgi:trace6 のように上げて、Apache のエラーログを確認します。これにより、Apache が FastCGI バックエンドに送信する環境変数の詳細が表示されることがあります。
    # httpd.conf または該当する VirtualHost/Directory コンテキストに追記
    LogLevel debug proxy_fcgi:trace6
    
    ログには、以下のような情報が出力される可能性があります(環境によって出力形式は異なります):
    [proxy_fcgi:trace1] [pid 12345:tid 1234567890] mod_proxy_fcgi.c(xxx): [client 192.168.1.1:12345] Request FastCGI env variable: SCRIPT_FILENAME = /var/www/html/index.php
    [proxy_fcgi:trace1] [pid 12345:tid 1234567890] mod_proxy_fcgi.c(xxx): [client 192.168.1.1:12345] Request FastCGI env variable: PHP_ADMIN_VALUE = open_basedir=/path/to/app
    

予期せぬ動作や競合

症状

  • 特定のリクエストでのみ問題が発生する。
  • 複数の ProxyFCGISetEnvIf ディレクティブが同じ環境変数を設定しようとして、期待しない値が設定される。

ProxyFCGISetEnvIf との関係
複数のディレクティブの組み合わせや、条件式の重複/漏れによって発生します。

トラブルシューティング

  • !variable-name の使用
    環境変数を「設定しない(unset)」場合と「空の文字列に設定する」場合の違いを理解します。ProxyFCGISetEnvIf "true" !MY_VAR は変数を FastCGI に送信しません。一方、ProxyFCGISetEnvIf "true" MY_VAR "" は変数を空の文字列として送信します。アプリケーションがどちらを期待するかによって使い分ける必要があります。
  • 条件式の排他性
    複雑な条件分岐が必要な場合、ProxyFCGISetEnvIf の条件式が相互に排他的であるか、または意図した通りの優先順位で適用されるように設計されているか再確認します。
  • 設定の順序
    同じ環境変数に対して複数の ProxyFCGISetEnvIf ディレクティブがある場合、Apache の設定ファイルの読み込み順序によって、最後に評価されたディレクティブの値が適用されます。意図した通りの順序で評価されるか確認し、必要に応じて設定を整理します。

ProxyFCGISetEnvIf のトラブルシューティングは、主に以下の点に集約されます。

  1. FastCGI バックエンドが正常に動作しているか。
  2. Apache から FastCGI バックエンドへ、期待通りの環境変数が期待通りの値で渡されているか。


mod_proxy_fcgi: ProxyFCGISetEnvIf のプログラミング例

ProxyFCGISetEnvIf は、Apache HTTP Server の設定ファイル (httpd.conf や仮想ホストの設定ファイルなど) に記述するディレクティブであり、厳密な意味での「プログラミング」とは異なりますが、Apache の式構文 (ap_expr) を使用するため、条件分岐や値の動的な生成といったプログラミング的な思考が必要になります。

以下に、一般的なユースケースにおける設定例を示します。

前提

  • 以下の例は、主に仮想ホスト (<VirtualHost>) コンテキストでの使用を想定していますが、必要に応じて <Directory><Location> コンテキストでも使用できます。
  • FastCGI バックエンド (例: PHP-FPM) がポート 9000 でリッスンしている。
  • mod_proxymod_proxy_fcgi モジュールが有効になっている。
  • Apache HTTP Server が稼働している。

例1: 異なる仮想ホストでPHP設定を上書きする

PHP-FPM を使用している場合、PHP_ADMIN_VALUEPHP_VALUE 環境変数を使って、リクエストごとに PHP の設定を動的に変更できます。これは、異なるサイトで異なる memory_limitopen_basedir を適用したい場合に非常に便利です。

# ---------------------------------------------
# Virtual Host for example.com
# ---------------------------------------------
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example.com/public_html

    # FastCGI バックエンドへのプロキシ設定
    # .php ファイルへのリクエストを PHP-FPM に転送
    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/example.com/public_html/$1

    # example.com 専用の PHP 設定を環境変数で渡す
    # PHP_ADMIN_VALUE は php.ini の system/perdir ディレクティブを上書き可能
    ProxyFCGISetEnvIf "true" PHP_ADMIN_VALUE "open_basedir=/var/www/example.com/public_html/:/tmp/:/usr/share"
    # PHP_VALUE は user/perdir ディレクティブを上書き可能
    ProxyFCGISetEnvIf "true" PHP_VALUE "memory_limit=128M"
    ProxyFCGISetEnvIf "true" PHP_VALUE "upload_max_filesize=32M"

    <Directory /var/www/example.com/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
</VirtualHost>

# ---------------------------------------------
# Virtual Host for anothersite.net
# ---------------------------------------------
<VirtualHost *:80>
    ServerName anothersite.net
    DocumentRoot /var/www/anothersite.net/public_html

    # FastCGI バックエンドへのプロキシ設定 (別のドキュメントルートを PHP-FPM に指示)
    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/anothersite.net/public_html/$1

    # anothersite.net 専用の PHP 設定
    ProxyFCGISetEnvIf "true" PHP_ADMIN_VALUE "open_basedir=/var/www/anothersite.net/public_html/:/tmp/"
    ProxyFCGISetEnvIf "true" PHP_VALUE "memory_limit=256M"
    ProxyFCGISetEnvIf "true" PHP_VALUE "max_execution_time=60"

    <Directory /var/www/anothersite.net/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/anothersite.net_error.log
    CustomLog ${APACHE_LOG_DIR}/anothersite.net_access.log combined
</VirtualHost>

解説

  • ProxyPassMatch の最後の引数 /var/www/.../$1 は、FastCGI バックエンドに SCRIPT_FILENAME として渡されるファイルパスを決定しています。これは ProxyFCGISetEnvIf で直接設定する代わりに、ProxyPassMatch で簡単に指定できるため、この例ではそうしています。
  • PHP_ADMIN_VALUE はセミコロン ; 区切りで複数の設定を渡すことができますが、PHP_VALUE は通常1つのディレクティブに1つの環境変数として渡すのが一般的です。複数の ProxyFCGISetEnvIf を書くことで、別々に設定できます。
  • それぞれの仮想ホストブロック内で、ProxyFCGISetEnvIf "true" ... を使用して、無条件に PHP の設定ディレクティブを FastCGI バックエンドに渡しています。

例2: 特定のURIパターンに基づいて環境変数を設定する

リクエストされた URI やクエリ文字列などに基づいて、FastCGI に渡す環境変数を動的に変更したい場合に役立ちます。

<VirtualHost *:80>
    ServerName myapp.example.com
    DocumentRoot /var/www/myapp/public_html

    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/myapp/public_html/$1

    # /api/v1/ で始まるリクエストに対して、API_VERSION 環境変数を設定
    ProxyFCGISetEnvIf "%{REQUEST_URI} =~ m|^/api/v1/|" API_VERSION "1.0"

    # /admin/ で始まるリクエストに対して、IS_ADMIN 環境変数を "true" に設定
    ProxyFCGISetEnvIf "%{REQUEST_URI} =~ m|^/admin/|" IS_ADMIN "true"

    # クエリパラメータ 'debug=1' が存在する場合に DEBUG_MODE を設定
    ProxyFCGISetEnvIf "%{QUERY_STRING} =~ /(?:^|&)debug=1(?:&|$)/" DEBUG_MODE "on"

    <Directory /var/www/myapp/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/myapp.example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.example.com_access.log combined
</VirtualHost>

解説

  • これにより、アプリケーション側でこれらの環境変数 (API_VERSION, IS_ADMIN, DEBUG_MODE) を取得し、それに応じて動作を分岐させることができます。
  • ProxyFCGISetEnvIf の最初の引数である条件式に、%{REQUEST_URI}%{QUERY_STRING} といった Apache の変数と正規表現 (=~) を組み合わせています。

例3: PATH_INFO を手動で設定する

FastCGI アプリケーションが PATH_INFO を必要とする場合(例: example.com/index.php/some/path/some/path の部分)で、mod_proxy_fcgi が自動的に正しく設定しない場合に、明示的に設定します。

<VirtualHost *:80>
    ServerName myapp.example.com
    DocumentRoot /var/www/myapp/public_html

    # FastCGI バックエンドへのプロキシ
    # この ProxyPassMatch は、`SCRIPT_FILENAME` が `/var/www/myapp/public_html/index.php` になるようにする
    ProxyPassMatch ^/(index\\.php)(/.*)?$ fcgi://127.0.0.1:9000/var/www/myapp/public_html/$1

    # /index.php/ 形式のURLに対してPATH_INFOを設定
    # 条件式で正規表現のキャプチャグループ ($2) を使用して、/index.php/ の後のパスを取得
    ProxyFCGISetEnvIf "%{REQUEST_URI} =~ m|^/index\\.php(/.*)$|" PATH_INFO "$1"

    <Directory /var/www/myapp/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/myapp.example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp.example.com_access.log combined
</VirtualHost>

解説

  • $1 は、その正規表現によってキャプチャされた最初のグループ、つまり /some/path の部分を指します。これを PATH_INFO に設定しています。
  • ProxyFCGISetEnvIf の条件式 %^/index\\.php(/.*)$|" は、REQUEST_URI/index.php に続き、その後に何かパスがある場合にマッチします。
  • ProxyPassMatch の正規表現 ^/(index\\.php)(/.*)?$ は、index.php 自体と、その後のパス (/some/path) をそれぞれ $1$2 にキャプチャします。

例4: 環境変数を削除する (unset)

FastCGI バックエンドに渡したくない環境変数がある場合、感嘆符 ! を付けてその変数を解除できます。

<VirtualHost *:80>
    ServerName secureapp.example.com
    DocumentRoot /var/www/secureapp/public_html

    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/secureapp/public_html/$1

    # Apache がデフォルトで設定する可能性のある特定のCGI変数を FastCGI に渡さない
    ProxyFCGISetEnvIf "true" !HTTP_USER_AGENT
    ProxyFCGISetEnvIf "true" !SERVER_SOFTWARE

    # 必要に応じて、PHP-FPM の設定で自動的に渡される不要な PHP 変数を無効化
    # (例: PHP_AUTH_USER, PHP_AUTH_PW など)
    # これは通常、ProxyFCGISetEnvIf ではなく PHP-FPM の設定 (`php-fpm.conf`) で制御します。
    # 例: clear_env = no は環境変数を引き継ぐ、clear_env = yes は引き継がない (デフォルトは yes)
    # fastcgi.cgi_fix_pathinfo=1 の設定も考慮

    <Directory /var/www/secureapp/public_html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/secureapp.example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/secureapp.example.com_access.log combined
</VirtualHost>
  • ProxyFCGISetEnvIf "true" !HTTP_USER_AGENT は、常に HTTP_USER_AGENT 環境変数を FastCGI プロセスに送信しないようにします。セキュリティ上の理由や、アプリケーションが必要としない情報の場合に利用できます。
  • SCRIPT_FILENAME の重要性
    ほとんどの FastCGI アプリケーション(特に PHP)にとって、SCRIPT_FILENAME は処理すべきスクリプトの絶対パスを示す非常に重要な環境変数です。これが正しく渡されないと、「No input file specified」などのエラーが発生します。ProxyPassMatch でパスを明示的に指定するか、ProxyFCGISetEnvIf で正確に設定することを確認してください。
  • PHP-FPM の設定との連携
    ProxyFCGISetEnvIf は Apache 側での環境変数操作ですが、PHP-FPM 自体にも FastCGI 環境変数を処理する設定があります(例: fastcgi.param ディレクティブなど)。両者の設定が競合しないように注意してください。
  • ログレベルの調整
    問題が発生した場合、Apache の LogLeveldebugproxy_fcgi:trace6 に設定することで、Apache が FastCGI に送信する環境変数の詳細や処理フローを確認できます。
  • Apache の式構文 (ap_expr) の習得
    ProxyFCGISetEnvIf を最大限に活用するには、Apache の式構文を理解することが不可欠です。公式ドキュメントを参照して、利用可能な変数、関数、演算子を確認してください。


SetEnv および SetEnvIf/SetEnvIfExpr ディレクティブ

これは ProxyFCGISetEnvIf と非常によく似ていますが、FastCGI プロキシに限らず、Apache が処理するすべてのリクエストに環境変数を設定します。FastCGI へのプロキシ時にその変数を引き継ぎたい場合に利用できます。

  • SetEnvIfExpr: Apache の式構文 (ap_expr) を使用して、より複雑な条件に基づいて環境変数を設定します。これは ProxyFCGISetEnvIf の条件式とほぼ同じ機能を提供します。

    # リクエストメソッドが POST で、かつクエリ文字列に "action=upload" が含まれる場合
    SetEnvIfExpr "req_method == 'POST' && %{QUERY_STRING} =~ /action=upload/" UPLOAD_REQUEST=true
    

    用途
    ProxyFCGISetEnvIf と同様に複雑な条件に対応できます。

  • SetEnvIf: リクエストの属性(リクエストヘッダー、IPアドレス、URIなど)に基づいて環境変数を設定します。正規表現によるマッチングが可能です。

    # User-Agent が "Mobile" を含む場合に MOBILE_DEVICE 環境変数を設定
    SetEnvIf User-Agent "Mobile" MOBILE_DEVICE=1
    
    # 特定のURIパターンにマッチした場合に特別なフラグを設定
    SetEnvIf Request_URI "/api/v2/" API_V2_ENABLED=true
    

    用途
    ProxyFCGISetEnvIf と同様に条件に基づいて設定できますが、mod_setenvif モジュールが提供するより一般的な環境変数設定ディレクティブです。FastCGI プロキシだけでなく、Apache 内部の他のモジュール(例: mod_rewrite)でもこれらの環境変数を参照できます。

  • SetEnv: 無条件に環境変数を設定します。

    SetEnv MY_APP_ENV "production"
    

    用途
    常に同じ環境変数を設定したい場合にシンプルで便利です。ただし、特定の条件に基づいて設定したい場合は不向きです。

SetEnv / SetEnvIf と ProxyFCGISetEnvIf の違い

  • 特定のCGI環境変数(例: SCRIPT_FILENAME, PATH_INFO)については、ProxyFCGISetEnvIf の方が直接的で推奨される場合があります。
  • ProxyFCGISetEnvIf は、FastCGI に渡すCGI環境変数として明示的に指定し、その値を設定します。Apache 内部の環境変数とは独立して制御できます。
  • SetEnv/SetEnvIf で設定された環境変数は、FastCGI バックエンドに自動的に引き継がれるわけではありません(ただし、CGI 環境変数として渡されるものはあります)。mod_proxy_fcgi がプロキシする際に、これらの Apache 内部の環境変数を FastCGI 環境変数に変換する挙動に依存します。

mod_rewrite (RewriteRule の [E] フラグ)

mod_rewrite は URL の書き換えに非常に強力ですが、[E=VAR:VALUE] フラグを使って環境変数を設定することもできます。設定された環境変数は、CGI/FastCGI プログラムに渡されることがあります。

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html

    # /legacy-api/ で始まるリクエストの場合に、API_VERSION を "old" に設定
    RewriteEngine On
    RewriteRule ^/legacy-api/(.*)$ - [E=API_VERSION:old,PT]

    ProxyPassMatch ^/(.*\\.php)$ fcgi://127.0.0.1:9000/var/www/html/$1
</VirtualHost>

用途

  • RewriteCond を使って非常に複雑な条件を設定できます。
  • URL の書き換えと同時に環境変数を設定したい場合に便利です。

注意点

  • [PT] (Pass Through) フラグは、内部サブリクエストとして処理を続行し、ProxyPassMatch などの後続のディレクティブが処理できるようにするために重要です。
  • SetEnv などと同様に、設定された環境変数が確実に FastCGI バックエンドに渡されるかは、Apache のバージョンや設定に依存する場合があります。通常、標準的なCGI環境変数名であれば問題なく渡されます。

FastCGI アプリケーション自体の設定ファイル

PHP-FPM のような FastCGI プロセスは、通常、独自のプール設定ファイルを持っています。これらのファイルで、環境変数を設定したり、PHP の設定ディレクティブを直接指定したりできます。これは Apache 側で環境変数を操作するのではなく、FastCGI アプリケーション側で環境を調整する最も直接的な方法です。

PHP-FPM の例 (www.conf またはカスタムプール設定ファイル)

; /etc/php/8.x/fpm/pool.d/www.conf (または custom-site.conf など)

[www]
user = www-data
group = www-data
listen = /run/php/php8.x-fpm.sock
; listen = 127.0.0.1:9000

; 環境変数の設定
env[MY_CUSTOM_VAR] = "Value from FPM config"
env[APP_MODE] = "production"

; PHP 設定の直接指定
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_value[display_errors] = Off ; 開発環境では On にする

; 特定の FastCGI パラメータの設定 (例: SCRIPT_FILENAME のデフォルト)
; fastcgi_param[SCRIPT_FILENAME] = $document_root$fastcgi_script_name;
; 注: Apache の ProxyPassMatch で SCRIPT_FILENAME を渡す方が一般的です。

用途

  • Apache の式構文のような動的な条件設定はできませんが、最も確実で安定した方法です。
  • PHP の php.ini ディレクティブを、Web サーバー経由ではなく FPM の設定レベルで直接制御したい場合に非常に便利です。
  • 特定の FastCGI プール全体に適用される共通の設定や環境変数を定義する場合に最適です。

ProxyFCGISetEnvIf との使い分け

  • FastCGI 設定ファイル: FastCGI アプリケーション全体、または特定のプールに共通で適用される静的な設定を行いたい場合に適しています。プロセスユーザー、リスニングポート、一般的な PHP 設定など。
  • ProxyFCGISetEnvIf: リクエストのヘッダー、URI、IPアドレスなど、Apache が認識しているリクエスト固有の情報に基づいて、動的に環境変数を変更したい場合に適しています。仮想ホストごとやパスごとに異なる PHP 設定を適用する場合など。

最終的には、アプリケーションコード自身が、受け取った環境変数を読み取り、それに基づいて動作を決定します。アプリケーションのロジックがシンプルであれば、環境変数に頼らずに、URLパス、クエリパラメータ、HTTPヘッダーなどを直接解析して動作を分岐させることも可能です。

PHP の例:

<?php
// 環境変数を取得する
$app_env = getenv('MY_APP_ENV');
$api_version = getenv('API_VERSION');
$debug_mode = getenv('DEBUG_MODE'); // ProxyFCGISetEnvIf で設定されたもの

if ($debug_mode === 'on') {
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
}

if ($api_version === '1.0') {
    // API v1.0 のロジックを呼び出す
} else {
    // デフォルトまたは新しいAPIのロジック
}

// PHP-FPM の設定で渡されたもの
$memory_limit_fpm = ini_get('memory_limit');

echo "APP_ENV: " . $app_env . "<br>";
echo "API_VERSION: " . $api_version . "<br>";
echo "DEBUG_MODE: " . $debug_mode . "<br>";
echo "Memory Limit (from FPM/php.ini): " . $memory_limit_fpm . "<br>";

?>

用途

  • 一部のフレームワーク(Laravel, Symfonyなど)は、.env ファイルや環境変数を読み込む独自のメカニズムを持っています。
  • 環境変数の受け取りは最後の手段であり、より柔軟なロジックをアプリケーション側で実装できます。

ProxyFCGISetEnvIf は Apache の FastCGI プロキシ機能に特化して、リクエストの動的な特性に基づいて環境変数を設定する強力なツールです。しかし、その代替や補完として以下の方法が考えられます。

  • アプリケーションロジック内での直接処理
    環境変数に頼らず、リクエスト情報を直接解析
  • FastCGI プロセス(PHP-FPMなど)固有の設定
    FastCGI アプリケーションの設定ファイル (php-fpm.conf など)
  • URL書き換えと同時設定
    mod_rewrite[E] フラグ
  • リクエスト属性に基づく一般的な環境変数の設定
    SetEnvIf, SetEnvIfExpr
  • 静的または一般的な環境変数の設定
    SetEnv