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

node.js

node.js Problem Overview


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.

node.js Solutions


Solution 1 - node.js

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.

Solution 2 - node.js

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:

Solution 3 - node.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.

Solution 4 - node.js

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);

Solution 5 - node.js

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.

Solution 6 - node.js

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.

Solution 7 - node.js

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?

Solution 8 - node.js

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.

Solution 9 - node.js

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.

Solution 10 - node.js

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).

Solution 11 - node.js

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 .

Solution 12 - node.js

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!

Solution 13 - node.js

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGuyView Question on Stackoverflow
Solution 1 - node.jsjosh3736View Answer on Stackoverflow
Solution 2 - node.jsAdam HalaszView Answer on Stackoverflow
Solution 3 - node.jsKrasimirView Answer on Stackoverflow
Solution 4 - node.jsfuelusumarView Answer on Stackoverflow
Solution 5 - node.jsScott PuleoView Answer on Stackoverflow
Solution 6 - node.jsuser568109View Answer on Stackoverflow
Solution 7 - node.jspapiroView Answer on Stackoverflow
Solution 8 - node.jsKevin Le - KhnleView Answer on Stackoverflow
Solution 9 - node.jstoshiView Answer on Stackoverflow
Solution 10 - node.jsMichaaatjeView Answer on Stackoverflow
Solution 11 - node.jsFattieView Answer on Stackoverflow
Solution 12 - node.jsIsaac PakView Answer on Stackoverflow
Solution 13 - node.jsZijian ZhangView Answer on Stackoverflow