Core: Multi-tenancy approach

Created on 20 Apr 2016  路  14Comments  路  Source: flarum/core

As I have shared on the forum, I need and want to make Flarum support multi-tenancy, in a simple, clean way, without complicating the existing code, forcing existing users to do any change or making installation harder at all.

This is my approach:

For now, multi-tenancy would mean that we can use the same code for multiple domains or sub-domains but different or / and common databases. To be more precise, in my case I would like to be able to use a master database with common (_users_) and global data (global, multi-domains _settings_) and a domain specific database for each domain (with posts, comments and so on).

So, first thing I am doing is adding a new tab to the installer form, called _Advanced_. Here, users will be able to specify the master database for common tables. The installer will save the connection data for the master database and domain-specific database, like this:

<?php return array (
  'debug' => true,
  'domains' => array (
    'mydomain1.com' => array(
      'masterdb' => array(
        'driver' => 'mysql',
        'host' => 'localhost',
        'database' => 'master_database',
        'username' => 'root',
        'password' => 'root',
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => 'tbl_',
        'strict' => false,
      ),
      'domaindb' => array(
        'driver' => 'mysql',
        'host' => 'localhost',
        'database' => 'mydomain1_database',
        'username' => 'root',
        'password' => 'root',
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => 'tbl_',
        'strict' => false,
      ),
      'url' => 'http://mydomain1.com',
      'paths' => array (
         'api' => 'api',
         'admin' => 'admin',
       ),
     )
);

If the user is not interested about multi-tenancy, the master database setting will not be created and the domains array will contain one domain with one database for everything.

In the case above, the installer ran for the first time. Now, imagine we have a second domain or sub-domain pointing to the same folder as the first. When that domain is accessed, if it is not found in the domains array, the installer is shown again, for this domain. Again, if the user wants this domain to share common data from a master database, the _Advanced_ tab of the installer form will allow him / her to set it up. If the chosen master database is already populated with tables, they will not be created. If the user doesn't want the master database, then all tables will be created in the domain-specific database specified in the default tab of the installer. In any case, the domain will be added to the array in the config file. The next time we access it, the forum is displayed.

What happens with the existing forums when this code would supposedly (and hopefully to me) be implemented? Their configuration file only holds a database and single domain.
Well, if there's no domains array then we will assume that that there's one single database, which we will use. The configuration file's structure would be changed only if a second domain pointing to the same folder would be accessed and configured, storing both domains' settings as in the example code above.

So, this is what I have in mind now. Of course, the way databases are used will be changed quite radically.

This big change will allow us to:

  • have domain-specific languages and extensions
  • have common settings and extensions, "overloaded" by domain-specific ones
  • reuse tables and share database in a lot of ways (single master - multiple slaves, multiple masters - multiple slaves, each domain with its own database)
  • single login on multiple domains (this needs more tricks and would be attended in another issue)

Maybe this looks a little bit crazy or out of your vision for Flarum. Well, I will do it anyway for what I need. If you will consider that it is worth, I will do a PR when done

Most helpful comment

@hifall We are currently working on some last large refactorings. One of them was to introduce a new Site class, which represents the environment or installation of Flarum.

(I will probably provide an interface for these that would need to be implemented for multi-tenant environments, e.g. to return a different Application instance based on the subdomain requested.)

All 14 comments

Personally I don't think multi tenancy should be part of the core. As a third party extension it would be fine.

Also I actually had a Flarum installation running in production as the old international forums. They used almost the same set up but without a master database, instead it would check whether the subdirectory was present as config file and load that instead of the default. You could adapt it to use the hostname instead.

Here is the snippet I used in the config.php:

if(getenv('FLARUM_TENANT')) {
        $tenant = getenv('FLARUM_TENANT');
} elseif(array_key_exists('REQUEST_URI', $_SERVER)) {
        $path = $_SERVER['REQUEST_URI'];
        $parts = explode('/', $path);
        $tenant = isset($parts[1]) && strlen($parts[1]) >= 2 ? $parts[1] : null;
}

if(file_exists(__DIR__ . "/config-{$tenant}.php")) {
        define('FLARUM_TENANT', $tenant);
        return require __DIR__ . "/config-{$tenant}.php";
}

I used the global constant in a custom extension that would generate the js and css with the tenant string prefixed. This way each tenant could set up their own extensions without them being active everywhere.

I would love to make this into a stable extension but I don't know if there are events for database configuration and operations (queries and migrations) that I could handle. Is the only thing I would need

There are no events. Your best bet is to overrule implementations using IoC - inversion of control. I recommend reading the Laravel documentation about that.

Thanks. I just hope I don't have to change anything in core, so I can keep updating it properly with Composer

Any changes you need in core are discussable. If an extension cannot be created then at least @flarum/core should take the time to consider how to support it in the long run. At least I believe that is the philosophy of Flarum ;)

@bmalex88 I am going to close this, unless one of the core devs re-opens it. I think they agree with me on this one. Feel free to continue discussing tenancy here though, I am subscribed and others can do the same. If you have any open code visible, people (including me) might even be willing to contribute.

I do agree.

As for proposal, @bmalex88: Good thinking.
I would probably suggest you try to fork flarum/flarum and create an alternative "skeleton" application - that seems like the way to go (better suited than an extension in this case). If you can't make it work, be sure to ask - we'll gladly help in getting the core configurable enough for this kind of setup.

@franzliedke and @Luceos , in order to achieve a basic level of multi-tenancy support I have implemented a simple solution: configuration files names contain the current domain on which the installation has been carried out. So, if you have 2 domains _domain1.net_ and _domain2.com_ pointing to the same source code folder, for example, you will have 2 separate configuration files config_domain1_net.php andconfig_domain2_net, generated by the installer and used further on. If a config.php file is found, then it will have priority (the others will be ignored), in order to keep everything backward compatible. I think this is a small change that will offer more freedom to multiple domains owners (will make it possible to have a domain for each language, using the same code and having the same extensions at disposal but using its own configuration - database, enabled extensions, language and so on). I can PR

What's the status of multi-tenancy? It'd be a very interesting and useful feature IMHO. @bmalex88 , did you actually PR?

@hifall We are currently working on some last large refactorings. One of them was to introduce a new Site class, which represents the environment or installation of Flarum.

(I will probably provide an interface for these that would need to be implemented for multi-tenant environments, e.g. to return a different Application instance based on the subdomain requested.)

Really glad to hear, @franzliedke. Will this come with the first official release of Flarum? Any ETA on that? Thanks!

It will be part of the next betas.

As for a release date, I can only point you to our FAQs, I'm afraid. :wink:

Has this become part of beta 7.1?

@ahrasis nope. Neither is this planned for any beta release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

luceos picture luceos  路  4Comments

jordanjay29 picture jordanjay29  路  3Comments

ardacebi picture ardacebi  路  4Comments

franzliedke picture franzliedke  路  4Comments

clrh picture clrh  路  4Comments