Express.js: how to get remote client address

node.jsExpressIpIp Address

node.js Problem Overview


I don't completely understand how I should get a remote user IP address.

Let's say I have a simple request route such as:

app.get(/, function (req, res){
   var forwardedIpsStr = req.header('x-forwarded-for');
   var IP = '';

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});

Is the above approach correct to get the real user IP address or is there a better way? And what about proxies?

node.js Solutions


Solution 1 - node.js

If you are running behind a proxy like NGiNX or what have you, only then you should check for 'x-forwarded-for':

var ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress 

If the proxy isn't 'yours', I wouldn't trust the 'x-forwarded-for' header, because it can be spoofed.

Solution 2 - node.js

While the answer from @alessioalex works, there's another way as stated in the Express behind proxies section of Express - guide.

  1. Add app.set('trust proxy', true) to your express initialization code.
  2. When you want to get the ip of the remote client, use req.ip or req.ips in the usual way (as if there isn't a reverse proxy)

Optional reading:

  • Use req.ip or req.ips. req.connection.remoteAddress does't work with this solution.
  • More options for 'trust proxy' are available if you need something more sophisticated than trusting everything passed through in x-forwarded-for header (for example, when your proxy doesn't remove preexisting x-forwarded-for header from untrusted sources). See the linked guide for more details.
  • If your proxy server does not populated x-forwarded-for header, there are two possibilities.
    1. The proxy server does not relay the information on where the request was originally. In this case, there would be no way to find out where the request was originally from. You need to modify configuration of the proxy server first.
    • For example, if you use nginx as your reverse proxy, you may need to add proxy_set_header X-Forwarded-For $remote_addr; to your configuration.
    1. The proxy server relays the information on where the request was originally from in a proprietary fashion (for example, custom http header). In such case, this answer would not work. There may be a custom way to get that information out, but you need to first understand the mechanism.

Solution 3 - node.js

In nginx.conf file:
proxy_set_header X-Real-IP $remote_addr;

In node.js server file:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

note that express lowercases headers

Solution 4 - node.js

Particularly for node, the documentation for the http server component, under event connection says:

> [Triggered] when a new TCP stream is established. [The] socket is an object of type > net.Socket. Usually users will not want to access this event. In > particular, the socket will not emit readable events because of how > the protocol parser attaches to the socket. The socket can also be > accessed at request.connection.

So, that means request.connection is a socket and according to the documentation there is indeed a socket.remoteAddress attribute which according to the documentation is:

> The string representation of the remote IP address. For example, > '74.125.127.100' or '2001:4860:a005::68'.

Under express, the request object is also an instance of the Node http request object, so this approach should still work.

However, under Express.js the request already has two attributes: req.ip and req.ips

> req.ip > > Return the remote address, or when "trust proxy" is enabled - the upstream address. > > req.ips > > When "trust proxy" is true, parse the "X-Forwarded-For" ip address list and return an array, otherwise an empty array is > returned. For example if the value were "client, proxy1, proxy2" you > would receive the array ["client", "proxy1", "proxy2"] where "proxy2" > is the furthest down-stream.

It may be worth mentioning that, according to my understanding, the Express req.ip is a better approach than req.connection.remoteAddress, since req.ip contains the actual client ip (provided that trusted proxy is enabled in express), whereas the other may contain the proxy's IP address (if there is one).

That is the reason why the currently accepted answer suggests:

> var ip = req.headers['x-forwarded-for'] || > req.connection.remoteAddress;

The req.headers['x-forwarded-for'] will be the equivalent of express req.ip.

Solution 5 - node.js

If you are fine using 3rd-party library. You can check request-ip.

You can use it is by

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});

The source code is quite long, so I won't copy here, you can check at https://github.com/pbojinov/request-ip/blob/master/src/index.js

Basically,

> It looks for specific headers in the request and falls back to some > defaults if they do not exist. > > The user ip is determined by the following order: > > 1. X-Client-IP
> 2. X-Forwarded-For (Header may return multiple IP addresses in the format: "client IP, proxy 1 IP, proxy 2 IP", so we take the the first > one.) > 3. CF-Connecting-IP (Cloudflare) > 4. Fastly-Client-Ip (Fastly CDN and Firebase hosting header when forwared to a cloud function) > 5. True-Client-Ip (Akamai and Cloudflare) > 6. X-Real-IP (Nginx proxy/FastCGI) > 7. X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray) > 8. X-Forwarded, Forwarded-For and Forwarded (Variations of #2) > 9. req.connection.remoteAddress > 10. req.socket.remoteAddress > 11. req.connection.socket.remoteAddress > 12. req.info.remoteAddress > > If an IP address cannot be found, it will return null.

Disclose: I am not associated with the library.

Solution 6 - node.js

  1. Add app.set('trust proxy', true)
  2. Use req.ip or req.ips in the usual way

Solution 7 - node.js

This is just additional information for this answer.

If you are using nginx, you would add proxy_set_header X-Real-IP $remote_addr; to the location block for the site. /etc/nginx/sites-available/www.example.com for example. Here is a example server block.

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    location / {
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_pass http://127.0.1.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

After restarting nginx, you will be able to access the ip in your node/express application routes with req.headers['x-real-ip'] || req.connection.remoteAddress;

Solution 8 - node.js

I know this question has been answered, but here's how I got mine to work.

let ip = req.connection.remoteAddress.split(`:`).pop();

Solution 9 - node.js

I wrote a package for that purpose. You can use it as express middleware. My package is published here: https://www.npmjs.com/package/express-ip

You can install the module using

npm i express-ip

Usage

const express = require('express');
const app = express();
const expressip = require('express-ip');
app.use(expressip().getIpInfoMiddleware);

app.get('/', function (req, res) {
    console.log(req.ipInfo);
});

Solution 10 - node.js

According to Express behind proxies, req.ip has taken into account reverse proxy if you have configured trust proxy properly. Therefore it's better than req.connection.remoteAddress which is obtained from network layer and unaware of proxy.

Solution 11 - node.js

This worked for me better than the rest. My sites are behind CloudFlare and it seemed to require cf-connecting-ip.

req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress

Didn't test Express behind proxies as it didn't say anything about this cf-connecting-ip header.

Solution 12 - node.js

var ip = req.connection.remoteAddress;

ip = ip.split(':')[3];

Solution 13 - node.js

In my case, similar to this solution, I ended up using the following x-forwarded-for approach:

let ip = (req.headers['x-forwarded-for'] || '').split(',')[0];

x-forwarded-for header will keep on adding the route of the IP from the origin all the way to the final destination server, thus if you need to retrieve the origin client's IP, this would be the first item of the array.

Solution 14 - node.js

The headers object has everything you need, just do this:

var ip = req.headers['x-forwarded-for'].split(',')[0];

Solution 15 - node.js

With could-flare, nginx and x-real-ip support

var user_ip;
    
    if(req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
      let first = req.headers['cf-connecting-ip'].split(', ');
      user_ip = first[0];
    } else {
      let user_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }

Solution 16 - node.js

Putting all together witk @kakopappa solution plus morgan logging of the client ip address:

morgan.token('client_ip', function getId(req) {
    return req.client_ip
});
const LOG_OUT = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :client_ip'
self.app.use(morgan(LOG_OUT, {
    skip: function(req, res) { // custom logging: filter status codes
        return res.statusCode < self._options.logging.statusCode;
    }
}));

// could-flare, nginx and x-real-ip support
var getIpInfoMiddleware = function(req, res, next) {
    var client_ip;
    if (req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
        var first = req.headers['cf-connecting-ip'].split(', ');
        client_ip = first[0];
    } else {
        client_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }
    req.client_ip = client_ip;
    next();
};
self.app.use(getIpInfoMiddleware);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionErikView Question on Stackoverflow
Solution 1 - node.jsalessioalexView Answer on Stackoverflow
Solution 2 - node.jsHaozhunView Answer on Stackoverflow
Solution 3 - node.jsququzoneView Answer on Stackoverflow
Solution 4 - node.jsEdwin DalorzoView Answer on Stackoverflow
Solution 5 - node.jsHongbo MiaoView Answer on Stackoverflow
Solution 6 - node.jsBaldView Answer on Stackoverflow
Solution 7 - node.jsjtlindseyView Answer on Stackoverflow
Solution 8 - node.jsLorem IpsumView Answer on Stackoverflow
Solution 9 - node.jsOyetoke TobiView Answer on Stackoverflow
Solution 10 - node.jsabbrView Answer on Stackoverflow
Solution 11 - node.jsileView Answer on Stackoverflow
Solution 12 - node.jsBhulawat AjayView Answer on Stackoverflow
Solution 13 - node.jsMenelaos KotsollarisView Answer on Stackoverflow
Solution 14 - node.jsJuan David ArceView Answer on Stackoverflow
Solution 15 - node.jskakopappaView Answer on Stackoverflow
Solution 16 - node.jsloretoparisiView Answer on Stackoverflow