Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vhost ip filter express node

I'm using vhost with express to manage two subdomain. All work well but I would like to filter the request for one of the subdomain by ip. Do you know if it's possible to do ?

I've tried to manage it in the app.js of my subdomain site but the req.connection.remoteAddress and req.ip give me the ip of my server.

When I've got only one subdomain and don't use vhost I've got the right ip, but since I used vhost I've got the ip of my server ...

Here is my folder structure before :

-- subdomain1/
    -- app.js
    -- views/

Here is my new structure :

-- subdomain1/
    -- app.js
    -- views/
-- subdomain2/
    -- app.js
    -- views/
-- manageSubdomain/
    -- app.js

Here is my code when it work before using vhost and for only one subdomain :

subdomain1/app.js :

var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
require('body-parser-xml')(bodyParser);

var routes = require('./routes/index');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// Example middleware to get ip
app.use(function (req, res) {
    console.log(req.ip); // it give me the correct IP
});

app.use('/', routes);

module.exports = app;

And the file who manage the server before :

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('webservicePrestashop:server');
var https = require('https');
var fs = require('fs');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '443');
app.set('port', port);

/**
 * Create HTTP server.
 */

//var server = http.createServer(app);
var options = {
     key: fs.readFileSync('/path/to/privkey.pem'),
     cert: fs.readFileSync('/path/to/fullchain.pem'),
     ca: fs.readFileSync('/path/to/chain.pem')
}
var server = https.createServer(options, app);

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

Here is my code to manage subdomain :

manageSubdomain/app.js :

var express = require('express');
var vhost = require('vhost');
var http = require('http');
var https = require('https');
var fs = require('fs');
var tls = require('tls');

// Gestions des sites
const subdomain1 = {
    app: require('../subdomain1/app'),
    context: tls.createSecureContext({
        key: fs.readFileSync('path/to/privkey.pem').toString(),
        cert: fs.readFileSync('path/to/privkey.pem/fullchain.pem').toString(),
        ca: fs.readFileSync('path/to/privkey.pem/chain.pem').toString()
    }).context
};
const subdomain2 = {
    app: require('../subdomain2/app'),
    context: tls.createSecureContext({
        key: fs.readFileSync('path/to/privkey.pem/privkey.pem').toString(),
        cert: fs.readFileSync('path/to/privkey.pem/fullchain.pem').toString(),
        ca: fs.readFileSync('path/to/privkey.pem/chain.pem').toString()
    }).context
};
var sites = {
    "my.subdomain1.com": subdomain1,
    "my.subdomain2.com": subdomain2
};

var exp = express();
for (let s in sites) {
  exp.use(vhost(s, sites[s].app));
}

// Redirect du http to https
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

var secureOpts = {
    SNICallback: function (domain, cb) {
        if (typeof sites[domain] === "undefined") {
            cb(new Error("domain not found"), null);
            console.log("Error: domain not found: " + domain);
        } else {
            cb(null, sites[domain].context);
        }
    },
    key: fs.readFileSync('path/to/privkey.pem/privkey.pem').toString(),
    cert: fs.readFileSync('path/to/privkey.pem/fullchain.pem').toString()
};

// Création du serveur https
var httpsServer = https.createServer(secureOpts, exp);
httpsServer.listen(443);

Now my subdomain1/app.js is the same than before

like image 831
jean-max Avatar asked Nov 08 '22 18:11

jean-max


1 Answers

Have you tried with the req.ip property?

Express documentation says:

Contains the remote IP address of the request.

When the trust proxy setting does not evaluate to false, the value of this property is derived from the left-most entry in the X-Forwarded-For header. This header can be set by the client or by the proxy.

To debug your code, add a logging middleware before adding any app to the express object:

var exp = express();

// ip logging middleware
app.use(function (req, res, next) {
    console.log(req.ip);
    next();
});

for (let s in sites) {
  exp.use(vhost(s, sites[s].app));
}

Then, add the same middleware as the first middleware of your sub apps. In this way you can be sure that the problem is caused by the vhost module.

like image 179
lifeisfoo Avatar answered Nov 15 '22 11:11

lifeisfoo