mod_proxy: ProxyDomain

2025-05-26

mod_proxy: ProxyDomainとは何か?

ProxyDomainは、Apache HTTP Serverのmod_proxyモジュールでかつて使用されていたディレクティブです。現在では非推奨 (deprecated) となっており、ほとんどの場合、使用すべきではありません

このディレクティブの目的は、プロキシされたリクエストのHTTPヘッダーにあるHostヘッダーを、指定されたドメイン名に書き換えることでした。具体的には、Apacheがリバースプロキシとして機能し、バックエンドのアプリケーションサーバーにリクエストを転送する際に、リクエストが本来意図していたドメイン名をバックエンドサーバーに伝えるために使われました。

なぜ非推奨になったのか?

ProxyDomainが非推奨になった主な理由は、その動作が多くのケースで意図しない副作用を引き起こす可能性があり、より柔軟で標準的なヘッダー操作の方法が導入されたためです。

  • 代替手段の存在
    現在では、ProxyPreserveHost Onディレクティブを使用することで、クライアントから送られてきたオリジナルのHostヘッダーをそのままバックエンドサーバーに転送することが推奨されています。もしHostヘッダーを変更する必要がある場合は、mod_headersモジュールとRequestHeaderディレクティブを組み合わせて、より細かく制御することが可能です。
  • 不透明なプロキシ
    mod_proxyは、通常、クライアントからのリクエストをそのままバックエンドサーバーに転送する「不透明なプロキシ」として機能することが期待されます。Hostヘッダーの変更は、この不透明性を損なうことがあります。
  • Hostヘッダーの変更
    ProxyDomainは強制的にHostヘッダーを書き換えますが、これはバックエンドサーバーがそのHostヘッダーに依存して動作する場合(例えば、バーチャルホストのルーティングなど)に問題を引き起こす可能性がありました。

現在、リバースプロキシを設定する際には、以下のディレクティブを使用することが一般的です。

  1. ProxyPreserveHost On (推奨) これは、クライアントから送られてきたHostヘッダーを変更せずにそのままバックエンドサーバーに転送します。ほとんどのリバースプロキシのユースケースでこれが望ましい動作です。

    <VirtualHost *:80>
        ServerName example.com
        ProxyPreserveHost On
        ProxyPass / http://backend-server.local/
        ProxyPassReverse / http://backend-server.local/
    </VirtualHost>
    
  2. mod_headersモジュールとRequestHeaderディレクティブ もし、バックエンドサーバーに特定のHostヘッダーを送信する必要があるが、それはオリジナルのクライアントからのHostヘッダーとは異なる場合、mod_headersモジュールを使ってRequestHeaderディレクティブで明示的に設定します。

    <VirtualHost *:80>
        ServerName example.com
        ProxyPass / http://backend-server.local/
        ProxyPassReverse / http://backend-server.local/
        RequestHeader set Host "desired-backend-host.local"
    </VirtualHost>
    

    この設定は、クライアントからのHostヘッダーにかかわらず、バックエンドサーバーには常にdesired-backend-host.localというHostヘッダーが送信されます。

ProxyDomainディレクティブは、Apache HTTP Serverのmod_proxyにおいて、プロキシされるリクエストのHostヘッダーを強制的に書き換えるために使われていましたが、現在では非推奨です。



Apache HTTP Server の mod_proxy: ProxyDomain ディレクティブは、現在では非推奨 (deprecated) となっており、ほとんどの場合、使用すべきではありません。そのため、これに関連する「一般的なエラーとトラブルシューティング」は、ProxyDomainが使われていた古い環境や、それを誤って現在の環境で使ってしまった場合に発生する問題、という文脈で捉える必要があります。

もし、意図的にProxyDomainを使おうとしているのであれば、それはお勧めできません。より新しい、推奨される設定方法(ProxyPreserveHost OnRequestHeader set Host)を使用すべきです。

しかし、もし古いシステムを引き継いだり、誤ってProxyDomainを使用した場合に遭遇する可能性のある問題と、そのトラブルシューティングについて解説します。

mod_proxy: ProxyDomain に関する一般的なエラーとトラブルシューティング (非推奨ディレクティブの文脈で)

ProxyDomainは、バックエンドサーバーに転送されるリクエストのHostヘッダーを強制的に書き換える機能を持っていました。この機能が意図しない挙動を引き起こすことが、主な問題の原因でした。

エラーメッセージ: Invalid command 'ProxyDomain' または Apache 起動失敗

これは最も直接的なエラーです。Apache のバージョンが新しい場合、ProxyDomainディレクティブはもはや認識されません。

  • トラブルシューティング
    • 設定ファイルからProxyDomainを削除する。
    • 代わりに、ProxyPreserveHost On を使用するか、mod_headersモジュールのRequestHeader set Hostディレクティブで必要なHostヘッダーを明示的に設定する。
    • Apache のエラーログ (error_log) を確認し、具体的なエラーメッセージ(どの行に問題があるかなど)を特定する。
  • 原因
    Apache HTTP Server のバージョンが、ProxyDomainディレクティブが削除されたバージョン(Apache 2.4以降など)である。

バックエンドサーバーでのホスト名不一致によるエラー (400 Bad Request, 404 Not Found など)

ProxyDomainの機能は、バックエンドサーバーが特定のHostヘッダーに依存してコンテンツを提供するバーチャルホスト構成の場合に、問題を引き起こす可能性がありました。

  • トラブルシューティング
    • ProxyDomainの使用を中止し、ProxyPreserveHost Onを設定する。 これにより、クライアントがリクエストしたオリジナルのHostヘッダーがバックエンドに転送されます。
    • もし、バックエンドサーバーが特定のHostヘッダーを必要とするが、それがオリジナルのリクエストのHostヘッダーと異なる場合は、ProxyPreserveHost Off(または設定しない)にした上で、RequestHeader set Host "バックエンドが期待するホスト名" を使用して明示的にHostヘッダーを設定する。
    • バックエンドサーバーのアクセスログやエラーログを確認し、どのようなHostヘッダーでリクエストを受信しているかを確認する。
  • 原因
    • ProxyDomainで指定したドメイン名が、バックエンドサーバーの期待するホスト名と一致していない。
    • バックエンドサーバーが、プロキシ元のオリジナルのHostヘッダーを期待しているにも関わらず、ProxyDomainがそれを書き換えてしまった。

リダイレクトループまたは不適切なリダイレクト

バックエンドアプリケーションが絶対URLでリダイレクトを行う場合、ProxyDomainの設定が原因で問題が発生することがありました。

  • トラブルシューティング
    • ProxyPassReverseディレクティブが正しく設定されていることを確認する。 ProxyPassReverseは、バックエンドサーバーからのリダイレクト応答のLocationヘッダーをApacheが書き換えるようにします。
      # 例:
      ProxyPass / http://backend-server.local/
      ProxyPassReverse / http://backend-server.local/
      # ProxyPassReverse は、バックエンドが返す "Location: http://backend-server.local/path" を
      # "Location: http://your-proxy-domain.com/path" のように書き換える
      
    • ProxyDomainを使用せず、ProxyPreserveHost OnProxyPassReverseの組み合わせを優先する。
    • 場合によっては、バックエンドアプリケーションのリダイレクトURL生成ロジックを調整する必要があることもあります。
  • 原因
    • バックエンドアプリケーションが、自分自身が認識しているURL(ProxyDomainによって書き換えられたHostヘッダーに基づく)でリダイレクトを発行し、それがApacheのプロキシ設定と競合する。
    • 例えば、ProxyDomainbackend.example.comと指定したが、バックエンドアプリケーションはwww.example.comとしてリダイレクトを生成するため、クライアントが無限ループに陥る、または間違ったURLに飛ばされる。

セキュリティ上の懸念 (オープンプロキシ)

ProxyDomain自体が直接オープンプロキシを引き起こすわけではありませんが、mod_proxyの不適切な設定と組み合わさることで、セキュリティ上のリスクを高める可能性がありました。

  • トラブルシューティング
    • リバースプロキシとして使用する場合、ProxyRequests Offが設定されていることを必ず確認する。 これは非常に重要です。
    • <Proxy>コンテナやRequireディレクティブを用いて、プロキシへのアクセスを制限する(例: Require ip 127.0.0.1Require all granted の代わりに特定のIPアドレスやネットワークからのアクセスのみを許可する)。
    • 不要なmod_proxyサブモジュール(例: mod_proxy_ftp, mod_proxy_connect など)をロードしない。
  • 原因
    • ProxyRequests Onが有効になっている(これは通常、フォワードプロキシ用であり、リバースプロキシではOffにすべき)。
    • ProxyDomainや他の設定が、外部からの不特定多数のリクエストを許可してしまう。

ProxyDomainに特化したエラーだけでなく、mod_proxy全般のトラブルシューティングに役立つ一般的なヒントを以下に示します。

    • 最も重要な情報源です。何が問題なのか、どのモジュールやディレクティブが関係しているのか、具体的なエラーコード(AHxxxx)などが記載されています。
    • ログレベルをLogLevel debugに一時的に上げて、より詳細な情報を取得することも有効です(ただし、運用環境では元に戻すこと)。
  1. 設定ファイルの構文チェックを行う。

    • apachectl configtest または httpd -t コマンドを使用して、設定ファイルの構文エラーがないか確認します。
    • 構文エラーがあれば、Apache は起動できません。
  2. mod_proxyおよび必要なサブモジュールがロードされているか確認する。

    • LoadModule proxy_module modules/mod_proxy.so
    • LoadModule proxy_http_module modules/mod_proxy_http.so (HTTP/HTTPSプロキシの場合)
    • apachectl -M コマンドで、ロードされているモジュールの一覧を確認できます。
  3. ProxyPassProxyPassReverseの順序とパスを確認する。

    • より具体的なProxyPassルール(長いパス)は、より一般的なルール(短いパス)の前に記述する必要があります。
    • 例: /app/subpath のプロキシは /app のプロキシより前に記述。
    • パスの末尾のスラッシュの有無も重要です。
  4. バックエンドサーバーの状態を確認する。

    • Apache がプロキシしようとしているバックエンドサーバーが、実際に稼働しているか、指定されたポートでリクエストを受け付けているかを確認します。
    • Apache サーバーからcurl http://backend-server.local:ポート/ のように直接アクセスしてみて、応答があるか確認すると良いでしょう。
  5. ネットワークの問題を確認する。

    • Apache サーバーからバックエンドサーバーへのネットワーク接続が確立されているか(ファイアウォール、ルーティングなど)を確認します。
    • telnet backend-server.local ポート で接続を試みるのも有効です。


まず、重要な注意点ですが、ProxyDomain ディレクティブは現在、非推奨 (deprecated) であり、新しい Apache 環境では使用すべきではありません。多くの Apache 2.4 以降のバージョンでは、このディレクティブはもはや認識されず、設定エラーとなります。

しかし、もし古いシステムを引き継いだり、なぜこのディレクティブが存在したのかを理解するために、かつてどのように使われていたかを示す「例示コード」を説明します。

ProxyDomain ディレクティブの主な目的は、Apache がリバースプロキシとして機能する際に、バックエンドサーバーに転送される HTTP リクエストの Host ヘッダーを強制的に指定したドメイン名に書き換えることでした。

例 1: 最も基本的な ProxyDomain の使用

この例では、http://www.example.com/app/ へのリクエストが、内部のバックエンドサーバー http://backend-app.internal/ にプロキシされます。この際、バックエンドサーバーには Host: internal-app.com というヘッダーが送信されます。

# 必要なモジュールのロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>
    ServerName www.example.com
    #ServerAlias example.com

    # !!! 非推奨のディレクティブ: 目的はHostヘッダーの書き換え !!!
    # この設定により、バックエンドに送られるリクエストのHostヘッダーが
    # 'Host: internal-app.com' に書き換えられます。
    ProxyDomain internal-app.com

    # /app/ へのリクエストを http://backend-app.internal/ へプロキシ
    ProxyPass /app/ http://backend-app.internal/
    # バックエンドからのリダイレクトのLocationヘッダーを書き換える
    ProxyPassReverse /app/ http://backend-app.internal/

    # リバースプロキシでは通常オフにする
    ProxyRequests Off

    ErrorLog ${APACHE_LOG_DIR}/proxy_domain_error.log
    CustomLog ${APACHE_LOG_DIR}/proxy_domain_access.log combined
</VirtualHost>

解説

  • ProxyPassReverse /app/ http://backend-app.internal/: バックエンドからのリダイレクトレスポンスに含まれる Location ヘッダー(例: Location: http://backend-app.internal/login)を、クライアント向け(例: Location: http://www.example.com/app/login)に書き換えます。
  • ProxyPass /app/ http://backend-app.internal/: www.example.com/app/ へのリクエストを backend-app.internal/ へ転送します。
  • ProxyDomain internal-app.com: これがProxyDomainディレクティブです。この設定があると、クライアントが www.example.com にリクエストしても、バックエンドの backend-app.internal には Host: internal-app.com というヘッダーでリクエストが転送されます。

ProxyDomain の問題点と、現在の推奨設定の例

上記のProxyDomainは、バックエンドアプリケーションが「internal-app.comというホスト名でアクセスされることを想定している」場合に、そのHostヘッダーを強制的に送信するためのものでした。しかし、これはしばしば誤解を招き、より複雑な問題(特にバーチャルホストやSSL終端の問題)を引き起こす原因となっていました。

現在、ProxyDomainの代わりに推奨される設定は以下のようになります。

現在の推奨設定例 1: クライアントの Host ヘッダーをそのままバックエンドに転送

これが最も一般的で推奨されるリバースプロキシのパターンです。

# 必要なモジュールのロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>
    ServerName www.example.com
    #ServerAlias example.com

    # !!! 現在の推奨設定: クライアントのHostヘッダーをバックエンドにそのまま転送 !!!
    # クライアントが 'Host: www.example.com' でリクエストした場合、
    # バックエンドにも 'Host: www.example.com' が送られます。
    ProxyPreserveHost On

    ProxyPass /app/ http://backend-app.internal/
    ProxyPassReverse /app/ http://backend-app.internal/

    ProxyRequests Off

    ErrorLog ${APACHE_LOG_DIR}/proxy_current_error.log
    CustomLog ${APACHE_LOG_DIR}/proxy_current_access.log combined
</VirtualHost>

解説

  • ProxyPreserveHost On: これがProxyDomainの最も一般的な代替手段です。クライアントから送られてきたHostヘッダー(例: www.example.com)をそのままバックエンドサーバーに転送します。バックエンドサーバーがそのHostヘッダーに基づいて適切なコンテンツを返す場合に最適です。

現在の推奨設定例 2: 特定の Host ヘッダーをバックエンドに送信 (mod_headers を使用)

もしバックエンドサーバーが、プロキシ元のドメインとは異なる特定のHostヘッダーを期待する場合(例: internal-app.com という内部名)、mod_headersモジュールのRequestHeaderディレクティブを使用します。これはProxyDomainが提供しようとしていた機能を、より明示的かつ制御可能に実現する方法です。

# 必要なモジュールのロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule headers_module modules/mod_headers.so # mod_headers もロード

<VirtualHost *:80>
    ServerName www.example.com
    #ServerAlias example.com

    # !!! 現在の推奨設定: 特定のHostヘッダーをバックエンドに送信 !!!
    # ProxyPreserveHost はOff(または設定しない)で、
    # RequestHeader set Host で明示的に設定します。
    # これにより、バックエンドには常に 'Host: internal-app.com' が送られます。
    RequestHeader set Host "internal-app.com"

    ProxyPass /app/ http://backend-app.internal/
    ProxyPassReverse /app/ http://backend-app.internal/

    ProxyRequests Off

    ErrorLog ${APACHE_LOG_DIR}/proxy_headers_error.log
    CustomLog ${APACHE_LOG_DIR}/proxy_headers_access.log combined
</VirtualHost>
  • RequestHeader set Host "internal-app.com": これが、バックエンドに転送するHostヘッダーを明示的に設定するコマンドです。クライアントからどのようなHostヘッダーが来ても、バックエンドにはinternal-app.comが送信されます。
  • LoadModule headers_module ...: RequestHeaderディレクティブを使用するためには、mod_headersモジュールがロードされている必要があります。


ProxyDomain が行っていた主なことは、「バックエンドサーバーに転送されるリクエストの Host ヘッダーを強制的に書き換える」ことでした。この機能を代替する主な方法は以下の2つです。

  1. ProxyPreserveHost On: クライアントが送ってきた Host ヘッダーをそのままバックエンドに転送する。
  2. mod_headers モジュールと RequestHeader set Host: 特定の Host ヘッダーをバックエンドに明示的に設定する。

それぞれの方法について、詳細と例を挙げながら説明します。

ProxyPreserveHost On (最も一般的で推奨される代替方法)

目的

クライアントが Apache プロキシに対して送信した HTTP リクエストの Host ヘッダーを、変更せずにそのままバックエンドサーバーに転送します。

いつ使うか

  • 最もシンプルで、多くのリバースプロキシのユースケースに適合します。
  • バックエンドサーバーが複数のバーチャルホストをホストしており、クライアントがリクエストした Host ヘッダーに基づいて適切なバーチャルホストを解決する必要がある場合。
  • バックエンドサーバーが、Apache プロキシにアクセスする際に使用されたオリジナルのドメイン名(例: www.example.com)に基づいてコンテンツを返すことを期待している場合。

設定例

# 必要なモジュールのロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # !!! クライアントのHostヘッダーをそのままバックエンドに転送する !!!
    ProxyPreserveHost On

    # /app/ へのリクエストを http://backend-server.local/ へプロキシ
    ProxyPass /app/ http://backend-server.local/app/
    # バックエンドからのリダイレクトのLocationヘッダーを書き換える
    ProxyPassReverse /app/ http://backend-server.local/app/

    # リバースプロキシでは通常オフにする
    ProxyRequests Off

    ErrorLog ${APACHE_LOG_DIR}/proxy_alt_preserve_error.log
    CustomLog ${APACHE_LOG_DIR}/proxy_alt_preserve_access.log combined
</VirtualHost>

解説

  • ProxyPreserveHost On: このディレクティブが設定されていると、クライアントからのリクエストヘッダーに含まれる Host: の値が、プロキシされてバックエンドに転送されるリクエストにもそのまま含まれます。例えば、クライアントが Host: www.example.com でリクエストした場合、バックエンドサーバーも Host: www.example.com を受け取ります。

バックエンドサーバーに転送される HTTP リクエストの Host ヘッダーを、指定した任意の値に強制的に書き換えます。これは ProxyDomain が行っていたことと最も直接的に対応します。

  • バックエンドアプリケーションが、複数のバーチャルホストを持っており、特定の Host ヘッダーで呼び出す必要がある場合。
  • バックエンドサーバーが、ロードバランサーやプロキシからのアクセスを、特定の Host ヘッダーで識別する必要がある場合。
  • バックエンドサーバーが、プロキシにアクセスする際に使用されたドメイン名とは異なる、特定の内部ホスト名(例: internal-app-backend.local)でアクセスされることを期待している場合。
# 必要なモジュールのロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule headers_module modules/mod_headers.so # !!! mod_headers が必要 !!!

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # !!! バックエンドに送信するHostヘッダーを明示的に設定する !!!
    # クライアントからのHostヘッダーに関わらず、バックエンドには
    # 'Host: internal-app-backend.local' が送信されます。
    RequestHeader set Host "internal-app-backend.local"

    # 必要に応じて ProxyPreserveHost を Off にすることもありますが、
    # RequestHeader set があれば、その設定が優先されます。
    # ProxyPreserveHost Off

    ProxyPass /app/ http://backend-server.local/app/
    ProxyPassReverse /app/ http://backend-server.local/app/

    ProxyRequests Off

    ErrorLog ${APACHE_LOG_DIR}/proxy_alt_headers_error.log
    CustomLog ${APACHE_LOG_DIR}/proxy_alt_headers_access.log combined
</VirtualHost>
  • この方法は、ProxyDomain が提供していた機能(バックエンドへの Host ヘッダーの強制的な書き換え)を、より明示的かつ柔軟に実現します。RequestHeader ディレクティブは Host ヘッダーだけでなく、他の任意の HTTP ヘッダーも設定、変更、削除することができます。
  • RequestHeader set Host "internal-app-backend.local": このディレクティブが、Apache がバックエンドに転送するリクエストの Host ヘッダーを internal-app-backend.local に設定します。クライアントが www.example.com でアクセスしても、バックエンドサーバーは常に Host: internal-app-backend.local を受け取ります。
  • LoadModule headers_module modules/mod_headers.so: RequestHeader ディレクティブを使用するためには、mod_headers モジュールをロードする必要があります。

上記の代替方法と組み合わせて、以下のディレクティブもリバースプロキシの設定で非常に重要です。

  • ProxyRequests Off: リバースプロキシとして機能する場合、ProxyRequests Off を設定することが必須です。このディレクティブは、Apache がオープンプロキシ(フォワードプロキシ)として機能するのを防ぎ、セキュリティ上の脆弱性(DDoS攻撃の中継など)を回避します。通常、デフォルトで Off ですが、明示的に記述することをお勧めします。

  • ProxyPassReverse: バックエンドサーバーからの HTTP レスポンスに含まれる Location ヘッダーや Content-Location ヘッダー、および HTML の <a href><img src> などの URL を、クライアントがアクセスしたプロキシの URL に書き換えます。これにより、バックエンドからのリダイレクトや、HTML 内の相対パスが正しく解決されます。

    ProxyPass /app/ http://backend-server.local/app/
    ProxyPassReverse /app/ http://backend-server.local/app/