Virtual hosting with standalone node.js server - node.js

Is there a way to currently do virtual hosting with node.js server (i.e. host multiple domains under one IP) ?

Sure, you can use bouncy or node-http-proxy specifically for that.
There's also an Express solution. Check out this example.

Web browsers send a the header property 'host' which identifies the domain host they are trying to contact. So the most basic way would be to do:
http = require('http');
server = http.createServer(function(request, response) {
switch(request.headers.host) {
case 'example.com': response.write('<h1>Welcome to example.com</h1>'); break;
case 'not.example.com': response.write('<h1>This is not example.com</h1>'); break;
default:
response.statusCode = 404;
response.write('<p>We do not serve the host: <b>' + request.headers.host + '</b>.</p>');
}
response.end();
});
server.listen(80);

I would recomend express-vhost because the others solutions are based on a proxy server, it means that each one of you vhost should open a different port.

Related

How to connect to node.js server from any ip

I want to create a private backend for an application I want to make, but I am having trouble connecting to my node server, I have the basic stuff right now,
var http = require("http");
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<html><body><h1>Hello World</h1></body></html>');
}).listen(3000);
console.log('Server running on port 300.')
But this only works for https://localhost:3000/, how do I make it so that if I have a separate computer on a separate connection, I can connect to this server?
I am not interested in just opening it to everyone but just to specific client IP's...
If the client IP's are on the same network as you, you can check out this question
If you want people from anywhere to access your application, I suggest hosting it on something like Heroku (very easy to deploy, pretty good free tier). You can then create a whitelist of IPs in your express application.
I would suggest for any port forwarding using ngrok or configuration in your router
For downloading ngrok https://ngrok.com/ go to this link
For configuration your router it will take some searching in google based on what type of router your using
You must mention that your localhost or Nat Ip and your public IP to resolve here is NOIP refrence https://www.noip.com/support/knowledgebase/general-port-forwarding-guide/
As you specified that you want the backend to be private, such that it can only be accessed by your specified node. You will have to host this node server on a cloud service or you can host it on your local machine by opening a port for the node server. Suppose you host the node server on port 1234 on your local machine ip address.
You can start the node server on localhost and your desired port, but you need to allow requests to the particular port.
Now you need to check for the origin of the request that your node server receives and validate that, so that only your private node(computer) can access the node server. You can do that by validating the hostname using express, you can get the hostname of the request in express.js using req.hostname or req.headers.host.
You would need to use express.js for this functionality and the code would be as follows
let express = require('express');
let app = express();
let allowedHost = 134.32.234.3 // the hostname which is allowed to access the backend
let port = 1234; // desired port
let host = 0.0.0.0 // desired host; 0.0.0.0 to host on your ip
app.get((req, res) => {
res.header('Content-Type', 'text/html');
if(req.hostname == allowedHost){
res.send('<html><body><h1>Hello World</h1></body></html>');
}
else{
res.send('Connection not allowed');
}
});
app.listen(host, port, ()=>{
console.log(`The server is running on http://${host}:${port}`);
}

how do i correctly proxy https requests to another https server for cordova

I have a number of different servers running on my system, all of them running a secure connection on there own port, etc. 50001,50002,50003...
all of thees can be accessed directly from https://domain1.com:50001 ...
now, not only do I want to limit the number of ports, but also change the domain so etc.
https://domain1.com:50001 <- https://srv1.domain2.com:443
https://domain1.com:50002 <- https://srv2.domain2.com:443
https://domain1.com:50003 <- https://srv3.domain2.com:443
All of thees servers run separate nodejs instances.
Now I want to build a proxy than redirect this, and I have chosen nodejs since everything else we do is in nodejs.
what i have now:
var app = require('express')();
var options = {
key : fs.readFileSync(CONFIG.sslKey).toString(),
cert : fs.readFileSync(CONFIG.sslCertificate).toString(),
ca : fs.readFileSync(CONFIG.sslCA).toString()
};
var http = require('https').Server(options,app);
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
ssl: {
key : fs.readFileSync(CONFIGsecure.sslKey).toString(),
cert : fs.readFileSync(CONFIGsecure.sslCertificate).toString(),
ca : fs.readFileSync(CONFIGsecure.sslCA).toString()
},
secure: true
});
var handleRequests = function(req, res){
proxyTo = "https://domain1.com:50001"; <= some logic chooses this based on req.headers.host
proxy.web(req, res, { target: proxyTo });
};
app.get('/*', handleRequests );
app.post('/*', handleRequests );
app.put('/*', handleRequests );
app.delete('/*', handleRequests );
http.listen(443, function(){});
okay so this actually works very well, everything is going where it should go in a browser, and in a cordova app using jquery ajax everything also works very well.
however if i use
FileTransfer().download(...)
I get error code 3 (connection error).
If I connect directly to https://domain1.com:50001 (direct) the app works, but if i connect to https://srv1.domain2.com:443 (the proxy) the app does not work.
All the certificates are valid, wildcard certificate on *.domain2.com and single certificate on domain1.com.
The end servers has domain1.com certificate installed and the proxy has *.domain2.com wildcard certificate installed.
Any idea on how to correctly setup a proxy server? The system is windows server 2012 R2 and I am open to use a real proxy if needed. However it would be nice with a solution as simple as possible.
I have tried example two form here:
http://blog.nodejitsu.com/http-proxy-intro/
however this is the same problem, and it is only GET requests.
I have also tried disabling https on the end server so thats it's only the proxy that is secure, however, same result...
Thanks...
Okay so i found the issue, for some reason req.headers.host string also contained the :port, and i was only switching on the address. now everything works perfekt.

Nodejs: websocket routing based on URL without port proxying

I am trying to do a game in html5 with serverside logic in node.js and that uses raw websockets (not Socket.IO, I need binary data). I wish to have multiple "rooms", thus multiple websocket servers, all having separate URLs. Currently, I only found a way to have each websocket server attached to a specific port, and then proxy the upgrade requests(not entirely sure how it works) to the right port based on the url.
It works on my computer. The problem is that when I try to submit it to a PaaS provider (AppFog), the code fails because they don't permit opening any ports other than the provided http port.
Here is a pretty cleared up version of my code:
//start web server (basic static express server) on 8080
// ...
//start game server and listen to port 9000
// I use the ws module for websockets
// I plan to have a couple of these "game servers"
// ...
//open the proxy server.
var httpProxy= require('http-proxy');
var webProxyServer = httpProxy.createServer(function (req, res, proxy){
// I need http requests to be redirected to the "game servers"
if(req.url.substring(0, "/room1".length) === "/room1") // if starts with "/room1"
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
else
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8080
});
}
webProxyServer.on('upgrade', function (req, socket, head) {
//redirecting logic goes here
if(req.url=="/room1/"){
webProxyServer.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 9000
})
}
});
webProxyServer.listen(8000); //the "outside port".
My question: is it somehow possible to open websocket servers without listening to any specific ports, and to manually attach sockets to them so I don't need to open any ports other than the basic http port? I know Socket.IO somehow does it. Maybe there is a way to listen to the upgrade event of a http server and pass the socket to the right websocket server?
I am pretty new to server-side stuff, so extra info here and there would be welcome.
Unfortunately, Appfog does not support websockets.
Feature Roadmap page - bottom of page: shows websockets as something coming soon (i.e. they don't support it).

Node.js+express proxy ssl

I'm trying to write a reverse proxy in node.js using express, and it works fine for http requests. The problem is that when requesting https it never responds, and the browser states that the proxy refused to connect.
Here is the working code for http requests:
var app = express(),
http=require('http');
app.configure(function(){ /* express stuff to log and use routes and the like */ });
http.createServer(app).listen(8000, function(){
console.log("Express server listening on port " + 8000);
});
app.all('*', proxy);
var request=require('request');
var proxy=function(req,resp){
var data={
url:req.url,
headers: {
'Connection': 'keep-alive'
}
}
var proxy=request(req.url);
proxy.pipe(resp);
}
Now, as for SSL, i am currently trying with:
var https=require('https'),
fs=require('fs');
https.createServer({
key: fs.readFileSync(__dirname+'/ssl/server.key', 'utf8'),
cert: fs.readFileSync(__dirname+'/ssl/server.crt', 'utf8')
},app).listen(8001, function(){
console.log("Express server listening on port " + 8001);
});
The proxy can be used from anywhere requiring 50.56.195.215:8000 for HTTP and 50.56.195.215:8001 for SSL. It has no security whasoever, so don't log in to anything important =D
I'm using a self signed SSL Certificate, and i guess it's kind of silly of me to try to do such a thing, but i don't have any ideas left :P
My suggestion is use the great existing library node-http-proxy from Nodejitsu. If you want to write your own, at least study their source code academically.
Some notes on your approach above:
You aren't handling HTTP methods other than GET (POST, PUT, DELETE, etc). These exist. You must handle them if you want your proxy to actually work. Every time you call request(req.url), request is making a GET request by default.
For HTTPS, you need to be able to handle HTTP Connects and also impersonate the destination server. You will need to have a Certificate for this.
You can try using this.
https://github.com/noeltimothy/noelsproxy
Copy the directory "magical" that contains a certificate as well as a key and then use noelsproxy. Remember to add the ca.pem to your trusted root store on your system.
If you are using windows, do this:
certutil -addstore -enterprise -f \"Root\" ./magical/ca.pem
Let me know if you have any issues. I'm willing to fix them immediately.

Implementing / forcing SSL for LocomotiveJS apps (NodeJS / Express)

With MVC frameworks like LocomotiveJS now available for NodeJS / Express, I'm just wondering how it would be possible to implement SSL on part of an app?
For example, an ecommerce app.
I'd need all /checkout controllers to force SSL.
I've read tutorials like this one but not sure on how to implement this with Locomotive, since Express is effectively "wrapped" ?
Currently SSL is not directly supported by Locomotive, but should be soon, according to this Google Groups posting in April by Jared Hanson, the creator of Locomotive.
Currently, I've always been putting Locomotive behind a proxy that
terminates SSL. But, I'll be adding a command line option for this
shortly, for direct support.
That said, if you want a completely node-based solution without using a proxy, then for the time being you'll need to edit the Express instance in Locomotive. I've tested the below and it's working well.
As of writing, npm install locomotive uses Express 2.x, though the latest at github has since been updated to use Express 3.x.
If you're using Locomotive with Express 2.x, then I think you have to edit /locomotive/lib/locomotive/index.js, around line 180, to look something like:
var sslOptions = {
cert : fs.readFileSync('/path/to/your/ssl-cert/dev.crt')
, key : fs.readFileSync('/path/to/your/ssl-key/dev.key')
};
var self = this
, server = express.createServer(sslOptions)
, entry;
Additionally, you will probably still want to listen on HTTP and redirect all traffic to HTTPS. Sticking with an all node-based solution, you could simply start another Express server at the end of /locomotive/lib/locomotive/cli/server.js that redirects all its traffic to HTTPS, e.g.
...
debug('booting app at %s in %s environment', dir, env);
locomotive.boot(dir, env, function(err, server) {
if (err) { throw err; }
server.listen(port, address, function() {
var addr = this.address();
debug('listening on %s:%d', addr.address, addr.port);
});
// add an http server and redirect all request to https
var httpServer = require('express').createServer();
httpServer.all('*', function(req, res) {
res.redirect('https://' + address + ':' + port + req.url);
});
httpServer.listen(80); // probably change based on NODE_ENV
});
}
Lastly, start the server:
$ lcm server -p 443 # again, probably use different port in development
All those frameworks are based on top of Express which based is on connect which has HTTPS support.
Anyway in a real life situation you might want to want to have a nginx/or nother proxy handling the https for you anyway.

Resources