I have a root server running with several node.js projects on it. They are supposed to run separately in their own processes and directories. Consider this file structure:
/home
+-- /node
+-- /someProject | www.some-project.com
| +-- index.js
| +-- anotherFile.img
| +-- ...
+-- /anotherProject | www.another-project.com
| +-- /stuff
| +-- index.js
| +-- ...
+-- /myWebsite | www.my-website.com
| +-- /static
| +-- index.js
| +-- ...
+-- ... | ...
Each index.js should be started as an individual process with its cwd
set to its parent-folder (someProject
, anotherProject
, etc.).
Think ov vHosts. Each project starts a webserver which listens on its own domain. And there's the problem. Only one script can start since, they all try to bind to port 80. I digged to into the node.js API and looked for a possible solution: child_process.fork()
.
Sadly this doesn't work very well. When I try to send a server instance to the master process (to emit a request later on) or an object consiting of request
and response
from the master to the salve I get errors. This is because node.js internally tries to convert these advanced objects to a JSON string and then reconverts it to its original form. This makes all the objects loose their reference and functionality.
Seccond approach child.js
var http = require("http");
var server = http.createServer(function(req, res) {
// stuff...
});
server.listen(80);
process.send(server); // Nope
First approach master.js
var http = require("http"),
cp = require("child_process");
var child = cp.fork("/home/node/someProject/index.js", [], { env: "/home/node/someProject" });
var router = http.createServer(function(req, res) {
// domaincheck, etc...
child.send({ request: req, response: res }); // Nope
});
router.listen(80);
So this is a dead end. But, hey! Node.js offers some kind of handles, which are sendable. Here's an example from the documentation:
master.js
var server = require('net').createServer();
var child = require('child_process').fork(__dirname + '/child.js');
// Open up the server object and send the handle.
server.listen(1337, function() {
child.send({ server: true }, server._handle);
});
child.js
process.on('message', function(m, serverHandle) {
if (serverHandle) {
var server = require('net').createServer();
server.listen(serverHandle);
}
});
Here the child directly listens to the master's server. So there is no domaincheck inbetween. So here's a dead end to.
I also thought about Cluster
, but this uses the same technology as the handle and therefore has the same limitations.
So... are there any good ideas?
What I currently do is rather hack-ish. I've made a package called distroy. It binds to port 80 and internally proxies all requests to Unix domain socket paths like /tmp/distroy/http/www.example.com
, on which the seperate apps listen. This also (kinda) works for HTTPS (see my question on SNI).
The remaining problem is, that the original IP address is lost, as it's now always 127.0.0.1. I think I can circumvent this by monkeypatching the net.Server
so that I can transmit the IP address before opening the connection.
If you are interested in a node.js solution check out bouncy, a websocket and https-capable http router proxy/load balancer in node.js.
Define your routes.json like
{
"beep.example.com" : 8000,
"boop.example.com" : 8001
}
and then run bouncy using
bouncy routes.json 80
Personally, I'd just have them all listen on dedicated ports or preferably sockets and then stick everything behind either a dedicated router script or nginx. It's the simplest approach IMO.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With