Saturday, September 12, 2009

Amazon ELB - Capturing Client IP Address

If you're using Amazon EC2's Elastic Load Balancer (ELB) for load balancing web applications, you may have noticed that in your web access logs, the remote host IP address is the same for every request. The IP address you see is the private IP address of the load balancer.

If you want to see the IP address of the client (called remote host in access log documentation), you'll need to look at the value of the X-Forwarded-For request header which ELB populates when it forwards the request.

This can be achieved in an Apache access log by using the syntax:
%{X-Forwarded-For}i
You Apache log format would then look something like this:
LogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined-elb
CustomLog log/acces_log combined-elb
See Apache Custom Log Formats

If you're using a Tomcat application server, you could define an access log Valve like this:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="access_log." suffix=".txt"
pattern="%{X-Forwarded-For}i %l %u %t &quot;%r&quot; %s %b &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"
resolveHosts="false"/>
See Tomcat 6 Valve Configuration Reference.

If you're trying to capture the client IP address within your application code, simply use whatever API you have to read the X-Forwarded-For request header. For example in Java use the HttpServletRequest:
String clientIpAddress = request.getHeader("X-Forwarded-For");
instead of
String clientIpAddress = request.getRemoteAddr();

10 comments:

sind26 said...

Thanks Ken,

I was wondering to get the external ip's in the access_log using while using elb.Your post was helpful.You saved my day.

Martin.M

Unknown said...

For some strange reason this isn't working for me.. My logs continue to show the ELB IP.

grourk said...

Is there any way to get the external IP for HTTPS requests? ELB only seems to set HTTP_X_FORWARDED_FOR for HTTP, which makes sense because for HTTPS it just does forwarding at the TCP level. Unfortunately I can't think of a way to get the client's IP address in this case.

Andy said...

This is very helpful, thanks for posting.

Dan Franklin said...

Here's what was causing our health checks to fail: we use name-based virtual hosting in Apache, and the first (default) vhost just redirects to our main vhost. Turns out that ELB does not supply a Host: header, so it hits this default vhost, and when it gets a 301 redirect it calls it a failure!

Solution is to have a file that your default vhost is willing to serve up, and call out that file in the ELB health check. I.e. before the default vhost redirects, check whether the incoming URL is this special file (we use arrowpoint.html for historical reasons) and skip the redirect in that case.

Anonymous said...

for IIS, follow this:
http://www.powercram.com/2011/10/amazon-elb-iis-capturing-client-ip.html

It works for me.

Scott McCarthy said...

Many thanks, this saved me a lot of work!

Anonymous said...

This is awesome! well done!

Anonymous said...

CustomLog log/acces_log combined-elb should be in this form

CustomLog "log/acces_log" combined-elb

thank you very much for the tip

thufael said...

Not sure if this works for an ELB with TCP passthrough enabled. Is there a way to capture true client ip when the ELB listener is configured in TCP passthrough mode. This is done for a purpose to support MATLS.