I look for a reverse proxy for my NodeJS website. I thought of Varnish or nginx or something else.
What would you suggest me and why (do not necessarily focus on Varnish vs nginx)?
nginx would probably be the best stand-alone solution, however, when I'm working with Node.js, I prefer to keep everything in Node.js so I don't have to worry about the (relatively simple) configuration. I personally use node-reverse-proxy, which allows me to just specify some simple routes in a simple application, and then route it back to the individual applications.
This is the node-reverse-proxy sample code:
var node_reverse_proxy = require('node-reverse-proxy');
var ip = '127.0.0.1';
var reverse_proxy = new node_reverse_proxy({
'first_host.com' : ip + ':8082',
'my.second_host.com' : ip + ':8081',
'my.second_host.com/page/' : ip + ':8080',
'' : ip + ':8080' // catch all other routes
});
reverse_proxy.start(80);
You might find that nginx better suits your needs, but personally, for a simple reverse proxy setup, I do prefer node-reverse-proxy.
Related
I'm trying to run 2 instances of NodeJS on the same port and server from diffrent server.js files (diffrent dir, config etc). My server provider gave me an information that vhost is running for a diffrent domain, and there is the question. How to handle it in NodeJS Express app ? I've tried to use vhost from https://github.com/expressjs/vhost like that :
const app = express();
const vhost = require('vhost');
app.use(vhost('example1.org', app));
// Start up the Node server
app.listen(4100, () => {
console.log(`Node server listening on 4100`);
});
And for second application like that:
const app = express();
const vhost = require('vhost');
app.use(vhost('example2.org', app));
// Start up the Node server
app.listen(4100, () => {
console.log(`Node server listening on 4100`);
});
But when I'm trying to run second instance I'm getting EADDRINUSE ::: 4100, so vhost doesn't work here.
Do you know how to fix it ?
You can only have one process listen to one port, not just in Node.js, but generally (with exceptions that don't apply here).
You can achieve what you need to one of two ways:
Combine the node apps
You could make the apps into one application, listen once and then forward requests for each host to separate bits of code - if you wanted to achieve code separation still, the separate bits of code could be NPM modules that are actually written and maintained in isolation.
Use webserver to proxy the requests
You could run the 2 node processes on some free port, say 5000 and 5001, and use a webserver to forward requests to it automatically based on host. I'd recommend Nginx for this, as its proxying capabilities are both relatively easy to set up, and powerful. It's also fairly good at not using too many system resources. Apache and others can also be used for this, but my personal preference would be Nginx.
Conclusion
My recommendation would be that you install a webserver and forward requests on the exposed port to the separately running node processes. I'd actually recommend that you run node behind a proxy as default for a project, and only expose it directly in excpetional circumstances. You get a lot of configuration options, security, and scalability benefits if your app already involves a well hardened server setup.
On the client I can use window.location.hostname to get the hostname. How can I get the same on the server?
I need this to work behind an Apache proxy, unfortunately Meteor.absoluteUrl() gives me localhost:3000. I also want it to work for different domains, I want one Meteor app that gives different results for different domains.
This question is somewhat related: Get hostname of current request in node.js Express
Meteor.absoluteUrl() given that your ROOT_URL env variable is set correctly.
See the following docs: http://docs.meteor.com/#meteor_absoluteurl.
Meteor doesn't know the outside-facing address of the proxy that it's sitting behind, and the (virtual) domain that this proxy was accessed by would have to be forwarded to the Meteor app for it to do what you are asking for. I don't think this is currently supported.
According to this you can now get the Host header inside Meteor.publish() and Meteor.methods() calls by accessing:
this.connection.httpHeaders.host
Elsewhere in the application, it's probably difficult to determine the Host header that is being used to connect.
If you want the hostname of the server, as configured in /etc/hostname for example:
With meteorite:
$ mrt add npm
In your server code:
os = Npm.require('os')
hostname = os.hostname()
This has no connection to the Host header provided in the incoming request.
updated answer with some of chmac's words from the comment below
In any server-side meteor file you can add:
if (Meteor.isServer) {
Meteor.onConnection(function(result){
var hostname = result.httpHeaders.referer; //This returns http://foo.example.com
});
}
You can fetch host as EnvironmentVariable from DDP object in method and publication. Meteor accounts-base package fetch userId via this way.
const currentDomain = function() {
const currentInvocation = DDP._CurrentMethodInvocation.get() || DDP._CurrentPublicationInvocation.get();
return currentInvocation.connection.httpHeaders.host;
}
I'm currently running two StrongLoop LoopBack apps (Nodejs apps) on a single server with different ports. Both apps were created using slc lb project and slc lb model from the command line.
Is it possible to run these apps on a single ports with different path and/or subdomain? If it is, how do I do that on a Linux machine?
Example:
http://api.server.com:3000/app1/ for first app.
http://api.server.com:3000/app2/ for second app.
thanks.
Since LoopBack applications are regular Express applications, you can mount them on a path of the master app.
var app1 = require('path/to/app1');
var app2 = require('path/to/app2');
var root = loopback(); // or express();
root.use('/app1', app1);
root.use('/app2', app2);
root.listen(3000);
The obvious drawback is high runtime coupling between app1 and app2 - whenever you are upgrading either of them, you have to restart the whole server (i.e. both of them). Also a fatal failure in one app brings down the whole server.
The solution presented by #fiskeben is more robust, since each app is isolated.
On the other hand, my solution is probably easier to manage (you have only one Node process instead of nginx + per-app Node processes) and also allows you to configure middleware shared by both apps.
var root = loopback();
root.use(express.logger());
// etc.
root.use('/app1', app1);
root.use('/app2', app2);
root.listen(3000);
You would need some sort of proxy in front of your server, for example nginx. nginx will listen to a port (say, 80) and redirect incoming requests to other servers on the machine based on some rules you define (hostname, path, headers, etc).
I'm no expert on nginx but I would configure it something like this:
server {
listen: 80;
server_name api.server.com;
location /app1 {
proxy_pass http://localhost:3000
}
location /app2 {
proxy_pass http://localhost:3001
}
}
nginx also supports passing query strings, paths and everything else, but I'll leave it up to you to put the pieces together :)
Look at the proxy server documentation for nginx.
I'm planning to do three sites using node.js. I have got some common templates among the sites. Should I run all three sites on single node.js instance?
I'm aware of 'vhost' middleware that allows you to run multiple domains on single http server. Is there any better option to do this?
I've also got some static html templates and not sure how to deal with these in node.js?
Finally I would like to know hosting options for this kind of setup?
I myself just had to do this exact same thing. What you want to do is use some sort of reverse proxy.
The one I use is here: https://github.com/nodejitsu/node-http-proxy
Simply install the proxy package: npm install http-proxy
What I do is have the proxy running on the server on port 80. I set the DNS up on each domain to point to this server.
Each application is running on the same server (im using screens).
For example:
MySiteApplication1 - 3001
MySiteApplication2 - 3002
MySiteApplication3 - 3003
Then your proxy server file would look like this
var httpProxy = require('http-proxy');
var server = httpProxy.createServer({
router: {
'mysite1.com': 'localhost:3001',
'mysite2.com': 'localhost:3002',
'mysite3.com': 'localhost:3003'
}
});
server.listen 80
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.