What is nodejs express manage several domains? - node.js

I have got 2 domain names. For instance, example0.org and example1.org.
How to setup nodejs using express to manage both of them?
For instance, I wanna share
/publicexample0
folder as root for
example0.org
and
/publicexample1
folder for
example1.org
as root
This works just for a one domain:
var app = express.createServer();
app.get('/', function(req, res) {
res.send('Hello World');
});
app.listen(3000);

I guess what you can do is to take advantage of the HTTP host header. It contains:
The domain name of the server (for virtual hosting), and the TCP port
number on which the server is listening. The port number may be
omitted if the port is the standard port for the service requested.
Mandatory since HTTP/1.1.
You can see its specification in the RFC 2616 - HTTP v1.1
And obviously you could read the header out of your request in Express and make a decision based on its value.
router.get('/hello', function(req, res){
var host = req.get('host');
if(host === 'example0.org'){
res.send(200,'Welcome from example0.org');
} else if(host === 'example1.org'){
res.send(200,'Welcome from example1.org');
} else {
res.send(200,'Welcome stranger');
}
});

Related

I need to know where user came from node js

I have a back-end by nodejs I need to know where user come from.
if he came from localhost (postman) or his website HTTP request.
I need to know his user domain's not mind like 'http://localhost/' or 'http://user-website.com' or even from google search ! from he is came ?
, I tried user req.get('origin) but always return undefined
You must connect 'url' module
var http = require('http');
var url = require('url') ;
http.createServer(function (req, res) {
var hostname = req.headers.host; // hostname = 'localhost:8080'
var pathname = url.parse(req.url).pathname; // pathname = '/MyApp'
console.log('http://' + hostname + pathname);
res.writeHead(200);
res.end();
}).listen(8080);
use req.headers['user-agent'] to see if it is postman agent or not.
In order to know whether the request is coming from localhost or a remote client, you'll need to obtain the client's IP address. Example in Express:
app.get('/', (req, res) => {
const ipAddress = req.connection.remoteAddress;
// ...
});
More docs about getting the IP here, also check this other question on the subject.
Basically if the request is coming from localhost, ipAddress will be ::1 or other localhost IP address, but if it's not, it's going to look like a public IP address, like 173.194.79.101 (the IP of google.com).

Req.secure in Node alwys false

Im trying to redirect HTTP requests to my site to HTTPS. Its been extraordinarily hard. My code is:
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log('req.protocol is ', req.protocol);
console.log('req.secure is ', req.secure);
if (req.url !== '/health' && !req.secure) {
console.log('redirecting .........');
return res.redirect('https://www.example.net/catch');
}
next();
});
app.get('/catch', function(req, res) {
res.send('Hello World!');
});
app.get('/', function(req, res) {
res.send('Hello World!');
});
app.get('/health', function(req, res) {
res.send('Hello World!');
});
app.listen(8080, function() {
console.log('Example app listening on port 8080!');
});
The load Balancer health check goes to '/health'. Every other request that isnt a health check, and is HTTP (rather than HTTPS) should be caught and redirected to https. However, I end up in an infinite loop as req.protocol always returns 'http' for http or https requests. req.secure therefore is false every time and I end up in a loop. Any ideas why this is?
It sounds like you installed the SSL certificate on your Elastic Load Balancer, so that's where SSL Termination is happening. So your load balancer is doing the SSL termination and always communicating with your server via HTTP. This means you have to check the 'x-forwarded-proto' header to determine if the original request is over HTTPS.
There are several other ways to configure SSL on AWS, including termination on the web server, but SSL termination on the ELB is the generally preferred method on AWS. You just have to be aware that in this configuration the request between the ELB and the web server isn't actually over SSL so you have to check the header accordingly.
Looks like req.protocol will always be 'http' on Amazon Web Services. Now im using:
req.get('x-forwarded-proto')

Node.js multiple subdomains

I am using node.js to build a multi-tenant application where different clients with their own subdomains will be accessing a single instance of my app. My questions is:
Is there a way for the app to find out which subdomain a user is on? That way, I can route the user to the correct database schema (postgresql).
Thanks in advance!
Additional information:
I am using the Express framework
I'm not using multiple instances because I expect to have upwards of thousands of users and I don't want to manage thousands of instances.
Regarding subdomains, I mean something like:
myapp.client1domain.com
myapp.client2domain.com
myapp.client3domain.com
Each of the above url's link to the same instance of the app. However, I need to know which subdomain a user is on so I can route them to the right database schema.
Since "host" from HTTP/1.1 or greater is reflected in the request object as "host" header. You could do something like:
const setupDatabaseScheme = (host, port) => {
// ...
};
http.createServer((req, res) => {
if (req.headers.host) {
const parts = req.headers.host.split(":");
setupDataBaseSchema(parts[0], parts[1]);
}
});
Please note that port might be undefined; and do additional checks, add error handling if there is no host header or HTTP version is below 1.1. Of course you could do similar as an express middleware, or with any similar framework, this is just bare node.js http.
Update:
In express I'd do something like:
const getConnecitonForSchemeByHost = (host) => {
// ... get specific connection for given scheme from pool or similar
return "a connection to scheme by host: " + host;
};
router
.all("*", function (req, res, next) {
const domain = req.get("host").split(":")[0];
const conn = res.locals.dbConnection = getConnecitonForSchemeByHost(domain);
if (conn) {
next();
} else {
next(new Error("no connection for domain: " + domain))
}
})
.get("/", function (req, res) { // use connection from res.locals at further routes
console.log(res.locals.dbConnection);
res.send("ok");
});
app.use("/db", router);
req.get("host") gives you back the host the request was directed to, e.g. myapp.client1domain.com or so (match specific part with regexp) and based on that you could set a property on res.locals which you could use on subsequent routes, or bail out in case of an unknown domain.
The above snipped would log "a connection to scheme by host: localhost", if you do a request to http://localhost:<port>/db.

Express wildcard rule

I am hosting a single page app with Node and Express. I use the static middleware for the client. I am using path URLs to navigate the app, for example domain.com/profile/134. I am using history.pushState to change pages internally on the client, and this works fine. What I am missing is a wildcard rule on the server to catch all possible paths when the user accesses my page directly to a path that is not root. If I try to access domain.com/profile/134 directly I get this: "Cannot GET /profile/134". I have tried to insert a wildcard get at the end of server.js, but it seems to be hit every time, also when I access the page root. This is my relevant code:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/../client'));
app.get('/*', function(req, res) {
console.log('wildcard');
});
Is this the correct GET wildcard rule to achieve what I need, and how can I serve the static client inside this handler? My client side will find the right page afterwards as long as the initial path is preserved. I basically want this wildcard rule to behave the same as the static rule, but keep the initial path.
You can use a hack
app.get('/:url', function(req, res) {
console.log('wildcard');
});
or try this one
app.get('/(.*)', function(req, res) {
console.log('wildcard');
});
[edited]: this should work as you expect:
var express = require('express');
var app = express();
app.get(/(.*)/, function(req, res) {
console.log("req.path", req.path);
res.send('success');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
I ended up using an npm module named express-history-fallback-api to solve this. Out of the box it solved both simple and advanced paths, like domain.com/settings and domain.com/profile/username
https://www.npmjs.com/package/express-history-api-fallback

How do I host multiple Node.js sites on the same IP/server with different domains?

I have a linux server with a single IP bound to it. I want to host multiple Node.js sites on this server on this IP, each (obviously) with a unique domain or subdomain. I want them all on port 80.
What are my options to do this?
An obvious solution seems to be to have all domains serviced by a node.js web app that acts as a proxy and does a pass through to the other node.js apps running on unique ports.
Choose one of:
Use some other server (like nginx) as a reverse proxy.
Use node-http-proxy as a reverse proxy.
Use the vhost middleware if each domain can be served from the same Connect/Express codebase and node.js instance.
Diet.js has very nice and simple way to host multiple domains with the same server instance. You can simply call a new server() for each of your domains.
A Simple Example
// Require diet
var server = require('diet');
// Main domain
var app = server()
app.listen('http://example.com/')
app.get('/', function($){
$.end('hello world ')
})
// Sub domain
var sub = server()
sub.listen('http://subdomain.example.com/')
sub.get('/', function($){
$.end('hello world at sub domain!')
})
// Other domain
var other = server()
other.listen('http://other.com/')
other.get('/', function($){
$.end('hello world at other domain')
})
Separating Your Apps
If you would like to have different folders for your apps then you could have a folder structure like this:
/server
/yourApp
/node_modules
index.js
/yourOtherApp
/node_modules
index.js
/node_modules
index.js
In /server/index.js you would require each app by it's folder:
require('./yourApp')
require('./yourOtherApp')
In /server/yourApp/index.js you would setup your first domain such as:
// Require diet
var server = require('diet')
// Create app
var app = server()
app.listen('http://example.com/')
app.get('/', function($){
$.end('hello world ')
})
And in /server/yourOtherApp/index.js you would setup your second domain such as:
// Require diet
var server = require('diet')
// Create app
var app = server()
app.listen('http://other.com/')
app.get('/', function($){
$.end('hello world at other.com ')
});
Read More:
Read more about Diet.js
Read more about Virtual Hosts in Diet.js
Read more about Server in Diet.js
Hm ... why you think that nodejs should act as a proxy. I'll suggest to run several node apps listening on different ports. Then use nginx to forward the request to the right port. If use a single nodejs you will have also single point of failure. If that app crashes then all the sites go down.
Use nginx as a reverse proxy.
http://www.nginxtips.com/how-to-setup-nginx-as-proxy-for-nodejs/
Nginx brings a whole host of benefits to your applications in the form of caching, static file handling, ssl and load balancing.
I have an API I use on a site and below is my configuration. I also have it with SSL and GZIP, if someone needs it, just comment me.
var http = require('http'),
httpProxy = require('http-proxy');
var proxy_web = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8080
}
});
var proxy_api = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 8081
}
});
http.createServer(function(req, res) {
if (req.headers.host === 'http://www.domain.com') {
proxy_web.proxyRequest(req, res);
proxy_web.on('error', function(err, req, res) {
if (err) console.log(err);
res.writeHead(500);
res.end('Oops, something went very wrong...');
});
} else if (req.headers.host === 'http://api.domain.com') {
proxy_api.proxyRequest(req, res);
proxy_api.on('error', function(err, req, res) {
if (err) console.log(err);
res.writeHead(500);
res.end('Oops, something went very wrong...');
});
}
}).listen(80);
If you are using connect/express server, you can see the vhost middleware. It will allow multiple domains(sub-domains) to be used for the server address.
You can follow the example given here, which looks exactly like what you need.
Here's how to do it using vanilla Node.js:
const http = require('http')
const url = require('url')
const port = 5555
const sites = {
exampleSite1: 544,
exampleSite2: 543
}
const proxy = http.createServer( (req, res) => {
const { pathname:path } = url.parse(req.url)
const { method, headers } = req
const hostname = headers.host.split(':')[0].replace('www.', '')
if (!sites.hasOwnProperty(hostname)) throw new Error(`invalid hostname ${hostname}`)
const proxiedRequest = http.request({
hostname,
path,
port: sites[hostname],
method,
headers
})
proxiedRequest.on('response', remoteRes => {
res.writeHead(remoteRes.statusCode, remoteRes.headers)
remoteRes.pipe(res)
})
proxiedRequest.on('error', () => {
res.writeHead(500)
res.end()
})
req.pipe(proxiedRequest)
})
proxy.listen(port, () => {
console.log(`reverse proxy listening on port ${port}`)
})
Pretty simple, huh?
First install forever and bouncy.
Then write a startup script. In this script, add a rule to the iptables firewall utility to tell it to forward the traffic on port 80 to port 8000 (or anything else that you choose). In my example, 8000 is where I run bouncy
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000
Using forever, let's tell the script to run bouncy on port 8000
forever start --spinSleepTime 10000 /path/to/bouncy /path/to/bouncy/routes.json 8000
The routes.json would something like
{
“subdomain1.domain.com" : 5000,
“subdomain2.domain.com" : 5001,
“subdomain3.domain.com" : 5002
}
NodeJS application1, application2 and application3 run on port 5000, 5001 and 5002 respectively.
The script I use in my case can be found here and you might have to change a little to fit in your environment.
I also wrote about this in more details and you can find it here.
This is my simplest demo project without any middleware or proxy.
This requires only a few codes, and it's enough.
https://github.com/hitokun-s/node-express-multiapp-demo
With this structure, you can easily set up and maintain each app independently.
I hope this would be a help for you.
Literally, when you get the request and response object, you can get the domain through "request.headers.host"... (not the IP address, actually the domain).
Based on #Michaaatje and #papiro, a very easy way:
Say you have some typical pages such as...
var app = express()
app.use(sess)
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))
app.get('/', ensureLoggedIn("/loginpage"), function(req, res, next) {
...
})
app.get('/sales', ensureLoggedIn("/loginpage"), function(req, res, next) {
...
})
app.get('/about', ensureLoggedIn("/loginpage"), function(req, res, next) {
...
})
app.post('/order', ensureLoggedIn("/loginpage"), urlencodedParser, (req, res) => {
...
})
.. and so on.
Say the main domain is "abc.test.com"
But you have an "alternate" domain (perhaps for customers) which is "customers.test.com".
Simply add this ...
var app = express()
app.use(sess)
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))
app.use((req, res, next) => {
req.isCustomer = false
if (req.headers.host == "customers.test.com") {
req.isCustomer = true
}
next();
})
and then it is this easy ...
app.get('/', ensureLoggedIn("/loginpage"), function(req, res, next) {
if (req.isCustomer) {
.. special page or whatever ..
return
}
...
})
app.get('/sales', ensureLoggedIn("/loginpage"), function(req, res, next) {
if (req.isCustomer) {
res.redirect('/') .. for example
return
}
...
})
app.get('/about', ensureLoggedIn("/loginpage"), function(req, res, next) {
if (req.isCustomer) { ... }
...
})
app.post('/order', ensureLoggedIn("/loginpage"), urlencodedParser, (req, res) => {
if (req.isCustomer) { ... }
...
})
Thanks to #Michaaatje and #papiro .
This guide from digital ocean is an excellent way. It uses the pm2 module which daemonizes your app(runs them as a service). No need for additional modules like Forever, because it will restart your app automatically if it crashes. It has many features that help you monitor the various applications running on your server. It's pretty awesome!
This can be done super easily by redbird. Suppose you have two domain names example.com and example1.com and two website serving on port 8000 and 8001.
You can set a reverse proxy to the two websites by the following scripts.
var proxy = require('redbird')({port: 80});
proxy.register("example.com", "http://localhost:8000");
proxy.register("example1.com", "http://localhost:8001");
You can use process management tool such as pm2 to run the scripts so that it will continue serving after you close your shell.

Resources