Apache HTTP Serverで実現する高可用性 - mod_proxy: ProxySetと他の選択肢

2025-05-27

ProxySet ディレクティブは、Apache HTTP Server の mod_proxy モジュールにおいて、プロキシの負荷分散構成を設定するために使用されます。特に、バックエンドサーバーのグループを定義し、それらへのリクエストの転送方法(バランスアルゴリズム、重み付け、健康状態のチェックなど)を制御する際に非常に重要です。

ProxySet とは何か?

主な用途

  • セッション維持: 特定のバランサーメンバーに対して、クライアントからの特定のセッションを維持するように設定できます。
  • 高可用性(ハイアベイラビリティ): バックエンドサーバーのいずれかがダウンした場合でも、他の利用可能なサーバーにリクエストを自動的に振り分けることで、サービスの継続性を確保します。
  • 負荷分散(ロードバランシング): 複数のアプリケーションサーバーやバックエンドサービス間でトラフィックを均等に、または設定された重み付けに従って分散させ、単一のサーバーへの負荷集中を防ぎます。

構文と主な引数

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

<Proxy balancer://balancer_name>
    ProxySet option=value [option=value ...]
</Proxy>

または、ProxySet<Proxy> ディレクティブの子ディレクティブとして記述することもできます。

ProxySet balancer://balancer_name option=value [option=value ...]

主なオプションと引数は以下の通りです。

  • noentireservername=On|Off:

    • プロキシされたリクエストの Host ヘッダーに、元のリクエストのホスト名ではなく、プロキシ先(バックエンド)のホスト名をそのまま渡すかどうかを制御します。通常は Off (元のホスト名を維持) が一般的です。
  • failonstatus=status_code[,status_code...]:

    • バックエンドサーバーから特定のHTTPステータスコードが返された場合、そのサーバーを一時的に「ダウン」とみなすように設定します。例えば、failonstatus=500 と設定すると、500 Internal Server Error を返したサーバーは一時的に負荷分散の対象から外されます。
  • nofailover=On|Off:

    • stickysession と組み合わせて使用されることが多く、セッションの固定先がダウンした場合でも、他のサーバーへのフェイルオーバーを許可するかどうかを制御します。On にするとフェイルオーバーしません。
  • timeout=seconds:

    • バックエンドサーバーへの接続タイムアウトを設定します。指定された秒数以内に応答がない場合、そのサーバーはダウンしているとみなされる可能性があります。
  • lbmethod=byrequests|bytraffic|bybusyness|heartbeat:

    • 負荷分散アルゴリズムを指定します。
      • byrequests (デフォルト): リクエスト数に基づいて負荷分散を行います。
      • bytraffic: 送受信されたデータ量に基づいて負荷分散を行います。
      • bybusyness: 各ワーカーのビジー状態(現在処理中のリクエスト数)に基づいて負荷分散を行います。最も負荷が低いサーバーにリクエストを転送します。
      • heartbeat: ApacheのHeartbeat機能を有効にし、バックエンドサーバーの健康状態と負荷情報を利用して負荷分散を行います。
  • stickysession=cookie_name|JSESSIONID:

    • セッションを維持するためのメカニズムを指定します。例えば、JSESSIONID のようなセッションIDを含むCookie名を設定することで、同じクライアントからの後続のリクエストが常に同じバックエンドサーバーにルーティングされるようにします。これは、セッションを共有しない複数のアプリケーションサーバーでステートフルなアプリケーションを運用する際に非常に重要です。
    • NOFAILOVER を追加すると、指定されたメンバーがダウンしてもセッションがフェイルオーバーしないように設定できます(通常は推奨されません)。

設定例

一般的な設定例を見てみましょう。

# mod_proxy と mod_proxy_balancer を有効にする
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

<VirtualHost *:80>
    ServerName example.com

    <Proxy balancer://mycluster>
        # セッションID "JSESSIONID" を使ってセッションを維持
        # セッション固定されたサーバーがダウンしてもフェイルオーバーしない
        ProxySet stickysession=JSESSIONID nofailover=On

        # リクエスト数に基づいて負荷分散 (デフォルトなので省略可能)
        ProxySet lbmethod=byrequests

        # バックエンドサーバーへの接続タイムアウトを5秒に設定
        ProxySet timeout=5

        # メンバーの追加
        BalancerMember http://backend1.example.com:8080 route=node1 loadfactor=10
        BalancerMember http://backend2.example.com:8080 route=node2 loadfactor=10
        BalancerMember http://backend3.example.com:8080 route=node3 loadfactor=5
    </Proxy>

    # /app のリクエストをバランサーに転送
    ProxyPass /app balancer://mycluster/app
    ProxyPassReverse /app balancer://mycluster/app

    # バランサーマネージャーへのアクセスを許可 (デバッグ用)
    <Location /balancer-manager>
        SetHandler balancer-manager
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Location>
</VirtualHost>

解説:

  • <Location /balancer-manager> は、バランサーの状態を確認・管理するためのWebインターフェース(balancer-manager)へのアクセスを設定しています。これはデバッグや監視に役立ちます。
  • ProxyPassReverse は、バックエンドサーバーからのリダイレクト応答のURLをApacheが書き換えるために必要です。
  • ProxyPass /app balancer://mycluster/app により、/app へのアクセスを mycluster バランサーに転送します。
  • BalancerMember ディレクティブで、個々のバックエンドサーバー(メンバー)を定義しています。routestickysession と連携し、セッション固定のためのサーバー識別子として使用されます。loadfactor は、そのサーバーに割り当てる相対的な重み付けを示します。
  • timeout=5 は、バックエンドサーバーへの接続タイムアウトを5秒に設定しています。
  • lbmethod=byrequests は、リクエスト数に基づいて負荷分散を行うことを明示しています(デフォルト値)。
  • nofailover=On により、セッション固定されたサーバーがダウンしても、他のサーバーへのフェイルオーバーを行いません。これは、セッション情報が特定のサーバーにしか存在しない場合に重要ですが、可用性の観点からは注意が必要です。
  • stickysession=JSESSIONID により、JSESSIONID というCookie名を使ってセッションを維持するように設定しています。
  • balancer://mycluster という名前のバランサーグループを定義しています。

注意点

  • 設定の複雑さ: 高度な負荷分散や特定のセッション要件がある場合、設定は複雑になることがあります。Apacheの公式ドキュメントや関連リソースを参照して、詳細な設定オプションを理解することが重要です。
  • 健康状態のチェック: mod_proxy は、バックエンドサーバーの死活監視を自動的に行い、ダウンしたサーバーを負荷分散の対象から一時的に外します。
  • セッションの共有: stickysession を使用しない場合や、特定のサーバーにセッションを固定しない場合は、バックエンドのアプリケーションサーバー間でセッション情報を共有する仕組み(例:データベース、Redisなど)が必要になることがあります。
  • mod_proxy_balancer の有効化: ProxySet を使用するためには、mod_proxy_balancer モジュールが有効になっている必要があります。


モジュールが有効になっていない (AH00534: httpd: Configuration error: No ProxySet directive found.)

エラーの症状: Apache を起動または再起動しようとすると、ProxySet ディレクティブが見つからないというエラーが表示される。

原因: ProxySetmod_proxy_balancer モジュールの一部であり、このモジュールが有効になっていない場合に発生します。また、mod_proxy および mod_proxy_http も必要です。

トラブルシューティング:

  1. 必要なモジュールが有効になっているか確認する:
    • httpd.conf または mods-available ディレクトリ内の設定ファイルで、以下の LoadModule ディレクティブがコメントアウトされていないことを確認します。
      LoadModule proxy_module modules/mod_proxy.so
      LoadModule proxy_http_module modules/mod_proxy_http.so
      LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
      
    • Ubuntu/Debian 系の場合:
      sudo a2enmod proxy
      sudo a2enmod proxy_http
      sudo a2enmod proxy_balancer
      sudo systemctl restart apache2 # または sudo service apache2 restart
      
    • CentOS/RHEL 系の場合:
      sudo systemctl restart httpd # または sudo service httpd restart
      # 必要に応じてモジュールファイルを編集し、LoadModule を有効にする
      
  2. 設定ファイルの構文チェック:
    • 変更後、必ず構文チェックを行います。
      apachectl configtest # または httpd -t
      

バックエンドサーバーへの接続タイムアウト (Proxy Error: The timeout specified has expired (70007).)

エラーの症状: クライアントからのリクエストがタイムアウトし、Apache のエラーログに The timeout specified has expiredAH00957: HTTP: attempt to connect to ... failed といったメッセージが表示される。

原因:

  • ProxySet または ProxyPass で設定されたタイムアウト値が短すぎる。
  • ネットワークの問題(ファイアウォール、ルーティングなど)により、Apache からバックエンドサーバーに接続できない。
  • バックエンドサーバーがダウンしている、応答が遅い、または過負荷状態である。

トラブルシューティング:

  1. バックエンドサーバーの稼働状況を確認する:
    • 直接バックエンドサーバーにアクセスして、アプリケーションが正常に動作しているか確認します。
    • バックエンドサーバーのログを確認し、エラーがないか、パフォーマンスの問題がないかを確認します。
  2. ネットワーク接続を確認する:
    • Apache サーバーからバックエンドサーバーへ pingcurl コマンドでアクセスし、ネットワーク接続性を確認します。
      # 例: curl -v http://backend.example.com:8080/
      
    • 途中のファイアウォール(OSのファイアウォール、AWSのセキュリティグループなど)でポートがブロックされていないか確認します。
  3. タイムアウト値を調整する:
    • ProxySet ディレクティブ内で timeout オプションを増やします。
      <Proxy balancer://mycluster>
          ProxySet timeout=30 # 例: 30秒に延長
          # ...
      </Proxy>
      
    • または、ProxyPass ディレクティブに直接 timeout を指定することもできます。
      ProxyPass /app balancer://mycluster/app timeout=30
      
  4. ProxyTimeout ディレクティブの確認:
    • グローバルまたは仮想ホストレベルで ProxyTimeout ディレクティブが設定されている場合、その値も影響します。
      ProxyTimeout 60 # 全てのプロキシ接続に適用されるデフォルトのタイムアウト
      

セッションが維持されない、またはセッションが失われる (stickysession の問題)

エラーの症状: セッション情報が維持されず、ユーザーが頻繁にログインを求められたり、ショッピングカートの内容が失われたりする。Apache のエラーログに BALANCER_ROUTE_CHANGED 関連のメッセージが出力されることがある(LogLevel を Debug に設定した場合)。

原因:

  • jvmRoute の設定がバックエンド(Tomcatなど)とApacheで一致していない。
  • バックエンドサーバーがダウンし、セッションが他のサーバーにフェイルオーバーされた(nofailover=Off の場合)。
  • バックエンドアプリケーションのセッションIDがApacheのstickysession設定と一致していない。
  • バックエンドアプリケーションがセッションIDを適切に発行していない。
  • ProxySet stickysession の設定が正しくない。

トラブルシューティング:

  1. stickysession オプションの確認:
    • ProxySet stickysession=CookieName が正しく設定されているか確認します。CookieName は、バックエンドアプリケーションがセッションIDを格納するために使用するCookie名(例: JSESSIONID)と完全に一致している必要があります。
  2. バックエンドアプリケーションのセッションID発行を確認する:
    • 開発者ツール(ブラウザのF12)でネットワークタブを開き、クライアントとバックエンドの間でやり取りされるHTTPヘッダーを確認します。特に、アプリケーションがセッションIDを返すCookie名が ProxySet stickysession で指定した名前と一致しているか確認します。
    • Tomcat の場合、server.xml<Engine> または <Host> 要素に jvmRoute 属性が設定されていることを確認します。
      <Engine name="Catalina" defaultHost="localhost" jvmRoute="node1">
      
    • Apache の BalancerMemberroute オプションと jvmRoute の値が一致しているか確認します。
      BalancerMember http://backend1.example.com:8080 route=node1
      
  3. nofailover オプションの動作を理解する:
    • ProxySet stickysession=JSESSIONID nofailover=On の場合、セッション固定されたバックエンドがダウンすると、そのセッションは他のサーバーにフェイルオーバーされず、エラーになります。これは意図的な動作ですが、可用性にとっては問題となる場合があります。
    • nofailover=Off(または省略)の場合、固定先のサーバーがダウンすると、他のサーバーにフェイルオーバーを試みます。この場合、セッションデータが共有されていないと、ユーザーはセッションを失う可能性があります。
  4. Apache のログレベルを Debug に設定する:
    • LogLevel debug を設定することで、mod_proxy_balancer の詳細な動作(どのリクエストがどのワーカーに送られたか、セッション固定の動作など)をログで追跡できます。
      LogLevel debug proxy_balancer:debug
      

バックエンドサーバーがエラーを返す (failonstatus の問題)

エラーの症状: バックエンドサーバーが特定のHTTPステータスコード(例: 500 Internal Server Error)を返しているにもかかわらず、Apache がそのサーバーをダウンと認識せず、リクエストを送り続けてしまう。

原因:

  • バックエンドサーバーが返すエラーページが、期待するHTTPステータスコードではなく、常に200 OK を返している。
  • ProxySet failonstatus オプションが設定されていない、または間違ったステータスコードが指定されている。

トラブルシューティング:

  1. failonstatus オプションを確認する:
    • バックエンドサーバーがエラー時に返すHTTPステータスコードを正確に把握し、ProxySet failonstatus=500,503 のように設定します。
      <Proxy balancer://mycluster>
          ProxySet failonstatus=500,503 # 500または503エラーでワーカーを一時停止
          # ...
      </Proxy>
      
  2. バックエンドサーバーの応答を確認する:
    • curl -I http://backend.example.com:8080/error_path のようにヘッダーのみを取得し、実際に返されるHTTPステータスコードを確認します。
    • 一部のアプリケーションフレームワークは、エラー発生時でもカスタムエラーページを200 OKで返すことがあります。その場合は、アプリケーション側の設定を変更するか、Apache側で別の検出方法(例えば、特定のレスポンスボディの文字列をチェックする)を検討する必要がありますが、これは mod_proxy の範囲外で、mod_rewrite などと組み合わせる必要があるかもしれません。

ProxyPass / ProxyPassReverse と ProxySet の競合や順序の問題

エラーの症状: リクエストが意図したバックエンドにルーティングされない、またはリダイレクトが正しく処理されない。

原因:

  • 複数の ProxyPass ディレクティブの順序が間違っている(より具体的なパスを先に記述する必要がある)。
  • ProxyPassProxyPassReverse のパスと ProxySet で定義されたバランサーのパスの間に矛盾がある。

トラブルシューティング:

  1. パスの一致を確認する:
    • ProxyPass /app balancer://mycluster/appProxySet で定義されたバランサーの名前が一致していることを確認します。
    • ProxyPassProxyPassReverse のパスが一致しているか確認します。末尾のスラッシュの有無も重要です。
      # 正しい例: 末尾スラッシュを揃える
      ProxyPass /app/ balancer://mycluster/app/
      ProxyPassReverse /app/ balancer://mycluster/app/
      
      # または末尾スラッシュなしで揃える
      ProxyPass /app balancer://mycluster/app
      ProxyPassReverse /app balancer://mycluster/app
      
      ただし、ProxyPass /app balancer://mycluster/app は、/app へのアクセスを balancer://mycluster/app にマッピングします。クライアントが /app/page.html をリクエストすると、バックエンドには http://backend_host:port/app/page.html が送られます。
  2. ProxyPass ディレクティブの順序:
    • Apache は設定ファイルを上から順に処理します。より具体的な ProxyPass ルールを先に記述し、より一般的なルールを後から記述するようにします。
      # NG: /api が先に評価されてしまう
      ProxyPass / balancer://general_cluster/
      ProxyPass /api balancer://api_cluster/
      
      # OK: /api が先に評価される
      ProxyPass /api balancer://api_cluster/
      ProxyPass / balancer://general_cluster/
      

SELinux による接続拒否 (CentOS/RHEL)

エラーの症状: Apache のエラーログに (13)Permission denied: AH00957: HTTP: attempt to connect to ... failed. のようなメッセージが表示されるが、ネットワーク接続自体は問題ないように見える。

原因: SELinux が Apache プロセスから外部ネットワークへの接続をブロックしているため。

トラブルシューティング:

  1. SELinux の状態を確認する:
    sestatus
    
  2. HTTPD がネットワーク接続を許可するように設定する:
    sudo /usr/sbin/setsebool -P httpd_can_network_connect 1
    
    -P オプションは、設定を永続化します。

SSL/TLS 証明書関連の問題 (HTTPS プロキシ)

エラーの症状: HTTPS のバックエンドサーバーにプロキシする際にエラーが発生する。特に、自己署名証明書や信頼できない証明書を使用している場合に顕著。

原因: Apache がバックエンドサーバーのSSL証明書を信頼できないため。

トラブルシューティング:

  1. 必要なモジュールの有効化:
    • mod_sslmod_proxy_http が有効になっていることを確認します。
  2. SSLProxyEngine の有効化:
    • HTTPS バックエンドに接続する場合、Apache の仮想ホスト設定で SSLProxyEngine on を設定する必要があります。
      <VirtualHost *:443>
          ServerName example.com
          SSLEngine on
          SSLCertificateFile /path/to/your/certificate.crt
          SSLCertificateKeyFile /path/to/your/private.key
      
          SSLProxyEngine on
          # 開発/テスト環境でのみ使用: バックエンド証明書の検証をスキップ
          # SSLProxyVerify none
          # SSLProxyCheckPeerCN off
          # SSLProxyCheckPeerName off
      
          <Proxy balancer://mycluster>
              # ...
          </Proxy>
          ProxyPass /app balancer://mycluster/app
          ProxyPassReverse /app balancer://mycluster/app
      </VirtualHost>
      
    • 本番環境では、バックエンドサーバーの証明書が信頼できる認証局によって署名されていることを確認し、検証をスキップする設定は避けるべきです。信頼されたCA証明書をApacheにロードする方法を検討します。
  3. 証明書パスの確認:
    • SSLCertificateFileSSLCertificateKeyFile のパスが正しいことを確認します。

一般的なトラブルシューティングのヒント

  • 設定ファイルをシンプルにする: 複雑な設定はエラーの温床となります。段階的に設定を追加し、その都度テストを行うことで、問題の特定が容易になります。
  • balancer-manager を活用する: mod_proxy_balancer の状態をリアルタイムで確認できる便利なツールです。
    <Location /balancer-manager>
        SetHandler balancer-manager
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1 # アクセスを許可するIPアドレス
    </Location>
    
    ブラウザから http://your-apache-server/balancer-manager にアクセスして、ワーカーの状態(Up/Down、ロードファクター、エラー回数など)を確認できます。
  • バックエンドサーバーのログも確認する: Apache 側だけでなく、プロキシ先のアプリケーションサーバーのログも確認することで、問題の切り分けに役立ちます。
  • apachectl configtest を常に実行する: 設定変更後、Apache を再起動する前に構文エラーがないか確認します。
  • Apache エラーログを確認する: 最も重要な情報源です。LogLevelwarn または info、問題が解決しない場合は debug に設定して、詳細な情報を取得します。
    • ログの場所は通常 /var/log/apache2/error.log (Debian/Ubuntu) または /var/log/httpd/error_log (CentOS/RHEL) です。


ProxySet ディレクティブは、特に mod_proxy_balancer と組み合わせて使用され、複数のバックエンドサーバー(ワーカー)を管理し、リクエストを分散させる方法を定義します。

前提条件:

以下のモジュールが有効になっていることを確認してください(httpd.confLoadModule ディレクティブのコメントを解除するか、適切なコマンドで有効にします)。

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so # byrequests 方式を使用する場合
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so # bytraffic 方式を使用する場合
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so # bybusyness 方式を使用する場合
# 必要に応じて、AJPプロトコルを使用する場合は mod_proxy_ajp.so など
# WebSockets を使用する場合は mod_proxy_wstunnel.so

例1: シンプルな負荷分散 (byrequests)

最も基本的な負荷分散の例です。クライアントからのリクエストを、定義されたバックエンドサーバー間で均等に(リクエスト数に基づいて)分散します。

# httpd.conf または仮想ホスト設定ファイル (例: /etc/httpd/conf.d/vhosts.conf または /etc/apache2/sites-available/your_site.conf)

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAdmin [email protected]

    # バランサーグループの定義
    # ここで 'mycluster' という名前のバランサーを作成します
    <Proxy balancer://mycluster>
        # 各バックエンドサーバー (BalancerMember) を定義
        # ここでは 'node1' と 'node2' の2つのバックエンドサーバーを設定しています
        BalancerMember http://192.168.1.101:8080 route=node1
        BalancerMember http://192.168.1.102:8080 route=node2

        # 負荷分散アルゴリズムをリクエスト数に基づいて設定 (デフォルトなので明示しなくても同じ動作)
        ProxySet lbmethod=byrequests

        # バックエンドへの接続タイムアウトを5秒に設定
        ProxySet timeout=5
    </Proxy>

    # /app へのリクエストを mycluster バランサーに転送
    ProxyPass /app/ balancer://mycluster/app/
    # バックエンドからのリダイレクトURLを書き換える
    ProxyPassReverse /app/ balancer://mycluster/app/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

解説:

  • ProxyPassReverse /app/ balancer://mycluster/app/: バックエンドサーバーからのリダイレクト応答(Locationヘッダーなど)に含まれるURLを、クライアントがアクセスできるプロキシのURLに書き換えます。
  • ProxyPass /app/ balancer://mycluster/app/: yourdomain.com/app/ へのすべてのリクエストを mycluster バランサーに転送し、バックエンドサーバーの /app/ パスにマッピングします。
  • ProxySet timeout=5: Apacheがバックエンドサーバーへの接続を試行する際のタイムアウトを5秒に設定します。これを超えると、そのバックエンドは一時的にダウンしていると見なされる可能性があります。
  • ProxySet lbmethod=byrequests: ロードバランシングの方法を「リクエスト数に基づく」に設定します。これはデフォルトの動作ですが、明示的に指定することで意図が明確になります。
  • BalancerMember http://192.168.1.101:8080 route=node1: mycluster グループに http://192.168.1.101:8080 をワーカーとして追加します。route=node1 はセッション固定に使用される識別子です(この例ではセッション固定は設定されていませんが、将来的な拡張のために含めています)。
  • <Proxy balancer://mycluster>: mycluster という名前のバランサーグループを定義するコンテナです。

例2: セッション維持 (Sticky Session) と重み付け負荷分散

特定のユーザーセッションを常に同じバックエンドサーバーにルーティングしたい場合に stickysession を使用します。また、各バックエンドサーバーの処理能力に応じて重み付けを行う loadfactor も組み合わせます。

<VirtualHost *:80>
    ServerName yourdomain.com

    <Proxy balancer://mycluster_sticky>
        BalancerMember http://192.168.1.101:8080 route=node1 loadfactor=10
        BalancerMember http://192.168.1.102:8080 route=node2 loadfactor=10
        BalancerMember http://192.168.1.103:8080 route=node3 loadfactor=5 # このサーバーは他の半分

        # JSESSIONID という名前のCookieを使ってセッションを維持
        # セッションが固定されたワーカーがダウンしてもフェイルオーバーしない
        ProxySet stickysession=JSESSIONID nofailover=On

        # 負荷分散アルゴリズムをビジー状態に基づいて設定 (最もアイドルなサーバーに転送)
        ProxySet lbmethod=bybusyness

        # バックエンドへの接続タイムアウトを10秒に設定
        ProxySet timeout=10

        # 500 (Internal Server Error) または 503 (Service Unavailable) を返した場合、ワーカーを一時停止
        ProxySet failonstatus=500,503
    </Proxy>

    ProxyPass /app/ balancer://mycluster_sticky/app/
    ProxyPassReverse /app/ balancer://mycluster_sticky/app/

    # バランサーマネージャーへのアクセスを許可 (監視・管理用)
    <Location /balancer-manager>
        SetHandler balancer-manager
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1 192.168.1.0/24 # アクセスを許可するIPアドレス
    </Location>
</VirtualHost>

解説:

  • <Location /balancer-manager>: バランサーのリアルタイムの状態を表示し、動的に設定を変更できる balancer-manager インターフェースを有効にします。アクセス制限を適切に行うことが重要です。
  • ProxySet failonstatus=500,503: バックエンドサーバーがHTTPステータスコード 500 または 503 を返した場合、そのワーカーを一時的に「ダウン」と見なし、負荷分散の対象から外します。これにより、クライアントへのエラー応答を減らし、サービスの健全性を維持できます。
  • ProxySet lbmethod=bybusyness: 各ワーカーの現在の処理中リクエスト数(ビジー状態)に基づいて負荷分散を行います。最も負荷の低いワーカーにリクエストを転送しようとします。
  • ProxySet stickysession=JSESSIONID nofailover=On:
    • JSESSIONID というCookie名を使用してセッションを固定します。TomcatなどのJavaアプリケーションサーバーでよく使用されるセッションIDです。
    • nofailover=On は、特定のワーカーにセッションが固定されている場合、そのワーカーがダウンしても他のワーカーへのフェイルオーバーを行わないことを意味します。セッション情報がサーバー間で共有されていない場合に、セッションの整合性を保つために使用されます。ただし、これを使用すると、固定先がダウンした場合にユーザーはサービスを利用できなくなります。
  • BalancerMember ... loadfactor=X: loadfactor は、そのワーカーに割り当てる相対的な重み付けです。node1node2node3 の2倍のリクエストを受け取ることになります(lbmethod に応じて動作が変わります)。

例3: HTTPS バックエンドへのプロキシ (SSLProxyEngine)

Apache が HTTPS を使用してバックエンドサーバーに接続する場合の設定です。

<VirtualHost *:443>
    ServerName secureapp.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/secureapp.com.crt
    SSLCertificateKeyFile /etc/ssl/private/secureapp.com.key
    # 必要に応じてSSLCertificateChainFileも設定

    # HTTPSバックエンドへのプロキシを有効にする
    SSLProxyEngine on
    # バックエンド証明書の検証に関する設定 (本番では通常、証明書検証を推奨)
    # 開発/テスト環境でのみ: バックエンド証明書の検証をスキップ
    # SSLProxyVerify none
    # SSLProxyCheckPeerCN off
    # SSLProxyCheckPeerName off

    <Proxy balancer://secure_cluster>
        BalancerMember https://192.168.1.201:8443 route=secure_node1
        BalancerMember https://192.168.1.202:8443 route=secure_node2

        ProxySet lbmethod=byrequests
        ProxySet timeout=15
    </Proxy>

    ProxyPass / secure_app/ balancer://secure_cluster/secure_app/
    ProxyPassReverse / secure_app/ balancer://secure_cluster/secure_app/

    ErrorLog ${APACHE_LOG_DIR}/ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
</VirtualHost>

解説:

  • SSLProxyVerify none, SSLProxyCheckPeerCN off, SSLProxyCheckPeerName off: これらの設定は、ApacheがバックエンドサーバーのSSL証明書の検証を行わないようにします。これはセキュリティリスクを伴うため、本番環境では強く非推奨です。 本番環境では、バックエンドサーバーが信頼できる認証局によって署名された証明書を使用し、ApacheにそのCA証明書を信頼させる設定(SSLProxyCACertificateFileSSLProxyCACertificatePath など)を行うべきです。
  • SSLProxyEngine on: これが最も重要で、ApacheがバックエンドサーバーとSSL/TLSハンドシェイクを行うことを許可します。
  • SSLEngine on, SSLCertificateFile, SSLCertificateKeyFile: クライアントとApache間のHTTPS接続のためのSSL設定です。

例4: WebSockets プロキシ

WebSockets を使用するアプリケーションをプロキシする場合、mod_proxy_wstunnel モジュールと upgrade=websocket オプションを使用します。

LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

<VirtualHost *:80>
    ServerName websocketapp.com

    <Proxy balancer://websocket_cluster>
        BalancerMember ws://192.168.1.301:8080/websocket route=wsnode1
        BalancerMember ws://192.168.1.302:8080/websocket route=wsnode2

        ProxySet lbmethod=byrequests
    </Proxy>

    # WebSocket プロキシのための特別な設定
    # Upgrade ヘッダーを処理し、WebSocket 接続をトンネルする
    ProxyPass /ws/ balancer://websocket_cluster/ upgrade=websocket
    ProxyPassReverse /ws/ balancer://websocket_cluster/

    ErrorLog ${APACHE_LOG_DIR}/ws_error.log
    CustomLog ${APACHE_LOG_DIR}/ws_access.log combined
</VirtualHost>

解説:

  • ProxyPass /ws/ balancer://websocket_cluster/ upgrade=websocket:
    • upgrade=websocket オプションが重要です。これにより、Apache はクライアントからの Upgrade: websocket ヘッダーを検知し、バックエンドへの接続をWebSocketプロトコルにアップグレードします。
    • パスの末尾にスラッシュを付けるかどうかは、アプリケーションのパス構造に合わせる必要があります。
  • BalancerMember ws://...: WebSocketプロトコルを使用する場合、ws:// (または wss:// for secure WebSockets) スキームを指定します。
  • LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so: WebSocketプロキシのためにこのモジュールが必要です。

例5: ヘッダーの操作とカスタマイズ

mod_headers と組み合わせて、Apache がバックエンドに転送するリクエストヘッダーや、クライアントに返すレスポンスヘッダーを操作できます。

LoadModule headers_module modules/mod_headers.so

<VirtualHost *:80>
    ServerName myapp.com

    <Proxy balancer://myapp_cluster>
        BalancerMember http://192.168.1.401:8080 route=appnode1
        BalancerMember http://192.168.1.402:8080 route=appnode2

        ProxySet lbmethod=byrequests
    </Proxy>

    # クライアントの元のIPアドレスをX-Forwarded-Forヘッダーに追加
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "http" # HTTPの場合
    RequestHeader set X-Forwarded-Port "80" # HTTPの場合
    # HTTPSの場合: RequestHeader set X-Forwarded-Proto "https"
    # HTTPSの場合: RequestHeader set X-Forwarded-Port "443"

    # Apacheによって設定されたセッション固定ルートをクライアントに返すCookieに追加
    # env=BALANCER_ROUTE_CHANGED が重要: ルートが変更された場合にのみCookieを設定
    Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; Path=/" env=BALANCER_ROUTE_CHANGED

    ProxyPass / balancer://myapp_cluster/
    ProxyPassReverse / balancer://myapp_cluster/
</VirtualHost>

解説:

  • Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; Path=/" env=BALANCER_ROUTE_CHANGED:
    • これは、バックエンドアプリケーションがセッションCookieを発行しない場合に、Apache自身がセッション固定用のCookieを発行する一般的なパターンです。
    • %{BALANCER_WORKER_ROUTE}e は、Apacheが現在リクエストをルーティングしているワーカーの route 値から取得される環境変数です。
    • env=BALANCER_ROUTE_CHANGED は、セッション固定のルーティングが変更された場合にのみこのヘッダー(Cookie)を追加するように条件を付けます。
  • RequestHeader set X-Forwarded-Proto "http" など: ロードバランサーの後ろに配置されたアプリケーションが、元のプロトコル(HTTPかHTTPSか)やポートを知るために必要なヘッダーを追加します。これは、アプリケーションが正しいリダイレクトURLを生成するのに役立ちます。
  • ProxyPreserveHost On: クライアントから受け取った Host ヘッダーをそのままバックエンドに転送します。


Nginx (エンジンエックス)

Nginx は、Webサーバーとしてだけでなく、高性能なリバースプロキシおよびロードバランサーとしても非常に広く利用されています。イベント駆動型アーキテクチャを採用しており、高負荷時でも低いメモリ使用量で多数の同時接続を処理できるのが特徴です。

特徴と利点:

  • Kubernetesとの親和性: KubernetesのIngress Controllerとして広く利用されています。
  • WebSocketsサポート: WebSocketプロキシも容易に設定できます。
  • レイヤー7の機能: HTTPヘッダーに基づいたルーティング、SSL終端、キャッシュなどの高度な機能を提供します。
  • シンプルな設定: Apacheに比べて設定ファイルが簡潔で分かりやすいことが多いです。
  • 高パフォーマンス: 特に静的ファイルの配信や大量の同時接続処理に優れています。

設定例 (Nginx):

# /etc/nginx/nginx.conf または sites-available/your_site.conf

http {
    upstream backend_servers {
        # ロードバランシング方式 (デフォルトは round-robin)
        # least_conn; # 最もアクティブな接続数が少ないサーバーに転送
        # ip_hash;    # クライアントのIPアドレスに基づいてセッション固定

        server 192.168.1.101:8080;
        server 192.168.1.102:8080;
        server 192.168.1.103:8080;
    }

    server {
        listen 80;
        server_name yourdomain.com;

        location /app/ {
            # upstream で定義されたバックエンドサーバーグループにリクエストを転送
            proxy_pass http://backend_servers/app/;

            # 実際のクライアントIPアドレスをバックエンドに伝える
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # WebSocketのアップグレードを許可
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";

            # セッション固定用のCookieを扱う例 (Nginxのupstream_hashを使用する場合)
            # upstream backend_servers {
            #     hash $cookie_JSESSIONID consistent;
            #     server 192.168.1.101:8080;
            #     server 192.168.1.102:8080;
            # }
        }
    }
}

HAProxy (エイチエープロキシ)

HAProxy は、高可用性と高性能な負荷分散に特化したオープンソースのプロキシサーバーです。TCP/HTTPアプリケーションの両方に対応し、非常に多くのロードバランシングアルゴリズムと詳細なヘルスチェック機能を提供します。

特徴と利点:

  • SSL終端: フロントエンドでのSSL終端が可能です。
  • スティッキーセッション: さまざまな方法でセッション固定をサポートします。
  • ACL (Access Control List): URL、ヘッダー、Cookieなどに基づいて高度なルーティングルールを設定できます。
  • 詳細なヘルスチェック: バックエンドサーバーの健全性を細かく監視し、問題のあるサーバーを自動的にプールから除外できます。
  • 多様なロードバランシングアルゴリズム: ラウンドロビン、最小接続数、ソースIPハッシュなど、多数のアルゴリズムをサポートします。
  • 非常に高いパフォーマンス: 特に大量の同時接続を処理することに特化しています。

設定例 (HAProxy):

# /etc/haproxy/haproxy.cfg

global
    log /dev/log    daemon
    maxconn 20000
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon

defaults
    mode http
    log global
    option httplog
    option dontlognull
    option http-server-close
    option forwardfor # X-Forwarded-For ヘッダーを追加
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

# フロントエンド (外部からのリクエストを受け付ける部分)
frontend http_front
    bind *:80
    acl is_app path_beg /app
    use_backend app_backends if is_app
    default_backend default_webserver

# バックエンド (アプリケーションサーバー群)
backend app_backends
    balance roundrobin # ロードバランシングアルゴリズム (ラウンドロビン)
    # balance leastconn # または最小接続数

    # セッション固定 (JSESSIONID クッキーに基づいて)
    # `app_backends` はアプリケーションサーバーが生成する `JSESSIONID` の末尾に付加される `jvmRoute` と一致させる
    # `route` は BalancerMember の `route` に相当する
    cookie JSESSIONID insert indirect nocache # クッキー名を指定し、挿入モードに
    option httplog
    option httpchk GET /health # /health エンドポイントへのHTTPヘルスチェック

    server app1 192.168.1.101:8080 cookie node1 check
    server app2 192.168.1.102:8080 cookie node2 check
    server app3 192.168.1.103:8080 cookie node3 check backup # app3 はバックアップサーバー

backend default_webserver
    server web1 192.168.1.100:80 check

クラウドプロバイダのロードバランサー (AWS ALB/NLB, GCP Cloud Load Balancing, Azure Load Balancer/Application Gateway)

クラウド環境でアプリケーションを運用している場合、各クラウドプロバイダが提供するマネージドロードバランサーサービスが最も一般的な代替手段です。これらは高度な可用性、スケーラビリティ、セキュリティ機能を備えています。

特徴と利点:

  • 統合された監視・ロギング: クラウドの監視ツールとシームレスに連携します。
  • 多様なロードバランシングアルゴリズム: クラウドプロバイダによって異なりますが、様々なアルゴリズムをサポートします。
  • セキュリティ: SSL/TLS終端、WAF (Web Application Firewall)、DDoS保護などの機能が統合されています。
  • 高可用性: 複数のアベイラビリティゾーン/リージョンにまたがる構成で、単一障害点を排除します。
  • 自動スケーリング: トラフィック量に応じて自動的にスケールイン/アウトします。
  • フルマネージド: インフラの構築・運用・保守がクラウドプロバイダによって行われるため、運用負荷が大幅に軽減されます。

例 (AWS Application Load Balancer - ALB):

ALBはレイヤー7(HTTP/HTTPS)のロードバランサーで、パスベースのルーティング、ホストベースのルーティング、セッション固定、SSL終端、WebSocketsなどをサポートします。

  • 設定方法: AWSマネジメントコンソール、AWS CLI、CloudFormation、Terraformなどを利用して設定します。コード例は複雑になるため省略しますが、設定の概念はApacheのProxySetと似ています。
    • ターゲットグループ: バックエンドサーバー(EC2インスタンス、コンテナなど)をグループ化し、ヘルスチェックを設定します。
    • リスナー: クライアントからの接続を待機するポートとプロトコル(例: HTTPS 443)を設定します。
    • ルール: リスナーにアタッチされ、リクエストのパスやホスト名に基づいてターゲットグループにトラフィックをルーティングするルールを定義します。セッション維持(スティッキーセッション)もここで設定します。

例 (AWS Network Load Balancer - NLB):

NLBはレイヤー4(TCP/UDP)のロードバランサーで、非常に高いスループットと低レイテンシが特徴です。IPアドレスとポートに基づいてトラフィックを転送します。

  • 設定方法: ALBと同様に、ターゲットグループとリスナーを設定しますが、機能はよりシンプルです。SSL終端も可能ですが、HTTPヘッダーベースのルーティングはできません。
  • API Gateway (例: Nginx Plus, Kong, Apigee): APIに特化したプロキシで、負荷分散だけでなく、認証、認可、レート制限、モニタリング、API変換などの機能を提供します。
  • Traefik Proxy: コンテナやマイクロサービス環境に特化したエッジルーター・ロードバランサーです。Docker、Kubernetesなどのオーケストレーターと密接に連携し、動的なサービスディスカバリやルーティングが可能です。
  • Caddy: 自動HTTPS機能を備えたモダンなWebサーバーで、リバースプロキシ機能もシンプルに設定できます。小規模なプロジェクトや開発環境で手軽に利用できます。
  • Envoy Proxy: クラウドネイティブ環境で広く利用される高機能なプロキシです。サービスメッシュのデータプレーンとしても機能し、高度なルーティング、トラフィック管理、可観測性を提供します。
代替手段最適なユースケース利点考慮事項
Nginx汎用的なWebサーバー、リバースプロキシ、中規模の負荷分散高性能、設定の簡潔さ、多様な機能大規模なエンタープライズ機能は限定的
HAProxy高可用性、高パフォーマンスなレイヤー4/7負荷分散高いパフォーマンス、豊富なロードバランシング機能、詳細なヘルスチェック設定がやや複雑、Webサーバー機能はない
クラウドLBクラウドネイティブな環境、大規模、高可用性フルマネージド、自動スケーリング、高いセキュリティクラウドベンダーへのロックイン、コスト
Envoy/Traefikマイクロサービス、コンテナ環境、サービスメッシュ動的ルーティング、高度なトラフィック制御、可観測性設定が複雑、学習曲線、主にコンテナ環境向け
Caddy小規模プロジェクト、開発環境、シンプルなHTTPSプロキシ自動HTTPS、設定の容易さ大規模な負荷分散には不向き