Multi tenant implementation

How do we implement multi tenancy. I’m sure someone’s implemented this before, is it possible ?
I want to set it up so that any new user has their own api and own dasboard.

Ok - So I wanted to reask this.
Is it possible to add a must have tenantID propoerty to teh base / root parse objects ( classes ) ?
Now when we store it, it’s all stored with a tenant id and search etc must add that as well. Is that possible? Can we create an adaptor that does that ?

I’d create separate Parse Server instances and database instances for each of the tenants.

Isn’t there a way to add tenantId to each record / class ?

There is no such feature built-in.

Is it possible to add an extension / decorator at a global level ?

Parse Server is essentially an Express.js middleware. You can build another Express.js middleware that run before Parse.

so I’d have to have a gateway that managed the tenency and each tenant is passed on from there ? what about security / authorisation - where will that be handled ?

This conversation is too abstract to give an opinion on that. Maybe you should give it a try and check the specific problems that you will have to fix.

Is this what you’re suggesting ? put an express engine before and connect to the tenancy db??

1 Like

What you seem to be trying to do has a multitude of approaches, each with different pros and cons. Which approach is right for you depends on the characteristics of the service you intend to build, for example considering:

  • scale
  • security context
  • efficiency
  • robustness / reliability

These are business decisions, so from a technical point of view there won’t be a right/wrong answer.

understood -
All I’m trying to do is have an install that has mutitenancy - but the information out there is very varied.
What mutiple approaches are you refering to ?

There are multiple architectural and technological approaches to achieve a similar outcome. Specifically, you would be looking for a solutions architect to design an infrastructure and technology solution that aligns with your product requirements - which you would have to formulate of course.

The simplest solution / proof concept for multi-tenancy would be 2 separate databases, 2 separate parse server instances and bind them to 2 different endpoints, for example:

  • External customer1.example.com routes to internal http://server1/parse
  • External customer2.example.com routes to internal http://server2/parse

Yes that’s what I’ve got in my diagram above. The binding is done dynamically via an xpress server . My concern with this (and your) suggestion is resources.

1- I’d need mutiple machines (or a really big one) that can run mongo efficiently for complex tasks.
2- How would I create new instances when a new tenant sights up?

Thanks

This depends on how you want to set this up. If you use a cloud provider, they have their own APIs to manage the infrastructure. The example above that I gave is also not an efficient solution, but merely a proof of concept. There is a lot of know-how from different disciplines that goes into creating - and maintaining - a commercially viable solution.

That is not to discourage you. You could start with a simple proof of concept and go from there as you identify bottlenecks along the way. Keep in mind that the know-how required goes beyond this forum and is in many aspects not related to Parse Server specifically.

Hi folks,

I’ve got a somewhat similar question. I’d like have a parse instance per customer. A friend suggested that I simply create a totally new instance of parse (i.e. a totally separate and full set of all files) per customer. I guess this is a workable option, but I was wondering if I can use a single copy of my parse code and simply create separate parse application instances in the parse server setup?

I understand from what I’ve read in a few different places online that cloud code is not designed to be “isolated” in a multi-tenancy type situation, but I’m happy quite happy to share as single set of cloud functions between customers as they will be locked down and only editable by ourselves, not the customers. In fact, I would prefer this :slight_smile: (Unless of course this implies that cloud coud would only be able to access a single app’s data?)

TL;DR:
My questions:

  • Will this approach work? Is it just a case of figuring it out? or
  • Can parse servers share a single code base but perhaps need to run in separate processes? or
  • Do I need to treat each parse server as totally separate? i.e. totally separate copy of files and separate parse setup?

Thanks in advance :smiley:


This is what I currently have setup:

const customers = [
  {
      appName: 'Customer One',
      customerPath: 'customer-one',
      databaseURI: 'mongodb://localhost:27017/customerOne',
      serverURL: `${config.parse.serverUrl}/customer-one`,
      publicServerURL: `${config.parse.serverUrl}/customer-one`,
      masterKey: 'masterCustomerOne',
      appId: 'Customer One App',
      cloud: `${__dirname}/${config.parse.cloudFunctions}`
  },
  {
      appName: 'Customer Two',
      customerPath: 'customer-two',
      databaseURI: 'mongodb://localhost:27017/customerTwo',
      serverURL: `${config.parse.serverUrl}/customer-two`,
      publicServerURL: `${config.parse.serverUrl}/customer-two`,
      masterKey: 'masterCustomerTwo',
      appId: 'Customer Two App',
      cloud: `${__dirname}/${config.parse.cloudFunctions}`
  }
]

const customerInstances = []
for (const customer of customers) {
  const instance = new ParseServer(customer)
  customerInstances.push(instance)
}

const apps = customers.map((customer) => {
    return {
        serverURL: serverURL: customer.serverURL,
        masterKey: customer.masterKey,
        appId: customer.appId,
        appName: customer.appId
    }
})

const parseDashboard = new ParseDashboard(
    {
        apps,
        users: [
            {
                user: config.parse.adminUser,
                pass: config.parse.adminPassword,
            },
        ],
    },
    {
        allowInsecureHTTP: !process.env.NODE_ENV || process.env.NODE_ENV !== "production"
    },
);

I start this up locally and…

  • In the terminal, I get a warning that the 2nd server is not running
  • In the dashboard, I can see both apps registered, but only the the first is usable (expected, seeing as the terminal output already mentioned that the 2nd is not running)
  • I can interact with the cloud functions via the rest api and I can add records via the js console.

I’ve already burnt a few hours in reading online to figure out if this approach will work, but I can’t seem to find anything.

How do you plan to deploy the servers themselves? Docker? K8S? Manually?

I can imagine a situation where you build a custom parse-server based docker image that basically just accepts a “MASTER_KEY” and “CUSTOMER_NAME” from the environment and hard codes everything else including the cloud code. Then you use the docker image to spin one or more instances for each customer as they are coming in.

Then if you need to modify the cloud code, update it, release a new version of your docker image and start upgrading the customers to the new version.

I can imagine having this working in K8S pretty easily and nicely.

thoughts?
Martin

1 Like

Thanks Martin!

I was going to just deploying them manually (mostly because I’ve already got 2 parse servers running this way and I already have some infra related script [deployments, etc, etc] setup).

I’ve never used docker for anything in production, but if getting multiple sites running from a single parse code base is not an possible, it might be worth looking into it. I was just hoping that I could handle it this way, so that the server runs nice and lean and that my setup is essentially config driven.

Thanks for taking the time to reply and for your suggestion.

Can’t you just add a TENANTID to each object ?

Hi Zak,

Thanks, I did consider this, seeing as one could add a beforeSave check to ensure that each object always gets a tenantId. The problem though, ensuring that a tenant id is always provided when query for data. Because there’s now built in way to enforce this, it leaves tenant data a bit exposed for my liking (along with a bunch of other complexities around ownership, permissions, etc).

I know you were asking questions around this topic. May I ask what you settled on?

The separate instances will work really well for me. I just need to figure out if I can do it in my preferred way. If not, I will have to reconsider things.