Express.js: how to get remote client address - node.js

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?

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.

While the answer from #alessioalex works, there's another way as stated in the Express behind proxies section of Express - guide.
Add app.set('trust proxy', true) to your express initialization code.
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.
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.
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.

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

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:
X-Client-IP
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.)
CF-Connecting-IP (Cloudflare)
Fastly-Client-Ip (Fastly CDN and Firebase hosting header when forwared to a cloud function)
True-Client-Ip (Akamai and Cloudflare)
X-Real-IP (Nginx proxy/FastCGI)
X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
X-Forwarded, Forwarded-For and Forwarded (Variations of #2)
req.connection.remoteAddress
req.socket.remoteAddress
req.connection.socket.remoteAddress
req.info.remoteAddress
If an IP address cannot be found, it will return null.
Disclose: I am not associated with the library.

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.

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

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;

I know this question has been answered, but here's how I got mine to work.
let ip = req.connection.remoteAddress.split(`:`).pop();

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);
});

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.

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.

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.

var ip = req.connection.remoteAddress;
ip = ip.split(':')[3];

The headers object has everything you need, just do this:
var ip = req.headers['x-forwarded-for'].split(',')[0];

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;
}

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);

Related

How to serve static files (CSS, ...) with multiples Express app + NGINX as reverse proxy server

Context
I'm runnig multiples nodesJS/Express app on the same server with the same IP adress.
I use Nginx to reverse proxy those apps and redirect it to subfolder adress (and not subdomain, i don't want to).
ex : http://123.0.0.1:8000 => http://monsite.com/Site1
Problem
My assets files (css, images, ...) do not load, I have a 404 error on those static files when the page loads. It happens only when I access the site via the proxy redirect http://monsite.com/Site1 and not when I use the IP adress : http://123.0.0.1:8000
I don't have this problem if a use the reverse proxy location from the root in the nginx conf :
location / {
but I want to access the site from a subfolder adress
My integration
Tree files:
var/www/html
|Site1/
| |server.js
| |Views/
| | |index.pug
| |Public/
| | |Css/
| | | |Style.css
|Site2/
|....
nodejs server code
const PORT = 8000;
const HOSTNAME = 'www.monsite.com';
// Dependencies.
const express = require('express');
const http = require('http');
// Initialization.
var app = express();
var server = http.Server(app);
app.set('port', PORT);
app.set('view engine', 'pug');
app.set('views','Views');
app.use(express.static('Public'));
app.use('/', (request, response) => {
response.render('index');
});
server.listen(PORT, HOSTNAME, function() {
console.log(`STARTING SERVER ON PORT ${PORT}`);
});
index pug code
doctype html
html
head
title Site 1
link(rel="stylesheet" href="/Css/style.css")
body
p Hello
nginx conf
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html index.php;
server_name www.monsite.com;
location / {
#Reserved for another site
}
location /Site1/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
proxy_pass http://123.0.0.1:8000/;
}
}
PS : I tried almost all the solutions and code I found searching for this problem and nothing worked, that's why I'm asking directly here. Thank you.
I think the issue is with the url in the link tag to load the css, the url is invalid because the url is actually /Site1/Css/style.css.

how to make Nodejs redirect work when called via Vuejs

I have created and tested the POST and GET request methods in Nodejs such that I can send the user through the Gocardless sign-up API perfectly fine.
This is a sign-up form provided by their API which allows them to input their details and then returns the user back after they fill it in.
But when I set up a front-end using Vuejs and make the same calls previously made from the back end using Axios, it seems that because the "redirect_url" fed back to me from the GC API had previously been fed directly into the browser url before, now, because it seems vue-router has control of the browser, I'm getting a cross origin error.
How can I configure the files to have the Nodejs back end acting as if it had control of the browser?
The end points are described here:
https://developer.gocardless.com/api-reference/#core-endpoints-redirect-flows
My nginx default is:
server {
charset UTF-8;
listen 80;
root /srv/www/sitename/;
index index.html;
server_name sitename.com;
location /api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://sitename.com:8081;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_redirect off;
}
location / {
try_files $uri.html $uri $uri/ /index.html;
}
My button from Vuejs front end:
completeOrder()
..and uses axios this way:
import axios from 'axios'
export default() => {
return axios.create({
baseURL: 'http://sitename.com:8081/api'
})
}
And set it up here:
import Api from '#/services/Api'
export default {
completeOrder () {
return Api().post('order')
}
}
In the back end it sends:
app.post('/api/order', function (req, res){
rp({
//rp is npm request-promise
uri: BASE_URL + "/redirect_flows",
method: 'POST',
body:JSON.stringify(input_json),
headers: headers
}) // this works and API sends me the response
.then(function(response) {
var str_response =JSON.parse(response);
url = str_response['redirect_flows']['redirect_url']
// url works fine when I paste into a separate browser
res.redirect(url)
})
.catch(function (err) {
console.error(err);
})
})
Everything works up until the point:
res.redirect(url)
..where the Gocardless API response supplies me with the URL which I need to load into a browser.
It looks something like this:
https://pay-sandbox.gocardless.com/flow/RE000156
I think I need to break out of Vuejs's control of the browser via vue-router just long enough to allow the user to call the form with the redirect_url, then come back to the home page of the app again.
Any ideas very welcome!
I think you actually have a JS error. In the then block you instantiate a response, but you use a res variable to redirect.
Try chaging the variable
.then(function(response) {
var str_response = JSON.parse(response);
url = str_response['redirect_flows']['redirect_url']
// url works fine when I paste into a separate browser
response.redirect(url)
})
I am not a Vue.JS expert, so I don't know if that works, try using a vanilla JS redirect to test this feature:
window.location.href = url;
This way, you will be sure that the url works. After that, try checking out a full Vue.JS option.

node.js: route request to different port on same host

I have a host computer which serves a number of webapplications (not node.js based). It does this using different ports. This means that for example the following applications are live:
app1: http://hostname:3000
app2: http://hostname:3001
app3: http://hostname:3003
Next to that I have a node.js based webapp (running on port 80) which I want to use as a sort of router. When someone navigates to http://localhost/app/app1. I want it to navigate to http://hostname:3000. This is relatively straightforward using a simple redirect. However, I would want to preserve the url http://localhost/app/app1. Can someone point me to a way to make this work using node.js/express?
My routing logic looks somewhat like this (pseudo-code).
app.route('/app/:appName')
.get(appEngine.gotoApp);
appEngine.gotoApp = function(req, res) {
redirectToApp logic
}
You probably better use Nginx setting up a reverse proxy with different locations per application.
It's not what you ask for because it does not use node.js, but if it's the only purpose, Nginx really suits your needs.
For example a Nginx configuration file like should work the way you want :
server {
listen 80;
server_name myapp.com;
location /app1 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:3000;
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;
}
location /app2 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:3001;
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;
}
location /app3 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:3003;
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;
}
}
If you use express, you can try to create the app with the cli express application generator.
It creates an express app and returns it with module exports.
In the server.js file it pass to listen function of the server instance the express app object.
You can create more server object and listen different app with different port.
var server = http.createServer(app);
server.listen(port);
var server2 = http.createServer(app2);
server2.listen(port2);
If you want to point different app based on the url, you can instance an express router instead of express object.
var app1 = express.Router();
Then you can set all your routes into this object with classic get or post or other methods.
Now you are able to pass the router as a middleware of your main express app.
app.use( "app1/", app1 );
You can also pass an express app to middleware, instead of router object, in order to gain the possibility of exec the app with a different url and port server listening.
There is a nice http-proxy lib designed exactly for that!
const httpProxy = require('http-proxy');
const url = require('url');
const proxy = httpProxy.createProxy();
const options = {
'/app/app1': 'http://localhost:3000',
'/app/app2': 'http://localhost:3001',
'/app/app3': 'http://localhost:3003',
}
require('http').createServer((req, res) => {
const pathname = url.parse(req.url).pathname;
for (const [pattern, target] of Object.entries(options)) {
if (pathname === pattern ||
pathname.startsWith(pattern + '/')
) {
proxy.web(req, res, {target});
}
}
}).listen(80);

How to determine a user's IP address in node

How can I determine the IP address of a given request from within a controller? For example (in express):
app.post('/get/ip/address', function (req, res) {
// need access to IP address here
})
In your request object there is a property called socket, which is a net.Socket object. The net.Socket object has a property remoteAddress, therefore you should be able to get the IP with this call:
request.socket.remoteAddress
(if your node version is below 13, use the deprecated now request.connection.remoteAddress)
EDIT
As #juand points out in the comments, the correct method to get the remote IP, if the server is behind a proxy, is request.headers['x-forwarded-for']
EDIT 2
When using express with Node.js:
If you set app.set('trust proxy', true), req.ip will return the real IP address even if behind proxy. Check the documentation for further information
var ip = req.headers['x-forwarded-for'] ||
req.socket.remoteAddress ||
null;
Note that sometimes you can get more than one IP address in req.headers['x-forwarded-for']. Also, an x-forwarded-for header will not always be set which may throw an error.
The general format of the field is:
x-forwarded-for: client, proxy1, proxy2, proxy3
where the value is a comma+space separated list of IP addresses, the left-most being the original client, and each successive proxy that passed the request adding the IP address where it received the request from. In this example, the request passed through proxy1, proxy2, and then proxy3. proxy3 appears as remote address of the request.
This is the solution suggested by Arnav Gupta with a fix Martin has suggested below in the comments for cases when x-forwarded-for is not set :
var ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() ||
req.socket.remoteAddress
Suggestion using modern JS:
processing x-forwarded-for only if set, if so, take the first address
other parameters use optional chaining (?.)
const parseIp = (req) =>
req.headers['x-forwarded-for']?.split(',').shift()
|| req.socket?.remoteAddress
console.log(parseIp(req))
// => 127.0.0.1
If using express...
req.ip
I was looking this up then I was like wait, I'm using express. Duh.
You can stay DRY and just use node-ipware that supports both IPv4 and IPv6.
Install:
npm install ipware
In your app.js or middleware:
var getIP = require('ipware')().get_ip;
app.use(function(req, res, next) {
var ipInfo = getIP(req);
console.log(ipInfo);
// { clientIp: '127.0.0.1', clientIpRoutable: false }
next();
});
It will make the best attempt to get the user's IP address or returns 127.0.0.1 to indicate that it could not determine the user's IP address. Take a look at the README file for advanced options.
You can use request-ip, to retrieve a user's ip address. It handles quite a few of the different edge cases, some of which are mentioned in the other answers.
Disclosure: I created this module
Install:
npm install request-ip
In your app:
var requestIp = require('request-ip');
// inside middleware handler
var ipMiddleware = function(req, res, next) {
var clientIp = requestIp.getClientIp(req); // on localhost > 127.0.0.1
next();
};
Hope this helps
request.headers['x-forwarded-for'] || request.connection.remoteAddress
If the x-forwarded-for header is there then use that, otherwise use the .remoteAddress property.
The x-forwarded-for header is added to requests that pass through load balancers (or other types of proxy) set up for HTTP or HTTPS (it's also possible to add this header to requests when balancing at a TCP level using proxy protocol). This is because the request.connection.remoteAddress the property will contain the private IP address of the load balancer rather than the public IP address of the client. By using an OR statement, in the order above, you check for the existence of an x-forwarded-for header and use it if it exists otherwise use the request.connection.remoteAddress.
Following Function has all the cases covered will help
var ip;
if (req.headers['x-forwarded-for']) {
ip = req.headers['x-forwarded-for'].split(",")[0];
} else if (req.connection && req.connection.remoteAddress) {
ip = req.connection.remoteAddress;
} else {
ip = req.ip;
}console.log("client IP is *********************" + ip);
Warning:
Don't just blindly use this for important rate-limiting:
let ip = request.headers['x-forwarded-for'].split(',')[0];
It's very easy to spoof:
curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"
In that case ther user's real IP address will be:
let ip = request.headers['x-forwarded-for'].split(',')[1];
I'm surprised that no other answers have mentioned this.
I have tried all of them didn't work though,
console.log(clientIp);
console.log(req.ip);
console.log(req.headers['x-forwarded-for']);
console.log(req.connection.remoteAddress);
console.log(req.socket.remoteAddress);
console.log(req.connection.socket.remoteAddress.split(",")[0]);
When running an Express app behind a proxy for me Nginx, you have to set the application variable trust proxy to true. Express offers a few other trust proxy values which you can review in their documentation, but below steps worked for me.
app.set('trust proxy', true) in your Express app.
app.set('trust proxy', true);
Add proxy_set_header X-Forwarded-For $remote_addr in the Nginx
configuration for your server block.
location / {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr; # this line
proxy_cache_bypass $http_upgrade;
}
You can now read off the client’s IP address from the
req.header('x-forwarded-for') or req.connection.remoteAddress; Full code for ipfilter
module.exports = function(req, res, next) {
let enable = true; // true/false
let blacklist = ['x.x.x.x'];
let whitelist = ['x.x.x.x'];
let clientIp = req.header('x-forwarded-for') || req.connection.remoteAddress;
if (!clientIp) {
return res.json('Error');
}
if (enable
&& paths.some((path) => (path === req.originalUrl))) {
let blacklist = blacklist || [];
if (blacklist.some((ip) => clientIp.match(ip) !== null)) {
return res.json({ status: 401, error: 'Your IP is black-listed !'});
}
let whitelist = whitelist || [];
if (whitelist.length === 0 || whitelist.some((ip) => clientIp.match(ip) !== null)) {
next();
return;
} else {
return res.json({ status: 401, error: 'Your IP is not listed !'});
}
}
next();
};
There are two ways to get the ip address :
let ip = req.ip
let ip = req.connection.remoteAddress;
But there is a problem with above approaches.
If you are running your app behind Nginx or any proxy, every single IP addresses will be 127.0.0.1.
So, the best solution to get the ip address of user is :-
let ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
function getCallerIP(request) {
var ip = request.headers['x-forwarded-for'] ||
request.connection.remoteAddress ||
request.socket.remoteAddress ||
request.connection.socket.remoteAddress;
ip = ip.split(',')[0];
ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
return ip;
}
In node 10.14 , behind nginx, you can retrieve the ip by requesting it through nginx header like this:
proxy_set_header X-Real-IP $remote_addr;
Then in your app.js:
app.set('trust proxy', true);
After that, wherever you want it to appear:
var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;
If you're using express version 3.x or greater, you can use the trust proxy setting (http://expressjs.com/api.html#trust.proxy.options.table) and it will walk the chain of addresses in the x-forwarded-for header and put the latest ip in the chain that you've not configured as a trusted proxy into the ip property on the req object.
If you're using express.js then,
app.post('/get/ip/address', function (req, res) {
res.send(req.ip);
})
var ipaddress = (req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress).split(",")[0];
If you get multiple IPs , this works for me:
var ipaddress = (req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress).split(",")[0];
Simple get remote ip in nodejs:
var ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
req.connection has been deprecated since node#12.12.0. Using req.connection.remoteAddress to get the client IP might still work but is discouraged.
Luckily, req.socket.remoteAddress has been there since node#0.5.10 and is a perfect replacement:
The string representation of the remote IP address. For example, '74.125.127.100' or '2001:4860:a005::68'. Value may be undefined if the socket is destroyed (for example, if the client disconnected).
There were a lot of great points here but nothing that was comprehensive, so here's what I ended up using:
function getIP(req) {
// req.connection is deprecated
const conRemoteAddress = req.connection?.remoteAddress
// req.socket is said to replace req.connection
const sockRemoteAddress = req.socket?.remoteAddress
// some platforms use x-real-ip
const xRealIP = req.headers['x-real-ip']
// most proxies use x-forwarded-for
const xForwardedForIP = (() => {
const xForwardedFor = req.headers['x-forwarded-for']
if (xForwardedFor) {
// The x-forwarded-for header can contain a comma-separated list of
// IP's. Further, some are comma separated with spaces, so whitespace is trimmed.
const ips = xForwardedFor.split(',').map(ip => ip.trim())
return ips[0]
}
})()
// prefer x-forwarded-for and fallback to the others
return xForwardedForIP || xRealIP || sockRemoteAddress || conRemoteAddress
}
I realize this has been answered to death, but here's a modern ES6 version I wrote that follows airbnb-base eslint standards.
const getIpAddressFromRequest = (request) => {
let ipAddr = request.connection.remoteAddress;
if (request.headers && request.headers['x-forwarded-for']) {
[ipAddr] = request.headers['x-forwarded-for'].split(',');
}
return ipAddr;
};
The X-Forwarded-For header may contain a comma-separated list of proxy IPs. The order is client,proxy1,proxy2,...,proxyN. In the real world, people implement proxies that may supply whatever they want in this header. If you are behind a load balancer or something, you can at least trust the first IP in the list is at least whatever proxy some request came through.
I use this for ipv4 format
req.connection.remoteAddress.split(':').slice(-1)[0]
You can Get User Ip with Express Like this
req.ip
For Example In This case we get the user Ip and send it back to the user With req.ip
app.get('/', (req, res)=> {
res.send({ ip : req.ip})
})
If you are using Graphql-Yoga you can use the following function:
const getRequestIpAddress = (request) => {
const requestIpAddress = request.request.headers['X-Forwarded-For'] || request.request.connection.remoteAddress
if (!requestIpAddress) return null
const ipv4 = new RegExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
const [ipAddress] = requestIpAddress.match(ipv4)
return ipAddress
}
I'm using express behind nginx and
req.headers.origin
did the trick for me
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
var ip = req.ip
console.log(ip);
res.send('Hello World!')
})
// Run as nodejs ip.js
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
In a shell, you would just curl https://api.ipify.org
So, let's observe this to port it to node.js!
curl is a application to fetch data from websites, we pass the website "https://api.ipify.org" as the argument. We could use node-fetch to replace curl!
The data we get from the website is our IP address, It's some sort of thing which just fetches your IP.
So to sum it up:
const fetch = require('node-fetch');
fetch('https://api.ipify.org')
.then(response => {/* whatever */})
.catch(err => {/* whatever */})
First, install request-ip in your project
import requestIp from 'request-ip';
const clientIp = requestIp.getClientIp(req);
console.log(clientIp)
If you work on localhost, the result might come ::1 because ::1 is real IP Address and is IPV6 notation for localhost.
Using ValidatorJS in Typescript. Here is NodeJS middleware:
// Extract Client IP Address
app.use((req, res, next) => {
let ipAddress = (req.headers['x-forwarded-for'] as string || '').split(',')[0]
if (!validator.isIP(ipAddress))
ipAddress = req.socket.remoteAddress?.toString().split(':').pop() || ''
if (!validator.isIP(ipAddress))
return res.status(400).json({errorMessage: 'Bad Request'})
req.headers['x-forwarded-for'] = ipAddress
next()
})
Here I am assuming all requests should have a valid IP address and hence return a response with code 400 if there is no valid IP address found.
For me using kubernetes ingress (NGINX):
req.headers['x-original-forwarded-for']
Worked like a charm in Node.js
we can check with this code in node js
const os = require('os');
const interfaces = os.networkInterfaces();
let addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
const address = interfaces[k][k2];
if ( (address.family === 'IPv4' || address.family === 'IPv6') &&
!address.internal) {
addresses.push(address.address);
}
}
}
console.log(addresses);

Remote IP address with node-js behind amazon ELB

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?
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();
});
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 );
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 );
}
);
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.
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.

Resources