Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpressJS Server - How to handle multiple domains

I'm fooling around a little with Express and I'm wondering, what the "most correct" way is to handle multiple domains which are linked to the same server.

Lets assume we have

  • foo.com
  • bar.net
  • baz.com

which all point to 111.222.333.444. That machine is running NodeJS with Express. My current solution looks like this:

var express = require( 'express' ),     app     = module.exports = express.createServer(), // ... more lines ... app.get( '/', routes.index.bind( app ) ); 

Thus far this is pretty straightforward. The only exception so far is in my app.configure call, where I didn't make a call to .use( express.static() ). Thats because the .routes.index() method looks like so right now:

var fs    = require( 'fs' ), // ... more lines ...  exports.index = function( req, res ) {     var host = /(\w+\.)?(.*)\.\w+/.exec( req.header( 'host' ) ),         app  = this;      switch( host[ 2 ] ) {         case 'foo':             app.use( express.static( '/var/www/foo' ) );             fs.readFile( '/var/www/foo/index.html', 'utf8', fileReadFoo );             break;         case 'bar':             app.use( express.static( '/var/www/bar' ) );             fs.readFile( '/var/www/bar/index.html', 'utf8', fileReadBar );             break;         case 'baz':             // ... lines ...             res.render( 'index', { title: 'Baz Title example' } );             break;         default:             res.send('Sorry, I do not know how to handle that domain.');     }      function fileReadFoo( err, text ) {         res.send( text );     }      function fileReadBar( err, text ) {         res.send( text );     } }; 

What happens here is, that I analyse the req.header for the host entry and parse the domain name. Based on that, I call the .static() method so Express can serve the right static resources etc., furthermore, I just simply read and send the contents of the index.html files. I tried to use Jade aswell for serving plain HTML files, but the include directive in Jade only accepts relative pathes.

However, this indeed works, but I'm pretty unsure if that is a good practice.

Any advice / help welcome.


Update

I think I need to make this more clear. I'm not a beginner by any means. I'm very aware how ES works and other servers like NGINX. I'm looking for qualified answers on what the right thing with NodeJS/Express is. If it doesn't make any sense to use Node/Express for that, please elaborate. If there is a better way to do this with Node/Express, please explain.

Thanks :-)

like image 368
jAndy Avatar asked Aug 14 '12 21:08

jAndy


People also ask

Can a server have multiple domains?

Can a single server be associated with multiple domains? Yes. This would be done by pointing those domains at your web server via DNS.

How many requests per second can an Express server handle?

There's a benchmark made by Fastify creators, it shows that express. js can handle ~15K requests per second, and the vanilla HTTP module can handle 70K rps.

Is Expressjs scalable?

The Express framework is equipped with similar scalability and features as the Nginx and Apache servers. Moreover, being lightweight, leveraging it to build large-scale applications is achievable.


1 Answers

Vadim was almost onto the right idea. You can configure how to respond to each domain with the vhost middleware:

// `baz.com` var app = express.createServer(); app.get( '/', routes.index );  // ...  express.createServer()     .use( express.vhost( 'foo.com', express.static( '/var/www/foo' ) ) )     .use( express.vhost( 'bar.net', express.static( '/var/www/bar' ) ) )     .use( express.vhost( 'baz.com', app ) )     .use( function( req, res ) {         res.send('Sorry, I do not know how to handle that domain.');     })     .listen( ... ); 

routes.index can then be simplified to handle only baz.com requests:

exports.index = function( req, res ) {     // ... lines ...     res.render( 'index', { title: 'Baz Title example' } ); }; 

Edit

As for comparisons:

The switch would effectively be done first and would determine how to handle all requests based on the host -- similar to:

express.createServer().use(function( req, res, next ) {     switch( req.host ) {         case 'foo.com': express.static( '/var/www/foo' )( req, res, next ); break;         case 'bar.net': express.static( '/var/www/bar' )( req, res, next ); break;         case 'baz.com': app.handle( req, res, next ); break;         default: res.send( ... );     } }).listen( ... ); 

It allows you to set the stack on start so any middleware is available immediately:

server.stack = [     express.vhost( 'foo.com', ... ),     express.vhost( 'bar.net', ... ),     express.vhost( 'baz.com', ... ),     [Function] ]; 

These also reflect the 2 possible sources of issues you might have:

Same stack without filters

Each Application only has 1 middleware stack, which all of the middleware you're using is being added directly to with app.use(...). Despite adding some under conditions, you're still getting:

app.stack = [     // ...,     app.router,     express.static( '/var/www/foo' ),     express.static( '/var/www/bar' ) ]; 

And the condition won't change how the static middlewares respond -- which is by req.path, not req.host -- only when they're in the stack to start responding.

State of the stack

And, if the static middlewares aren't added until after another request has been made, then I take it they aren't available immediately:

// GET http://foo.com/file 404 app.stack = [ app.router ]  // GET http://foo.com/ 200 app.stack = [ app.router, express.static( '/var/www/foo' ) ]  // GET http://foo.com/file 200 app.stack = [ app.router, express.static( '/var/www/foo' ) ] 

This may also mean the same static middleware could be added to the stack multiple times:

// 3x GET http://foo.com/ app.stack = [     app.router,     express.static( '/var/www/foo' ),     express.static( '/var/www/foo' ),     express.static( '/var/www/foo' ) ] 

And having their addition depend on other requests also suggests a possible race conditions:

// was `foo.com` or `bar.net` first? app.stack = [     app.router,     express.static( ? ),     express.static( ? ) ] 
like image 189
14 revs Avatar answered Sep 25 '22 03:09

14 revs