
テクニカルサポート業務の中で、Google Cloud Platform上で稼働するお客様のTomcatサーバーがアクセスログに正しいリモートIPアドレスを記録していないことが判明しました。
原因はもちろん、TomcatがGoogleの優秀なロードバランサーの背後に配置されていたためです。ロードバランサーはクライアントのリモートIPアドレスをX-Forwarded-For HTTPヘッダーに追記します。

正しいTomcatの設定にたどり着くまで数時間を要したため、同じ問題で悩む方が少しでも時間を節約できるよう、ここで手順を公開しておきます。
変更前:
remoteHostname: 130.211.2.139 // 内部ロードバランサーのアドレスx-fwd-for= 192.115.200.197, 35.186.199.42変更後:
remoteHostname: 192.115.200.197 // 実クライアントIPx-fwd-for= 192.115.200.197, 35.186.199.42「RemoteIpValve」クラスは、リクエストに記録される見かけ上のクライアントリモートIPアドレスおよびホスト名を、プロキシやロードバランサーからリクエストヘッダー(例: 「X-Forwarded-For」)経由で渡されたIPアドレスのリストで置き換えます。
仕組みは以下の通りです。
- RemoteIpValveは、前段のロードバランサーまたはプロキシがリクエストのHTTPヘッダー
$remoteIpHeader(デフォルトはx-forwarded-for)に格納した、カンマ区切りのIPおよびホスト名のリストをループ処理します。値は右から左の順に処理されます。 - リスト内の各IP/ホストに対し、internalProxiesと照合します:
- 内部プロキシのリストに一致した場合、そのIP/ホストは破棄されます。
- 一致しなかった場合、そのIP/ホストをリモートIPと判定し、ループを終了します。
あとは、IPレンジ 130.211.0.0/22 と 35.191.0.0/16 にマッチする「internalProxies」の正規表現を用意するだけです。
このレンジはGoogleが以下のページで公開しています:
https://cloud.google.com/load-balancing/docs/https/#firewall_rules
"130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}"さらに、ロードバランサーの外部IPもX-Forwarded-Forヘッダーに追加されるため、これも正規表現に含める必要があります。
今回のケースでは 35.186.199.42 です。
最終的な正規表現は次のようになります:
"130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}|35\.186\.199\.42"完成形の設定は以下のようになります:
<Valve className="org.apache.catalina.valves.RemoteIpValve"internalProxies="130\.211\.\d{1,3}\.\d{1,3}|35\.191\.\d{1,3}\.\d{1,3}|35\.186\.199\.42" /><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access_log" suffix=".txt" pattern="combined" requestAttributesEnabled="true" />これをserver.xmlに追記し、Tomcatサービスを再起動すれば完了です。
それでは、快適なロギングを :)