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
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 :-)
Can a single server be associated with multiple domains? Yes. This would be done by pointing those domains at your web server via DNS.
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.
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.
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( ? ) ]
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