I want to implement SaaS App & I have read the relevant posts also.
Now, I will share what should be the approach and my concerns regarding the same. Please guide me in the right direction so that I can possibly contribute more to the Meteor.
- You should have a wildcard subdomain
- Configure NGINX to accept traffic from whatever be the subdomain. You can check from the server whether that subdomain is already exists or not. If not then you can display the 404 page.
- For Publications & Subscriptions you could pass the domain name as an argument or use this approach for getting the relevant data.
- For Favicon we can use this approach. Multitenancy and Meteor
Now, here are some concerns
- How do we connect each subdomain to a different mongoldb instance.
- Is there any way we can achieve the same sort of behavior without using wildcard subdomains.
- How can we pass environmental variables to each subdomain. If we can pass environmental variables then how do we apply them at run time.
Please share your thoughts on the same. It might be useful for others as well. Looking forward to this discussion
@filipenevola Can this be possible with Meteor?
It sounds like your approach is good.
For your concerns it mostly depends on whether you’re going to have a single meteor instance per subdomain. If you do, then (1) and (3) are trivial, you just pass in different meteor settings and environment variables. If you don’t, things become more complicated - you have to attach what you would consider “environment variables” to specific customers in a DB (e.g., feature flags, credentials, etc). That mostly resolves (3).
For (1) - it’s more complicated if you use a single instance. There is nothing stopping you declaring as many DB connections as you like (though there is probably a performance cost to this, particularly if you’re using the regular oplog package), you can either prefix the collection names with the domain (in it’s own DB) or do the prefixing as part of your pub/sub (e.g., instead of
this.added("users", ...) you’d call
this.added(domain+"_users", ...)), or - you can skip this entirely if you know a client (and therefore a connection) will only need to reason about a single domains data at once.
For (2) - if you don’t want to run specific servers per customer, you could use a URL suffix
https://mydomain/customersubdomain. If your question is specifically about not using wildcards (but still using subdomains) then yes, you’d need whatever your onboarding procedure is to add a DNS entry - but you’d have to wait for it to propagate (can be as long as 24 hours) before customers could reliably connect to it.
Will probably need more details about what you think your infrastructure will be before answering in more detail.
Check Reaction Commerce. There you have multiple services. You would want to look at Reaction (API) and Reaction Admin. You get some code for starting Meteor from Node, ensure the env vars are set and perhaps you get an ideea on how to pull the env vars from somewhere (Mongo) and attach to the Meteor command before you start it.
Will Check it & update, Thanks @paulishca
Following would be the infrastructure
Also, can you provide some sort of reference or example for passing environmental variables while creating the second instance?
It depends entirely on your deployment mechanism - if you go with mup I think you’d need a separate config file for each deployment and you specify the environment variables there (in their entirety) it only sucks if you have a bunch of shared env vars that you end up having to duplicate.
I’ve worked with custom deployments scripts specifically designed for this, where you have many customers on (sometimes) different versions of an application and need to maintain the intersection of shared and customer specific environment variables (sometimes across multiple applications per customer).
If you’re going to have lots of these deployments (and an increasing number of them) it may be worth adding an abstraction layer, something like kubernetes or rancher.
I had also thought of custom deployment scripts running docker commands & NGINX on different ports to achieve the same. I was thinking of made changes in Nginx configuration every time when someone requested a sub-domain & then look for a port that is open and then configuring the Environment variables to run the Application on the sub-domain.
Kubernetes would need separate instance for every deployment, is there any way we can use Kubernetes for doing the subdomain part?
If you use docker, you shouldn’t need to modify NGINX you can capture the deployment name from the subdomain and route based on that.
Regarding kubernetes, it shouldn’t require 1 deployment per host. As I understand it (at least AWS’ implementation of it) you provision a fleet of hosts, and kubernetes balances the load of all your deployments between those hosts. It will also have some routing capabilities, but that’s not really specific to meteor, you’ll need to read through the documentation of kubernetes to set that up
Can you share the docker configuration that allows us to create the subdomain & that does the routing part also?
Where did you read that you should have a subdomain per tenant? I’ve been involved on a few discussions here where that is one option, but does make things difficult.
Rather than using custom subdomains and different databases, another approach is to have one subdomain and to partition your database at a low level using https://github.com/Meteor-Community-Packages/meteor-partitioner.
Then all you need to do is assign a new
groupId to the first user in each tenancy, then any documents they create in partitioned collections, or any new users they invite will automatically be assigned to their tenancy.
Thanks for this. But the reason for not using is this package is this that its not maintained and very old. You can check the last commit on this was few years back
The last commit was sometime ago, yes, but it works perfectly so doesn’t really need any maintenance. It’s now ‘maintained’ by Meteor-Community-Packages which means that it should always be fairly good quality.
At it’s heart it’s a very simple package, so easy to fork and maintain yourself if you really need to. I’m using my own fork which is a bit more efficient for my use-case. Feel free to try that if you want.
Having a single subdomain and single database does make things much easier, in my opinion.
We use this approach and don’t use any package for it. We have a base schema with a tenantId (and some other things) that all core collection schemas inherit from. You do need to be careful with your publications and methods to ensure no tenant can alter or see data from another (which is what this package does for you) but like @wildhart says, it’s far simpler than separate infrastructure for each. I know Qualia does the separate infrastructure solution, IIRC they use terraform. If you’re familiar with that and have similar requirements to them (I think they had to separate client’s data) then maybe it makes sense.
Additional benefits of all the tenants in one database:
- My superAdmin dashboard can collate data from all tenants to tell me which tenants are active or not, how many users they have, how much money I’m making , etc.
- As a superAdmin I can ‘become’ any tenant and view their data to help with customer support - all I have to do is change my own
groupId and thanks to reactive publications my subscriptions automatically update.
- Only one db to backup.
I do like having the low-level package to manage the separation - means I can write publications and methods without having to worry too much about leakage - the cost of data leakage between tenancies is too high. I suppose that’s the certainty that separate database give you.