Log Originating Client IP on Linux App Service (Tomcat)
The X-Forwarded-For (XFF) header is a de-facto standard header for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or a load balancer. When traffic is intercepted between clients and servers, server access logs contain the IP address of the proxy or load balancer only. To see the original IP address of the client, the X-Forwarded-For request header is used.
We can get the value of this header using multiple ways. One of the common ways is via code. Here is a sample Java Code you could use:
private static String getClientIp(HttpServletRequest request) {
String remoteAddr = "";
if (request != null) {
remoteAddr = request.getHeader("X-FORWARDED-FOR");
if (remoteAddr == null || "".equals(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
}
return remoteAddr;
}
Credits: Mkyong: How to get client Ip Address in Java
In this blog, I will be covering how this can be done by configuring Tomcat so that we can get it directly from the Access logs of Tomcat.
Steps
-
Go to the Kudu and use SSH into your application container. [The app needs to be running for this to work] https://«webappname».scm.azurewebsites.net/webssh/host
- Copy default Tomcat configurations to /home.
mkdir -p /home/tomcat cp -R /usr/local/tomcat/conf /home/tomcat/
- Edit the server.xml under /home/tomcat/conf
Replace the following:
<!-- In AppService below is customized to add : unpackWARs="${site.unpackWARs}" and workDir="${site.tempdir}-->
<Host name="localhost" appBase="${site.root}"
unpackWARs="${site.unpackWARs}" autoDeploy="true" workDir="${site.tempdir}">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<!-- In AppService prefix and pattern are customized-->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="${site.logdir}/http/RawLogs"
prefix="site_access_log.${catalina.instance.name}" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D %{x-arr-log-id}i" />
</Host>
with:
<!-- In AppService below is customized to add : unpackWARs="${site.unpackWARs}" and workDir="${site.tempdir}-->
<Host name="localhost" appBase="${site.root}"
unpackWARs="${site.unpackWARs}" autoDeploy="true" workDir="${site.tempdir}">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Remote IP Valve -->
<Valve className="org.apache.catalina.valves.RemoteIpValve" />
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<!-- In AppService prefix and pattern are customized-->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="${site.logdir}/http/RawLogs"
prefix="site_access_log.${catalina.instance.name}" suffix=".txt"
pattern="%{X-Forwarded-For}i %l %u %t "%r" %s %b %D %{x-arr-log-id}i" />
</Host>
Now, restart the WebApp and you should see the originating client IP in the access logs available under /home/LogFiles/http/RawLogs
Know More
That’s it!