リクエストヘッダーを操る!Apache mod_headers: RequestHeaderの基本と応用
Apache HTTP Server の mod_headers
モジュールは、HTTP リクエストおよびレスポンスのヘッダーを操作するための強力なツールです。このモジュールが提供するディレクティブの一つに RequestHeader
があります。
RequestHeader
ディレクティブは、クライアントからサーバーへのリクエストヘッダーを操作するために使用されます。具体的には、以下の3つの主要な操作が可能です。
- 追加 (add): 指定したヘッダーが存在しない場合に追加します。
- 設定 (set): 指定したヘッダーが存在する場合はその値を上書きし、存在しない場合は新しく追加します。
- 削除 (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
など)。
具体的な使用例
-
カスタムヘッダーの追加
特定の情報(例えば、ロードバランサーを経由したクライアントのIPアドレス)をバックエンドサーバーに伝えるためによく利用されます。RequestHeader set X-Forwarded-Proto "https"
この設定は、リクエストヘッダーに
X-Forwarded-Proto: https
を追加または設定します。これにより、バックエンドアプリケーションがSSL/TLSオフロードが行われたことを認識できます。 -
不要なヘッダーの削除
セキュリティ上の理由や、帯域幅の節約のために、特定のヘッダーを削除したい場合があります。RequestHeader unset User-Agent
これにより、クライアントから送られてくる
User-Agent
ヘッダーがバックエンドに転送されなくなります。 -
条件付きヘッダー操作
環境変数と組み合わせて、特定の条件が満たされた場合にのみヘッダーを操作することができます。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_headers
の RequestHeader
ディレクティブは、HTTP リクエストヘッダーを操作する上で重要な役割を果たしますが、以下のような一般的な問題に遭遇することがあります。
Invalid command 'RequestHeader' エラー
症状
Apache の設定ファイル(httpd.conf
や sites-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
モジュールがロードされていないために発生します。RequestHeader
は mod_headers
が提供するディレクティブです。
トラブルシューティング
- モジュールのロード確認
Apache の設定ファイルでmod_headers
がロードされているか確認します。通常、LoadModule headers_module modules/mod_headers.so
のような行があるはずです。この行がコメントアウトされているか、存在しない可能性があります。 - モジュールの有効化
- 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 を再起動します。
- Debian/Ubuntu の場合:
- モジュールファイルの確認
modules
ディレクトリ(Apache のインストールパスによって異なるが、通常は/usr/lib/apache2/modules/
や/etc/httpd/modules/
など)にmod_headers.so
ファイルが実際に存在するか確認します。ファイルが破損しているか、見つからない場合は、Apache の再インストールやパッケージの再インストールが必要になることがあります。
設定したはずのヘッダーが反映されない
症状
RequestHeader
ディレクティブを設定したにもかかわらず、バックエンドのアプリケーションや次のプロキシサーバーに、意図したヘッダーが送信されていない。
原因
複数の要因が考えられます。
- Header と RequestHeader の混同
レスポンスヘッダー (Header
ディレクティブ) とリクエストヘッダー (RequestHeader
ディレクティブ) を間違えている。 - 処理順序の問題
他のディレクティブ(mod_rewrite
など)との兼ね合いで、RequestHeader
の処理が意図したタイミングで行われていない。特にearly
やlate
オプションの理解不足。 - コンテキストの問題
RequestHeader
ディレクティブが、その効果が及ぶべきスコープ(VirtualHost, Directory, Location など)内に正しく記述されていない。 - 設定の適用漏れ
Apache の設定変更後に再起動/リロードを忘れている。 - キャッシュの問題
ブラウザや途中のプロキシがキャッシュを持っているため、古い情報が表示されている場合があります。
トラブルシューティング
- Apache の再起動/リロード
設定を変更したら、必ず Apache を再起動 (systemctl restart httpd
またはservice apache2 restart
) またはリロード (systemctl reload httpd
またはservice apache2 reload
) します。 - キャッシュのクリア
テスト時には、ブラウザのキャッシュを無効にするか、シークレットモード/プライベートブラウジングを使用するか、curl
コマンドでテストします。 例:curl -v http://your.domain.com/
(-v
オプションでリクエスト/レスポンスヘッダーを確認) - 設定ファイルの確認
RequestHeader
ディレクティブが、実際にリクエストを処理する VirtualHost や Location ブロック内に記述されているか確認します。early
やlate
オプションが適切に設定されているか確認します。通常はデフォルトで問題ありませんが、特定のモジュールとの連携が必要な場合は重要になります。- 環境変数 (
env=変数名
) を使用している場合、その環境変数が期待通りに設定されているか、mod_setenvif
などで正しくセットされているかを確認します。
- Apache のログを確認
LogLevel debug
を設定し、Apache のエラーログ(通常/var/log/httpd/error_log
や/var/log/apache2/error.log
)に詳細なデバッグ情報が出力されるようにします。ヘッダーの処理に関する情報が見つかる場合があります。mod_log_forensic
やmod_unique_id
などを使って、リクエストヘッダーや環境変数をログに出力し、実際に何が送られているかを確認します。
- Header ディレクティブとの区別
- クライアントからサーバーへのリクエストヘッダーを操作したい場合は
RequestHeader
を使用します。 - サーバーからクライアントへのレスポンスヘッダーを操作したい場合は
Header
を使用します。この違いを理解しているか確認します。
- クライアントからサーバーへのリクエストヘッダーを操作したい場合は
- 正規表現の誤り
RequestHeader edit
などで正規表現を使用している場合、その正規表現が意図した通りにマッチしているか、オンラインの正規表現テスターなどで確認します。
原因
HTTPヘッダーは通常、ASCII文字で構成されることを前提としています。非ASCII文字を直接ヘッダーに含めると、エンコーディングの問題が発生する可能性があります。
トラブルシューティング
- mod_headers の制限
mod_headers
自体は文字エンコーディングの変換機能を持たないため、文字化けを解決するには、エンコード/デコードをアプリケーション側で行うのが最も確実な方法です。
RequestHeader が mod_rewrite の環境変数を参照できない
症状
mod_rewrite
で設定した環境変数を RequestHeader
で参照しようとすると、期待する値がセットされない、または空になる。
原因
Apache の内部処理順序の問題です。mod_rewrite
による環境変数の設定と、mod_headers
によるヘッダー操作のタイミングが合わない場合があります。特に、リライトルールが内部リダイレクト([P]
フラグなど)を引き起こす場合、環境変数のスコープがリセットされることがあります。
- 処理順序の確認
RequestHeader
ディレクティブのearly
オプションとlate
オプションを試してみます。early
はリクエストの早い段階で処理され、late
は後の段階で処理されます。- 場合によっては、
mod_rewrite
で環境変数を設定した後に、すぐにRequestHeader
を適用する必要があるかもしれません。
- 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
- 代替手段の検討
- もし可能であれば、ヘッダーの設定を
mod_rewrite
以外(例:mod_setenvif
やmod_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-SSL
や X-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=)
SetEnvIf
や mod_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
コンテキストでのみ有効であり、Directory
や Location
などでは使用できない点に注意が必要です。
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_http
や mod_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 サーバーの設定とは別の場所で管理が必要になります。