14

I have a node application on an instance-store amazon machine behind the elastic load balancer (elb). However, the remote IP adress seems to always be the same. I used this code to get the client's IP address in node (via connect/express):

req.socket.remoteAddress

I didn't get anything else from the node documentation. Any hint?

starball
  • 20,030
  • 7
  • 43
  • 238

5 Answers5

10

Here's a solution in case you are using express:
According to the documentation, you can enable trust proxy for your express instance and then req.ip will be populated with the correct ip address.

By enabling the "trust proxy" setting via app.enable('trust proxy'), Express will have knowledge that it's sitting behind a proxy and that the X-Forwarded-* header fields may be trusted, which otherwise may be easily spoofed.

Enabling this setting has several subtle effects. The first of which is that X-Forwarded-Proto may be set by the reverse proxy to tell the app that it is https or simply http. This value is reflected by req.protocol.

The second change this makes is the req.ip and req.ips values will be populated with X-Forwarded-For's list of addresses.

Here's an example:

var app = express();
app.enable('trust proxy');
// ...

app.use(function(req, res, next) {
  console.log('client ip address:', req.ip);
  return next();
});
Michael
  • 22,196
  • 33
  • 132
  • 187
  • I was actually using this one for the last few years, but forgot about this question :) thanks for bringing it up again! – Johann Philipp Strathausen Oct 04 '14 at 12:36
  • 3
    express 4 have changed the way how [`trust proxy`](http://expressjs.com/api.html#trust.proxy.options.table) option is handled, so you can use something like `app.set('trust proxy', 1)` to only trust your load balancer – Juicy Scripter Mar 09 '15 at 19:55
  • By the way, in case of Amazon I think the value has to be `2`, one for the nginx on the actual machine, and another one is the actual load balancer. – Johann Philipp Strathausen Feb 05 '17 at 11:03
8

The answer worked for me, thanks. But you may just try:

var ip_address = null;
if(req.headers['x-forwarded-for']){
    ip_address = req.headers['x-forwarded-for'];
}
else {
    ip_address = req.connection.remoteAddress;
}
sys.puts( ip_address );
Mario Michelli
  • 523
  • 1
  • 5
  • 11
6

Your receiving the IP of the ELB instance and you'll need to get the x-forwarded-for value from the headers. Since I'm not a node.js guru, I found this code at http://forum.webfaction.com/viewtopic.php?id=4500

Example:

var http = require( 'http' ),
sys = require( 'sys' );

http.createServer(
        function( req, res ) {
                        var ip_address = null;
                        try {
                                ip_address = req.headers['x-forwarded-for'];
                        }
                        catch ( error ) {
                                ip_address = req.connection.remoteAddress;
                        }
                        sys.puts( ip_address );
        }
);
joet3ch
  • 2,236
  • 1
  • 21
  • 19
  • Cool thanks, just tried it and it works. I didn't know about that header. – Johann Philipp Strathausen Aug 22 '11 at 09:39
  • 7
    Is is not an error if `req.headers['x-forwarded-for']` does not exist. `ip_address` will just be `undefined`. `ip_address = req.headers['x-forwarded-for'] || req.connection.remoteAddress`;` will do the job – don_jones Feb 08 '12 at 14:58
1

The selected correct answer here is dangerous, because AWS ELBs switch the order as expected: https://github.com/koajs/koa/issues/1094#issuecomment-345861282

Express, koa, etc. typically take the left-most item, while ELB makes it the right-most item

(express docs):

If true, the client’s IP address is understood as the left-most entry in the X-Forwarded-For header.

danthegoodman
  • 501
  • 4
  • 10
1

In case if express.js is in use:

app.set('trust proxy', 2)

Instead of

app.enable('trust proxy')

Because the app.enable('trust proxy') uses the leftmost ip from the x-forwarded-for header and so can be easily spoofed by just providing x-forwarded-for header manually.

While the app.set('trust proxy', 2) has the number of hops specified that being counted from right to left of the x-forwarded-for header. I.e. if there is an AWS load balancer than 2 will be the right number to count because each new hop ip is added to the end of the x-forwarded-for header.

If you're using something else then do the similar way. Just get the req.headers['x-forwarded-for'], split by coma and then count hops from right to left until load balancer ip is not excluded.

AndrewK
  • 345
  • 3
  • 9