How to do customer/client style subdomains using Node and Express
Asked Answered
D

3

14

How does one allow customers to access a SaaS using their organization name in the domain?

For example, a web app, example.com, may have 2 customers, OrgA and OrgB.

Once logged in, each customer is redirected to their site, orga.example.com / orgb.example.com.

Once the request that includes the subdomain reaches the node server, my hope is to handle the request with a single '/' route. Inside the route handler, it simply inspects the host header and treats the subdomain as a param for the organization.

Something like:

app.get "/*", app.restricted, (req, res) ->
  console.log "/* hit with #{req.url} from #{req.headers.host}"
  domains = req.headers.host.split "."
  if domains
    org = domains[0]
    console.log org
    # TODO. do something with the org name (e.g. load specific org preferences)
  res.render "app/index", { layout: "app/app" }

NB. The first item in the domains array is the organization name. I am assuming that no port appears in the host header and, for now, I am not considering how to handle non-organisation sub domain names (e.g. www, blog, etc.).

The question I have is more about how node/express can be configured to handle requests with varying host headers. This is generally solved in Apache using a wildcard alias or in IIS using a host header.

An Apache/Rails example is @ http://37signals.com/svn/posts/1512-how-to-do-basecamp-style-subdomains-in-rails

How can the same be achieved in node?

Dale answered 14/1, 2012 at 4:20 Comment(2)
You could write a middleware that looks at the host header, gets whatever data it needs for that specific host and adds to the req object for use in the routes/middleware.Homs
I think that bit is what i've got already (albeit not yet moved to middleware). I'm blocked/unclear on how to set up a server to catch *.example.com. Am thinking a proxy may be required (github.com/nodejitsu/node-http-proxy) but I need to learn more before I attempt to understand it. I also need the solution to let me develop locally (on OSX).Dale
R
7

if you dont want to use express.vhost, you can use http-proxy to achieve a more organized routing/port system

var express = require('express')
var app = express()
var fs = require('fs')

/*
Because of the way nodejitsu deals with ports, you have to put 
your proxy first, otherwise the first created webserver with an 
accessible port will be picked as the default.

As long as the port numbers here correspond with the listening 
servers below, you should be good to go. 
*/

var proxyopts = {
  router: {
    // dev
    'one.localhost': '127.0.0.1:3000',
    'two.localhost': '127.0.0.1:5000',
    // production
    'one.domain.in': '127.0.0.1:3000',
    'two.domain.in': '127.0.0.1:4000',

  }
}

var proxy = require('http-proxy')
  .createServer(proxyopts) // out port
  // port 4000 becomes the only 'entry point' for the other apps on different ports 
  .listen(4000); // in port


var one = express()
  .get('/', function(req, res) {
   var hostport = req.headers.host
   res.end(hostport)
 })
 .listen(3000)


var two = express()
  .get('/', function(req, res) {
    res.end('I AM APP FIVE THOUSAND')
  })
  .listen(5000)
Reword answered 15/12, 2012 at 23:28 Comment(0)
D
2

I think that any request that arrives at the IP-address and port of your node server should get handled by your node server. That's why you make vhosts in apache, to differentiate between the requests apache receives by for example subdomain.

Take a look at the source code for express-subdomains if you want to see how it handles subdomains (the source is only 41 lines).

Dialytic answered 16/1, 2012 at 17:10 Comment(0)
M
2

I had a similar situation, although I had the main site example.com where the user could login and manage their site, then OrgA.example.com was a public facing site that would be updated based on the logged in user's actions at example.com.

I ended up creating two separate apps and setting up virtual hosts within connect to point 'example.com' to one application, and '*' to another. Here's an example on how to do it.

Misdirect answered 16/1, 2012 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.