Multisites for Groups as Roles.

The solution is designed to run an affiliated network of sites for groups, from a single Drupal installation.  It allows you to share users and content across a group of sites such as:
  - example.local
  - finance.example.local
  - plan.example.local

By default, these sites share almost all tables in your Drupal installation. But some tables  will be prefixed in order to allow a site to define it's own configuration for theme, menus, blocks and one or two other things.

This tutorial is based on - and extends - the idea of "Groups as roles" described in our first tutorial at http://drupal.org/node/200631. It shows you how to achieve the following multisite requirements:

  1. Separate site (domain) for one or more groups or departments.
  2. The solution must be an integrated system for running many domains/websites.
  3. The solution must use a single Drupal code-base for all websites.
  4. Each domain/website must be able to define a look for its user interface using site specific theme, menu, blocks.
  5. Nodes, images and user/contact records - most basic content must be shareable across all domains.
  6. Each website needs to have both a ‘public’ part (for anonymous users) and a ‘private’, community part (for authenticated users)

Drupal already provides most of the required functionality in its core. Our solution is based on Drupal's taxonomy module. We think it is best to use as much as possible from the Drupal core and as few as possible contributed modules, because of issues about module compatibility and upgrades. (See tutorial one for more explanation on this. Also note: in tutorial one we added one contributed module, Taxonomy Access Control, in order to restrict access and editing control to specific groups of users but this module is not required for the multisite solution presented in this second tutorial. However, in order to see the power of our total Groups/Multisite solution, we recommend considering the two tutorials together.)

The rest of this tutorial will use as an example a company website (example.local) that will have site areas and content for two groups: a Finance department and a Planning department. The requirement to restrict the editing of each department's area/content to members of that department only, was described in the first tutorial: http://drupal.org/node/200631.

Now we will spawn two new websites, finance.example.local and plan.example.local; put the public content of the finance department onto the front page of finance.example.local, and planning department content onto plan.example.local. At the same time, users and editors will be able to move freely between our three websites (example.local, finance.example.local, plan.example.local) without being required to log in again.

Let us first list the steps we are going to take:

  1. Install Drupal for multisites.
  2. DNS configuration.
  3. Installation continuation.
  4. Define groups, roles, users and grants.
  5. Site specific configuration
  6. Test

1. Install Drupal for multisites
The process of default Drupal installation is described very well in its INSTALL.txt.
This tutorial is written for Drupal 5.x version.  Make sure you have drupal files in you web server document root folder.
Create a database "gar_tutorial2" and a user with the same name "gar_tutorial2" using you "phpmyadmin" or any other favourite db administration tool.
For simplicity make our user able to connect without password.
On your filesystem go to the "sites" folder under you drupal root installation.
create three new subfolders (example.local, finance.example.local, plan.example.local) like this:

  root
      - sites
          - all
          - default
          - example.local
          - finance.example.local
          - plan.example.local

Do not try to view your site in your browser until you have completed the entire configuration described below.

Open the file 'settings.php' in the sites/default folder. Go to line 93 (or somewhere around there) and you should find a line like this:

$db_url = 'mysql://username:password@localhost/databasename';
change this line with your DB name, DB user and password. It will look like:
$db_url = 'mysql://gar_tutorial2@localhost/gar_tutorial2';
Just below the line we just changed above, there is a line that goes like:
$db_prefix=’’;
Since we want to share some but not all of the tables in the database between our sites, we can instruct Drupal by adding site-specific prefixes for the names of those tables we do NOT wish to share.
Put the following into your settings.php file:

$db_prefix = array(
'default' =>'',
'blocks'=> 'main_',
'boxes' => 'main_',
'menu' => 'main_',
'variable' => 'main_',
'cache' => 'main_',
'cache_menu'=> 'main_',
);

This sets table sharing as the default, except for those tables listed, which are prefixed by 'main_'.

Our users and editors must be able to move freely between our three websites. To achieve this, edit the variable '$cookie_domain' near the end of the settings.php table, so that it looks like this:
$cookie_domain = 'example.local';
Save the settings.php file and copy it to our 3 site specific folders.
Then you filesystem should look like this.

root
     - sites
         - all
         - default
              - settings.php
         - example.local
              - settings.php
         - finance.example.local
              - settings.php
         - plan.example.local
              - settings.php

We will keep the settings.php file identical in the sites/default and sites/example.local folders, but we must change it a bit for sites/finance.example.local and sites/plan.example.local.

All setting.php files should contain the same value for the $db_url variable:
$db_url = 'mysql://gar_tutorial2@localhost/gar_tutorial2';

Open settings.php in sites/finance.example.local. Edit the $db_prefix variable, replacing 'main_' with 'finance_' like this:

$db_prefix = array(
'default' => '',
'blocks' => 'finance_',
'boxes' => 'finance_',
'menu' => 'finance_',
'variable' => 'finance_',
'cache' => 'finance_',
'cache_menu'=> 'finance_',
);

Repeat for settings.php under sites/plan.example.local, but replace 'main_' with 'plan_':

$db_prefix = array(
'default' => '',
'blocks' => 'plan_',
'boxes' => 'plan_',
'menu' => 'plan_',
'variable' => 'plan_',
'cache' => 'plan_',
'cache_menu'=> 'plan_',
);

Additional helpful information can be found in this discussion for deciding which database tables to share between sites:

Multisite Database Configuration Example
http://groups.drupal.org/node/4247

That link, like this article, is based on Drupal 5 and does not translate directly to Drupal 6.

2. DNS configuration For the solution to work correctly, the DNS record of your server must accept multiple DNS entries pointing at a single IP address that hosts your Drupal installation.
For example, on a local testing machine, you can edit your "hosts" file (see http://en.wikipedia.org/wiki/Hosts_file for information on where to find it) and add the following entries:

127.0.0.1 example.local
127.0.0.1 finance.example.local
127.0.0.1 plan.example.local

On your real server the two basic methods for doing this are either to:
  - Setup WildCard DNS, so that *.example.local resolves to your Drupal site.
  - Setup VirtualHosts so that finance.example.local, plan.example.local, etc. all resolve to your Drupal site.

It is beyond the scope of this document to explain how to configure your DNS server.  For more information, see:
- http://en.wikipedia.org/wiki/Wildcard_DNS_record
- http://en.wikipedia.org/wiki/Virtual_hosting

After you have enabled multiple DNS entries to resolve to your Drupal installation, you may go to next step.

3. Installation continuation.
I assume you have installed phpmyadmin or another tool that helps you to administer your database. You will need that.
But first let us perform database installation for our 3 sites.

Open your browser and point it to http://example.local/install.php. Installation should be successful and our database now contains all tables.
As expected your database contains all tables not prefixed by default and only tables mentioned in settings.php will be prefixed with 'main_'.
Now we will drop created tables leaving only prefixed ones there.
Open your phpmyadmin and drop all tables in gar_tutorial2 database, except for main_blocks, main_menus, main_cache, main_boxes, main_variable, main_cache_menu
Open your browser and point it to http://finance.example.local/install.php. Installation should be successful and your database now contains all tables.
As expected your database contains all tables not prefixed by default and only tables mentioned in settings.php will be prefixed with 'finance_'
Open you phpmyadmin and drop all tables in gar_tutorial2 database except for those prefixed with 'main_' and 'finance_'.

Open your browser and point it to http://plan.example.local/install.php. Installation should be successful and your database should now contain now all the tables you need - unprefixed ones to be shared, and three prefixed sets for the tables which should be site-specific.

If you want to add a new domain later after installation is complete, you can generate sql export script for the tables main_blocks, main_menus, main_cache, main_boxes, main_variable, main_cache_menu. Edit the generated script and replace 'main_' with your new site's prefix and run that script on the database. Do not forget to create a new folder under sites/ with a site-specific settings.php configuration file that reflects the db prefixing.

4.  Define groups, roles, users and grants.
Everything we need to do here is described in first part of this tutorial. If you have already implemented that, then go to the next step. Also you could download a Database dump at http://drupalproject.iofc.org/files/docs/u1/gar_tutorial_db_dump_sql_tar.gz and drop all tables (except prefixed) in your database and execute our script. After that you will have 2 groups (Finance and Planning)

Next we will build a dedicated site for each of our groups.

5. Site specific configuration
Make sure you have created the first user (username 'admin')
Go to "http://finance.example.local" and log in as admin. Configure the theme for this new site by going to Administer > Site building > Themes. Set the default to bluemarine (enable first).
We want our finance site to show Finance group content on its frontpage.
Go to  Administer > Site configuration > Site Information. In the "Default front page" edit box replace word "node" with "taxonomy/term/1".
Repeat this process after logging in to http://plan.example.local, but choose a different theme, and set 'Default front page' to "taxonomy/term/2".

6. Test
Having this configuration in place, your primary hub site (example.local) will show all content of all groups on its frontpage. Finance.example.local now shows only content from the Finance group, and plan.example.local site shows only Planning group content.
    You can use the "Views" module to achieve finer-grained control over frontpage presentation.
Because of menu and blocks table prefixing we can define site specific blocks and menus, to build completely different websites with some content particular to each site and some content shared.

Conclusion

Taken together, these two tutorials show how to construct multiple websites, each with several groups of users, with content shared and controlled in how it is made available to public visitors, authenticated users or just group members - all built on one Drupal codebase, and with minimal extra tables used. We have presented things in the simplest terms, and you will quickly see how to extend the approach to achieve more complex, fine-grained solutions. For example, we have experimented with adding a new vocabulary 'Domains', which makes it possible to place content in a more tightly-controlled way.

We would be happy to answer your questions related to the approach
described. But we also need your feedback - is it a good solution or are alternatives better? Are there problems we have not yet encountered? Please give us the benefit of your thought and experience. Thank you!

Comments

Anonymous’s picture

Very nice tutorial(s)!

How is it different for Drupal 6?

sukr_s’s picture

You can share user's picture across the multiple sites by overriding the theme function see http://www.drupalfx.com/content/sharing-user-picture-across-multiple-dru...

TazimHossain’s picture

I read this tutorial, but i can't understand that,

In NO 1:

root
      - sites
          - all
          - default
          - example.local
          - finance.example.local
          - plan.example.local

you say "root -> sites folder"
you say this folder is "/home/myubuntuname/sites" am i right?

but where i put drupal all files and folders?

Please help me...

paulfrottawa’s picture

none

paulfrottawa’s picture

The main prefix default is set different between my installations and then set identical at the end. Like so I enter into the site for insallation and while at the third page (database infomation) I add manually these settings to the settings.php file and then click save on the web page.

My dektop site

  $databases = array (
  'default' => 
  array (
    'default' => 
    array (
      'database' => 'atad',
      'username' => 'drupal',
      'password' => '*******',
      'host' => 'postgres',
      'port' => '5432',
      'driver' => 'pgsql',
      'prefix' => array(
'default' => 'main_',
'block' => 'desktop_',
'variable' => 'desktop_',
'cache' => 'desktop_',
'cache_menu'=> 'desktop_',
'cache_bootstrap' => 'desktop_',
'cache_block' => 'desktop_',
),
),
),
);

My Mobilesite

$databases = array (
  'default' => 
  array (
    'default' => 
    array (
      'database' => 'atad',
      'username' => 'drupal',
      'password' => '*******',
      'host' => 'postgres',
      'port' => '5432',
      'driver' => 'pgsql',
      'prefix' => array(
'default' => 'temp_',
'block' => 'mobile_',
'variable' => 'mobile_',
'cache' => 'mobile_',
'cache_menu'=> 'mobile_',
'cache_bootstrap' => 'mobile_',
'cache_block' => 'mobile_',
),
    ),
  ),
);

-Then change the 'default' => 'temp_',
To this 'default' => 'main_',
My two sites now shares content and display different site names. Like mobile for mobile and desktop for desktop

gavsiu’s picture

I'm having trouble trying to adapt this for Drupal 8. The settings.php file seems to have changed. Has anyone gotten this to work with Drupal 8?

evildoerizm’s picture

same question!