Serving pages depending on domain name

Hello,
Is it possible that several domain names redirect to the same IP (and thus Meteor app), and that this app can detect the domain name from which it is served and redirect to a specific route that would appear as the root route ?
Mickael

2 Likes

Interesting. I think we can run multiple meteor instances handle domains. But it’s limited.

Certainly the first part, we use a combination of a domain prefix and url suffix to uniquely identify a specific client, (e.g., [sport].domain.com/[teamName]) - however we don’t change routes based on this, all teams share the same routes, its just the data context that changes.

For the second part, I think you’d have to modify your router (e.g., flow-router) to allow route groups defined by domain rather than URL

run multiple meteor instances

Well, yes, that is easy, and I am already doing that. The domain is handled by the proxy (nginx) and each instances has its own ROOT_URL.

But running multiple Meteor app instances is exactly what I want to avoid.

1 Like

you’d have to modify your router to allow route groups defined by domain rather than URL

I think this is it ! I will search a version of Iron Router (never went the Flow way) that is doing that. Thank you !

But then I think I will have another problem with mup deployments and the forced ROOT_URL of the app. I don’t want the domain name to be changed due to the fact that the ROOT_URL is different.

Root URL doesn’t really matter, except if you use Meteor.absoluteUrl and its easy enough to modify that to check for the actual URL in use on the client. On the server (if your server sends back any absolute URL’s to use, its more difficult. In our case, the server tracks which team a user is logged in as (with its sport prefix) so we know what to send back.

2 Likes

I just created a small meteor project (meteor run --port 4000) and pointed nginx with several server names to it (you need to change to your FQDN)

server {
    server_name domain-a.example.com domain-b.example.com domain-c.example.com;
    root /Users/user/Meteor/domains/public;
    location / {
        proxy_pass http://127.0.0.1:4000;
        proxy_http_version 1.1;
        proxy_read_timeout 36000s;
        proxy_send_timeout 36000s;
        proxy_set_header Upgrade $http_upgrade; # allow websockets
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP
        proxy_set_header Host $host;
        #
        #proxy_set_header Connection "";
        #proxy_redirect off;
        #chunked_transfer_encoding off;
        #
        # this setting allows the browser to cache the application in a way compatible with Meteor
        # on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
        # the root path (/) MUST NOT be cached
        if ($uri != '/') {
            expires 30d;
        }
    }
}

and it works pretty much as expected.

I get the domain with document.location.host.split('.').shift() on the client.

I created a little method that updates the domain per connection so the server knows which domain a connection is on.

  Meteor.methods({
    domain(domain){
      var c = DomainConnections.findOne(this.connection.id);
      if (c) {
        DomainConnections.update(c._id, { $set: { domain: domain } })
      } else {
        c = { _id: DomainConnections.insert({ _id: this.connection.id, domain: domain }) }
      }
      return c._id;
    }
  });
  Meteor.onConnection(function (connection) {
    const connectionId = connection.id;
    connection.onClose(function () {
      let c = DomainConnections.remove(connectionId);
      console.log(`onClose ${connectionId} removed ${c}`);
    });
  });

  Meteor.startup(function () {
    //
    // clear DomainConnections when server starts
    //
    DomainConnections.remove({});
  });

  Meteor.publish('domain', function () {
    var c = DomainConnections.findOne( this.connection.id );
    if(!c) {
      console.log(`inserted ${DomainConnections.insert({ _id: this.connection.id, domain:'unknown'})}`);
    }
    return DomainConnections.find({ _id: this.connection.id });
  });
3 Likes

I do in my application using nginx redirect. The first redirect lets application know which subdomain is accessing, from there everything works on the main domain. Not perfect but works for me.

Beautiful. It’s very useful.

Thank you for all your replies !

What I learned:

  • I thought that setting ROOT_URL was forcing the site to use this url, but it is not.
  • I use Iron.Location.get().hostname to test for domain name (host)
  • using mup proxy settings ease the proxy setup (duh!)
  • running several sites with only one instance while taking care of dynamic content for each site is not that hard
  • I love Meteor

I would have loved to set up the proxy dynamically to handle new domain names easy (without redeploying) and thus create sites on the fly but that will be saved for later…

6 Likes