リクエストヘッダーを操る!Apache mod_headers: RequestHeaderの基本と応用

2025-06-06

Apache HTTP Server の mod_headers モジュールは、HTTP リクエストおよびレスポンスのヘッダーを操作するための強力なツールです。このモジュールが提供するディレクティブの一つに RequestHeader があります。

RequestHeader ディレクティブは、クライアントからサーバーへのリクエストヘッダーを操作するために使用されます。具体的には、以下の3つの主要な操作が可能です。

  1. 追加 (add): 指定したヘッダーが存在しない場合に追加します。
  2. 設定 (set): 指定したヘッダーが存在する場合はその値を上書きし、存在しない場合は新しく追加します。
  3. 削除 (unset): 指定したヘッダーをリクエストから削除します。

使用例と解説

基本的な構文は以下のようになります。

RequestHeader add ヘッダー名 "値" [early|late|env=変数名]
RequestHeader set ヘッダー名 "値" [early|late|env=変数名]
RequestHeader append ヘッダー名 "値" [early|late|env=変数名]
RequestHeader unset ヘッダー名 [early|late|env=変数名]
  • [early|late|env=変数名]: オプションの引数で、ヘッダー操作が実行されるタイミングや、環境変数に基づいた条件付けを指定できます。
    • early: リクエスト処理の非常に早い段階で操作を行います。
    • late: より遅い段階(例えば、プロキシモジュールがリクエストを処理した後)で操作を行います。
    • env=変数名: 指定された環境変数が設定されている場合にのみ操作を実行します。
  • "値": add, set, append の場合、ヘッダーに設定する値。
  • ヘッダー名: 操作対象のHTTPヘッダーの名前(例: X-Forwarded-For, User-Agent など)。

具体的な使用例

  1. カスタムヘッダーの追加
    特定の情報(例えば、ロードバランサーを経由したクライアントのIPアドレス)をバックエンドサーバーに伝えるためによく利用されます。

    RequestHeader set X-Forwarded-Proto "https"
    

    この設定は、リクエストヘッダーに X-Forwarded-Proto: https を追加または設定します。これにより、バックエンドアプリケーションがSSL/TLSオフロードが行われたことを認識できます。

  2. 不要なヘッダーの削除
    セキュリティ上の理由や、帯域幅の節約のために、特定のヘッダーを削除したい場合があります。

    RequestHeader unset User-Agent
    

    これにより、クライアントから送られてくる User-Agent ヘッダーがバックエンドに転送されなくなります。

  3. 条件付きヘッダー操作
    環境変数と組み合わせて、特定の条件が満たされた場合にのみヘッダーを操作することができます。

    SetEnvIf Request_URI "/admin" IS_ADMIN
    RequestHeader set X-Custom-Auth "AdminAccess" env=IS_ADMIN
    

    この例では、URLが /admin を含む場合に IS_ADMIN 環境変数が設定され、その場合にのみ X-Custom-Auth ヘッダーが追加されます。

RequestHeader の目的と利点

RequestHeader ディレクティブの主な目的は以下の通りです。

  • デバッグとトラブルシューティング
    特定のヘッダーを追加して、リクエストがどのように処理されているかを追跡するのに役立ちます。
  • アプリケーションロジックの調整
    アプリケーションがヘッダー情報に基づいて動作する場合、RequestHeader を使って特定のヘッダーを追加または変更することで、アプリケーションの挙動を制御できます。
  • セキュリティの強化
    不要な情報を公開するヘッダーを削除することで、セキュリティリスクを軽減できます。
  • プロキシ環境での情報伝達
    ロードバランサーやリバースプロキシの背後にあるサーバーに対して、クライアントのオリジナルIPアドレス(X-Forwarded-For)やプロトコル(X-Forwarded-Proto)などの重要な情報を受け渡すことができます。


mod_headersRequestHeader ディレクティブは、HTTP リクエストヘッダーを操作する上で重要な役割を果たしますが、以下のような一般的な問題に遭遇することがあります。

Invalid command 'RequestHeader' エラー

症状
Apache の設定ファイル(httpd.confsites-enabled 内の VirtualHost 設定など)に RequestHeader ディレクティブを記述すると、Apache の起動時や設定テスト時(apachectl configtest または httpd -t)に Invalid command 'RequestHeader', perhaps misspelled or defined by a module not included in the server configuration のようなエラーが表示される。

原因
mod_headers モジュールがロードされていないために発生します。RequestHeadermod_headers が提供するディレクティブです。

トラブルシューティング

  1. モジュールのロード確認
    Apache の設定ファイルで mod_headers がロードされているか確認します。通常、LoadModule headers_module modules/mod_headers.so のような行があるはずです。この行がコメントアウトされているか、存在しない可能性があります。
  2. モジュールの有効化
    • Debian/Ubuntu の場合: sudo a2enmod headers を実行し、その後 sudo service apache2 restart または sudo systemctl restart apache2 で Apache を再起動します。
    • CentOS/RHEL の場合: httpd.conf または conf.modules.d/*.conf 内で LoadModule headers_module modules/mod_headers.so の行が有効になっていることを確認します。変更後、sudo systemctl restart httpd で Apache を再起動します。
  3. モジュールファイルの確認
    modules ディレクトリ(Apache のインストールパスによって異なるが、通常は /usr/lib/apache2/modules//etc/httpd/modules/ など)に mod_headers.so ファイルが実際に存在するか確認します。ファイルが破損しているか、見つからない場合は、Apache の再インストールやパッケージの再インストールが必要になることがあります。

設定したはずのヘッダーが反映されない

症状
RequestHeader ディレクティブを設定したにもかかわらず、バックエンドのアプリケーションや次のプロキシサーバーに、意図したヘッダーが送信されていない。

原因
複数の要因が考えられます。

  • Header と RequestHeader の混同
    レスポンスヘッダー (Header ディレクティブ) とリクエストヘッダー (RequestHeader ディレクティブ) を間違えている。
  • 処理順序の問題
    他のディレクティブ(mod_rewrite など)との兼ね合いで、RequestHeader の処理が意図したタイミングで行われていない。特に earlylate オプションの理解不足。
  • コンテキストの問題
    RequestHeader ディレクティブが、その効果が及ぶべきスコープ(VirtualHost, Directory, Location など)内に正しく記述されていない。
  • 設定の適用漏れ
    Apache の設定変更後に再起動/リロードを忘れている。
  • キャッシュの問題
    ブラウザや途中のプロキシがキャッシュを持っているため、古い情報が表示されている場合があります。

トラブルシューティング

  1. Apache の再起動/リロード
    設定を変更したら、必ず Apache を再起動 (systemctl restart httpd または service apache2 restart) またはリロード (systemctl reload httpd または service apache2 reload) します。
  2. キャッシュのクリア
    テスト時には、ブラウザのキャッシュを無効にするか、シークレットモード/プライベートブラウジングを使用するか、curl コマンドでテストします。 例: curl -v http://your.domain.com/ (-v オプションでリクエスト/レスポンスヘッダーを確認)
  3. 設定ファイルの確認
    • RequestHeader ディレクティブが、実際にリクエストを処理する VirtualHost や Location ブロック内に記述されているか確認します。
    • earlylate オプションが適切に設定されているか確認します。通常はデフォルトで問題ありませんが、特定のモジュールとの連携が必要な場合は重要になります。
    • 環境変数 (env=変数名) を使用している場合、その環境変数が期待通りに設定されているか、mod_setenvif などで正しくセットされているかを確認します。
  4. Apache のログを確認
    • LogLevel debug を設定し、Apache のエラーログ(通常 /var/log/httpd/error_log/var/log/apache2/error.log)に詳細なデバッグ情報が出力されるようにします。ヘッダーの処理に関する情報が見つかる場合があります。
    • mod_log_forensicmod_unique_id などを使って、リクエストヘッダーや環境変数をログに出力し、実際に何が送られているかを確認します。
  5. Header ディレクティブとの区別
    • クライアントからサーバーへのリクエストヘッダーを操作したい場合は RequestHeader を使用します。
    • サーバーからクライアントへのレスポンスヘッダーを操作したい場合は Header を使用します。この違いを理解しているか確認します。
  6. 正規表現の誤り
    RequestHeader edit などで正規表現を使用している場合、その正規表現が意図した通りにマッチしているか、オンラインの正規表現テスターなどで確認します。

原因
HTTPヘッダーは通常、ASCII文字で構成されることを前提としています。非ASCII文字を直接ヘッダーに含めると、エンコーディングの問題が発生する可能性があります。

トラブルシューティング

  1. mod_headers の制限
    mod_headers 自体は文字エンコーディングの変換機能を持たないため、文字化けを解決するには、エンコード/デコードをアプリケーション側で行うのが最も確実な方法です。

RequestHeader が mod_rewrite の環境変数を参照できない

症状
mod_rewrite で設定した環境変数を RequestHeader で参照しようとすると、期待する値がセットされない、または空になる。

原因
Apache の内部処理順序の問題です。mod_rewrite による環境変数の設定と、mod_headers によるヘッダー操作のタイミングが合わない場合があります。特に、リライトルールが内部リダイレクト([P] フラグなど)を引き起こす場合、環境変数のスコープがリセットされることがあります。

  1. 処理順序の確認
    • RequestHeader ディレクティブの early オプションと late オプションを試してみます。early はリクエストの早い段階で処理され、late は後の段階で処理されます。
    • 場合によっては、mod_rewrite で環境変数を設定した後に、すぐに RequestHeader を適用する必要があるかもしれません。
  2. RewriteRule の [E] フラグ
    mod_rewrite で環境変数を設定する際に、RewriteRule[E=変数名:値] フラグを使用していることを確認します。このフラグは、内部リダイレクト時でも環境変数を保持するのに役立つことがあります。
    RewriteEngine On
    RewriteCond %{QUERY_STRING} ^foo=(.*)$
    RewriteRule ^ - [E=MY_VAR:%1]
    RequestHeader set X-My-Header "%{MY_VAR}e" env=MY_VAR
    
  3. 代替手段の検討
    • もし可能であれば、ヘッダーの設定を mod_rewrite 以外(例: mod_setenvifmod_rewrite 以外で設定可能な環境変数)で行うことを検討します。
    • または、Apache 側でヘッダーを設定するのではなく、バックエンドのアプリケーション側で必要な情報を取得し、ヘッダーを生成するロジックを実装することも有効です。

一般的なデバッグのヒント

  • 開発者ツール/curl の活用
    Web ブラウザの開発者ツール(ネットワークタブ)や curl -v コマンドを使用して、実際にクライアントから送信されているリクエストヘッダーや、Apache を経由してバックエンドに到達しているリクエストヘッダーを確認します。特にプロキシ環境では、Apache とバックエンド間のトラフィックをキャプチャして確認することも有効です。
  • 単体テスト
    問題の原因を特定するために、影響を受けている RequestHeader ディレクティブのみを残し、他の設定を一時的に無効にしてテストします。
  • 構文チェック
    apachectl configtest または httpd -t を実行して、設定ファイルの構文エラーがないか常に確認します。
  • Apache のログレベルを上げる
    LogLevel debug に設定すると、詳細な情報がエラーログに出力されます。デバッグが終了したら元に戻すことを忘れないでください。


RequestHeader ディレクティブは、Apache の設定ファイル(httpd.conf、VirtualHost 設定ファイル、または .htaccess ファイルなど)に記述されます。使用する前に、mod_headers モジュールがロードされていることを確認してください。

# mod_headers モジュールをロードする (httpd.conf の先頭付近で確認)
# LoadModule headers_module modules/mod_headers.so

ヘッダーを追加する (add)

指定したヘッダーが存在しない場合のみ、そのヘッダーを追加します。既に同じ名前のヘッダーが存在する場合は、何も起こりません(ただし、add の代わりに append を使うと重複して追加されます)。

例: カスタムヘッダー X-Client-Info を追加する

# すべてのリクエストに X-Client-Info ヘッダーを追加
RequestHeader add X-Client-Info "MyApplication/1.0"

これにより、すべてのHTTPリクエストに以下のヘッダーが追加されます。

X-Client-Info: MyApplication/1.0

ヘッダーを設定・上書きする (set)

指定したヘッダーが存在する場合はその値を上書きし、存在しない場合は新しく追加します。最も一般的な操作です。

例1: X-Forwarded-Proto ヘッダーを設定する(SSLオフロード環境向け)

ロードバランサーやリバースプロキシの背後でApacheが動作している場合、クライアントとロードバランサー間がHTTPSでも、ApacheにはHTTPでリクエストが届くことがあります。この場合、バックエンドアプリケーションが正しいプロトコルを認識できるように X-Forwarded-Proto を設定します。

<VirtualHost *:80>
    ServerName yourdomain.com
    # HTTPでアクセスされた場合
    RequestHeader set X-Forwarded-Proto "http"
    # その他の設定...
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    SSLEngine on
    # HTTPSでアクセスされた場合
    RequestHeader set X-Forwarded-Proto "https"
    # その他の設定...
</VirtualHost>

または、ロードバランサーが送信する X-Forwarded-SSLX-Forwarded-Port などのヘッダーを元に判断することもできます。

# ELB (Elastic Load Balancer) などが設定するヘッダーを利用
RequestHeader set X-Forwarded-Proto "https" env=HTTPS
# HTTPS環境変数が設定されている場合(SSL接続時)のみ "https" をセット

例2: Host ヘッダーを変更する(プロキシ設定など)

プロキシの背後で特定のバックエンドサーバーにリクエストを転送する際、Host ヘッダーをバックエンドサーバーのホスト名に書き換えたい場合があります。

<Location /app/>
    ProxyPass http://backend-server.example.com/
    ProxyPassReverse http://backend-server.example.com/
    # Host ヘッダーをバックエンドサーバーのものに書き換える
    RequestHeader set Host "backend-server.example.com"
</Location>

ヘッダーを削除する (unset)

指定したヘッダーをリクエストから完全に削除します。

例: User-Agent ヘッダーを削除する

バックエンドのロギングや処理で User-Agent 情報が不要な場合や、プライバシー保護のために削除したい場合に利用します。

RequestHeader unset User-Agent

ヘッダーの値を編集する (edit)

正規表現を使って、既存のヘッダーの値を置換します。

例: Destination ヘッダーのスキームを https: から http: に書き換える

これは、DAV (WebDAV) クライアントがHTTPS経由で接続しているが、バックエンドのApacheがHTTPでDAVを処理する場合などに役立ちます。

RequestHeader edit Destination ^https: http: early
  • early: この操作をリクエスト処理の早い段階で実行することを指定します。
  • http:: 置換後の文字列。
  • ^https:: マッチさせる正規表現。文字列の先頭が https: であることを意味します。

環境変数に基づいてヘッダーを操作する (env=)

SetEnvIfmod_rewrite などで設定された環境変数の値に基づいて、ヘッダーの操作を行うことができます。

例: 特定のURIへのリクエストの場合のみカスタムヘッダーを追加する

# /admin/ 以下のURIへのリクエストの場合に IS_ADMIN 環境変数をセット
SetEnvIf Request_URI "^/admin/" IS_ADMIN

# IS_ADMIN 環境変数が設定されている場合のみ X-Admin-Access ヘッダーを追加
RequestHeader set X-Admin-Access "true" env=IS_ADMIN

この設定では、http://yourdomain.com/admin/dashboard のようなURIにアクセスがあった場合に、リクエストヘッダーに X-Admin-Access: true が追加されます。

既存のヘッダーに値を追加する (append)

同じ名前のヘッダーが既に存在する場合、そのヘッダーの値に新しい値をコンマで区切って追加します。HTTPヘッダーの仕様上、同じヘッダー名を複数回使用するのではなく、コンマで区切るのが一般的な形式です。

例: Cache-Control ヘッダーに no-cache を追加する

元々 Cache-Control: public が設定されているリクエストに、さらに no-Control: no-cache を追加したい場合。

RequestHeader append Cache-Control "no-cache"

元のリクエストヘッダーが Cache-Control: public の場合、最終的なリクエストヘッダーは Cache-Control: public, no-cache となります。

設定場所の考慮

RequestHeader ディレクティブは以下のコンテキストで使用できます。

  • .htaccess (ただし AllowOverride FileInfo が必要)
  • directory (<Directory> ブロック内)
  • virtual host (<VirtualHost> ブロック内)
  • server config (サーバー全体の設定)

設定の順序とコンテキストは重要です。特に early オプションを使用する場合、VirtualHost コンテキストでのみ有効であり、DirectoryLocation などでは使用できない点に注意が必要です。



mod_rewrite を使用する

mod_rewrite は URL の書き換えに非常に強力なモジュールですが、環境変数を設定する機能も持っており、これを利用して間接的にヘッダー操作を行うことができます。

方法
RewriteRule[E] フラグ(環境変数設定)と、その環境変数を参照する RequestHeader を組み合わせる。


特定のパスにアクセスがあった場合にカスタムヘッダーを追加する

# mod_rewrite を有効にする
RewriteEngine On

# /api/v1/ のパスにマッチしたら MY_API_REQUEST 環境変数をセット
RewriteRule ^/api/v1/ - [E=MY_API_REQUEST:true,L]

# MY_API_REQUEST 環境変数がセットされていたら X-Custom-Header を追加
RequestHeader set X-Custom-Header "API-Access" env=MY_API_REQUEST

利点

  • ヘッダー操作だけでなく、同時に URL の書き換えも行いたい場合に便利です。
  • URL パス、クエリ文字列、User-Agent など、より複雑な条件に基づいてヘッダー操作を行いたい場合に強力です。

欠点

  • mod_rewrite の処理順序を理解している必要があります。
  • RequestHeader を直接使用するよりも設定が複雑になる場合があります。

mod_setenvif を使用する

方法
SetEnvIf または SetEnvIfNoCase で条件を設定し、環境変数をセット。その後、RequestHeader でその環境変数を参照する。


特定の User-Agent からのリクエストの場合にカスタムヘッダーを追加する

# Chrome ブラウザからのリクエストの場合に IS_CHROME 環境変数をセット
SetEnvIf User-Agent "Chrome" IS_CHROME

# IS_CHROME 環境変数がセットされていたら X-Browser-Type を追加
RequestHeader set X-Browser-Type "Chrome" env=IS_CHROME

利点

  • 主にリクエスト属性(ヘッダー、URI、リクエストメソッドなど)に基づいた環境変数設定に特化しています。
  • mod_rewrite よりも直感的に条件を設定できます。

欠点

  • 複雑なロジック(例: OR条件、AND条件の多重化)になると設定が煩雑になることがあります。

mod_proxy_http や mod_proxy_wstunnel の ProxyRequestHeader (Apache 2.4以降)

mod_proxy_httpmod_proxy_wstunnel など、プロキシ関連のモジュールには ProxyRequestHeader ディレクティブが存在します。これは、Apache がバックエンドサーバーに転送する際に、プロキシリクエストのヘッダーを操作するためのものです。RequestHeader が Apache がリクエストを受け取った時点で操作するのに対し、ProxyRequestHeader はプロキシ転送時に操作します。

方法
ProxyRequestHeader ディレクティブを使用する。


バックエンドへのプロキシリクエストに X-Backend-Auth ヘッダーを追加する

<Location /proxy-app/>
    ProxyPass http://backend.example.com/
    ProxyPassReverse http://backend.example.com/
    # プロキシ転送時に X-Backend-Auth ヘッダーを追加
    ProxyRequestHeader set X-Backend-Auth "secure-token"
</Location>

利点

  • 特にマルチホッププロキシ環境で、各プロキシ段階でヘッダーを調整するのに便利です。
  • プロキシ機能と密接に連携しており、バックエンドへのリクエストに特化したヘッダー操作を行えます。

欠点

  • クライアントから Apache への最初のリクエストヘッダーを操作する目的には適していません。
  • プロキシ機能を使用している場合にのみ適用可能です。

アプリケーション層でのヘッダー操作

Apache ではなく、Apache の背後で動作するアプリケーション(PHP, Python, Node.js, Java など)でリクエストヘッダーを読み取り、必要に応じて新しいリクエストヘッダーを作成して、次のサービスに転送することも可能です。

方法
アプリケーションのコード内でHTTPヘッダーを読み書きする。

例 (PHP)
Apache からの X-Forwarded-For ヘッダーを読み取り、新しいヘッダーを追加して次のサービスに転送する(これは通常、自身がプロキシになる場合に行う)。

<?php
// Apache (mod_headers) で設定されたヘッダーを取得
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];

// 新しいリクエストを作成し、カスタムヘッダーを追加して次のサービスに転送
$ch = curl_init('http://next-service.example.com/endpoint');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "X-Client-Real-IP: " . $client_ip,
    "X-App-Version: 2.0"
]);
$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

利点

  • HTTP ヘッダーだけでなく、リクエストボディの内容に基づいてヘッダーを生成するなど、高度な処理が可能です。
  • 最も柔軟性が高く、複雑なロジックやデータベースの参照などに基づいてヘッダーを動的に生成できます。

欠点

  • パフォーマンス面で、Apache のモジュールで行うよりもオーバーヘッドが発生する可能性があります。
  • Apache 単独では完結せず、アプリケーション側の開発が必要になります。

ロードバランサー/リバースプロキシでのヘッダー操作

Apache の手前に Nginx や HAProxy、クラウドプロバイダーのロードバランサー(AWS ALB/ELB, GCP Load Balancer など)がある場合、それらのレイヤーでリクエストヘッダーを操作することが可能です。

方法
ロードバランサー/リバースプロキシの設定を使用する。

例 (Nginx)

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        # クライアントのオリジナルのIPを転送
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # SSL/TLSオフロードが行われたことを転送
        proxy_set_header X-Forwarded-Proto $scheme;
        # カスタムヘッダーを追加
        proxy_set_header X-Nginx-Gateway "true";
        proxy_pass http://backend_apache;
    }
}

利点

  • 特定のクラウド環境に最適化された機能を利用できます。
  • マイクロサービスアーキテクチャや大規模なシステムで、リクエストヘッダーの一元的な管理や標準化に適しています。
  • Apache の負荷を軽減できます。
  • インフラストラクチャ全体の設計に影響を与えます。
  • Apache サーバーの設定とは別の場所で管理が必要になります。