This document is written with assumptions that you have:

  • installed Drupal 5 before
  • access to your server via ssh / telnet
  • access to MySQL database / you can setup your own MySQL database

In this example, I will setup two sites using:

  • Drupal 5
  • One database on MySQL
  • Linux-based server

Also:

  • Website’s url is: www.example.com
  • Drupal is installed in: /var/www/drupal
  • Names of sites are: ‘site_1’ and ‘site_2’

These sites will share session and user-related tables so once users login to one of the sites, they can view the other site without logging in. User roles and profiles are also shared among the two sites. And to be clear, "shared sign on" means that when you created a user/pass on one site, it will work on the other site(s). It doesn't mean that you'll be automatically logged in to all sites at once (if that's what you want there are two modules to help: singlesignon and fierce_sso.)

1. Prepare database and database user

1.1. create a database and user

In this example, I will use:

  • DB name: drupal_db
  • DB username: druser
  • Password: twosites
  • Access right: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES

2. create and modify site configuration

2.1. duplicate settings folder

Duplicate a folder contains site config information under drupal/sites/

dru@/var/www/drupal/sites: cp –R default/ www.example.com.site_1
dru@/var/www/drupal/sites: cp –R default/ www.example.com.site_2

2.2. Modify config files

2.2.1. provide DB connection detail

Open settings.php in a folder under www.example.com/site_1. Go to line 93 (or somewhere around there) and you should find a line that goes:

$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://druser:twosites@localhost/drupal_db';

2.2.2. set prefixes for table names

just below the line we just changed above, there is a line that goes like:

$db_prefix=’’;

Since we want to share a database among two sites but not completely, we decide which tables to share / not to share. This can be done by adding prefixes to table names. An example given below is for sharing user-related tables, sequences (this table is a ‘counter’ of users, nodes and other stuff) and session information.

$db_prefix = array(
'default'   => 'site_1_',
'users'     => 'shared_',
'sessions'  => 'shared_',
'role'      => 'shared_',
'authmap'   => 'shared_',
'sequences' => 'shared_',
'profile_fields' => 'shared_',
'profile_values' => 'shared_',
'users_roles' => 'shared_',
);

the second line that goes:

'default'   => 'site_1_',

this means tables that are not shared with other sites will have a prefix ‘site_1_’. So for example, table name ‘node’ will be ‘site_1_node’.

Now, when you finish editing this file, open and edit drupal/sites/www.example.com.site_2/settings.php. This time, you enter the exact same information for the database connection. So the line around 93 should look like:

$db_url = 'mysql://druser:twosites@localhost/drupal_db';

Then, you add an array of prefixes, which will look like:

$db_prefix = array(
'default'   => 'site_2_',
'users'     => 'shared_',
'sessions'  => 'shared_',
'role'      => 'shared_',
'authmap'   => 'shared_',
'sequences' => 'shared_',
'profile_fields' => 'shared_',
'profile_values' => 'shared_',
'users_roles' => 'shared_',
);

notice a prefix in the second line is now ‘site_2_’. At the installation, all tables will have this prefix except for the ones that are specifically given a prefix ‘shared_’.

3. create static links

In order to access site_1 and site_2 from web browser, you have to make static links to drupal directory. In the directory /var/www, enter the following commands:

ln -s drupal site_1
ln -s drupal site_2

now access ‘www.example.com/site_1’ (and ‘site_2’). If you see a drupalicon and a message like ‘Unable to select database’, go back to 2.2.1 of this manual and check if you have all details correct, including a single-quotation and semicolon.

If you see hundreds of messages like ‘Warning: Table 'continuu_test.access' doesn't exist’, you are almost there. While this may look scary or makes you think you have done something wrong, it is just saying that it cannot find tables Drupal needs to have access to. This is simply because we have not yet finished installing Drupal. All the necessary tables will be created in the next step, which is described below.

4. install drupal

Since we have entered information for database connection, we can run the install script (install.php) straight away, instead of giving all the detail to installation wizard. From your web browser, just access:
http://www.example.com/site_1/install.php
http://www.example.com/site_2/install.php

Installation should complete within a second (or two). If you fail to install:

  • read the error message and find out what is wrong (wrong DB name, username or password, etc.)
  • make sure $db_url (around line 93 in settings.php) ends with a quotation mark and semicolon. ( ‘; )

If you have two separate Drupal sites and are thinking about merging them with above method, I would recommend you not to do it. Yes, it is not impossible. You can rename tables and modify values in sequence table and so on, but i tried it and had a hell of a hard time... If you have sites already setup, using CAS or other authentication services is more appropriate than merging.

Comments

jjh’s picture

Some more ways to go if you want a Single Sign On Solution using Drupal:

As explained in the article , the method of sharing database tables between several drupal sites enables people to use the same username/password combinations on all sites. It does however not automatically log you in at all subsites. Besides the singlesignon and fierce_sso modules, the Drupal Multisite Login Module (http://drupal.org/project/multisite_login) will also log you in automatically.

If you are looking for solution to integrating several non-Drupal sites into a single-signon network, then the Drupal Modules supporting CAS, CoSign or Sebboleth authentication might be an option for you. Note however that these options will usually not run on the usual cheap PHP&MySQL hosting services.

If you don't need the Single-Signon-Features (that log you in automatically), but if all you need is to have the same username/password combinations on a number of sites, then consider using OpenID (which is very well integrated into Drupal) or LDAP authentication.

detsky’s picture

...works well. But the following should be considered, if the database is converted from an existing site which contains already nodes, users, etc.:

Table 'sequences' (new: 'shared_sequences') contains entries in the form
name = "table"_"id",
id = counter / max existing id of "id" in table "table".
These counters tell Drupal how to generate new content (nodes, comments, users, etc.)

You must convert the name entries to the newly renamed table names:
name = "new-table"_"id"

Otherwise Drupal will create these entries itself when necessary, but starts counting from the beginning. Soon it will collide with id numbers of existing content.

Example:
users_uid -> shared_users_uid
comments_cid -> site_1_comments_cid
files_fid -> site_1_files_fid
menu_mid -> site_1_menu_mid
node_nid -> site_1_node_nid
node_revisions_vid -> site_1_node_revisions_vid
term_data_tid -> site_1_term_data_tid
vocabulary_vid -> site_1_vocabulary_vid

Depending on your installed modules there might be other entries which must be changed, too.

kingandy’s picture

Is this the only thing apart from the table names themselves that needs to be updated?

I've dumped my db using mysqldump and edited the file using VI ... rather than do it by hand I've used a search-and-replace:

:%s/DROP TABLE IF EXISTS `/DROP TABLE IF EXISTS `prefix_/g
:%s/CREATE TABLE `/CREATE TABLE `prefix_/g
:%s/LOCK TABLES `/LOCK TABLES `prefix_/g
:%s/INSERT INTO `/INSERT INTO `prefix_/g
:%s/ALTER TABLE `/ALTER TABLE `prefix_/g

... and then updated the sequences (now `prefix_sequences`) table by hand, checking each contrib module for {} syntax. Importing the change .sql file seems to have worked - as in the tables are there - but on duplicating the site and editing the new settings.php to include a $db_prefix declaration, the second site still seems to be using the same tables. (I tried creating a new node on one site and it is visible on both.)

I've truncated all the cache tables. Is there something obvious I'm missing that will tell the site to use the new $db_prefix?

EDITED TO ADD: Ahh, I didn't spot the $db_prefix = ''; at the end of the $db_url row! It was unsetting my prefix. All better now.

++Andy
Developing Drupal websites for Livelink New Media since 2008

detsky’s picture

In my opinion, the 'sessions' table should not be shared! Otherwise users logged in at one site are shown at all sites as logged in. Moreover, a certain user logged in at two sites is shown twice at all sites. Keeping the sessions table individual prevents this. Are there other arguments to share the table?

dokumori’s picture

>Moreover, a certain user logged in at two sites is shown twice at all sites.

yeah, that's the whole point ;)

> Moreover, a certain user logged in at two sites is shown twice at all sites

ah, I don't display 'who's logged in' block, so I didn't notice.

the benefit of this method is the shared user account and profile. if you don't really need it, then openID is the best option IMO.

jippie1948’s picture

In order to make the subscriptions module work for two sites with shared users

I shared the subscriptions_user table while each site has their own versions of the other three subscriptions tables.

It all works fine.

All the best,

JanPieter

superdorx’s picture

Looking for a solution based on the following criteria.

1.1 - www.example.com will be a portal page that links to Canada (www.example.ca) and US (www.example.us).

1.2 - These pages will share the same database but not the same users tables. I believe if I don't include 'users' => 'shared_' in the settings.php for both subs it should create sub users tables. Please advise if this is the proper way of handling.

The following is beyond this topic but maybe it has some importance in helping me make a better decision on how to approach this project.

- Each sub-site of the multi-site will have different users that will see different prices in an Ubercart shopping cart.

I would appreciate any feedback, advice or strategies you can propose.

Cheers,
------------------------------------------
Solutions for interactive design™
www.ss-interactive.com

Dan

superdorx’s picture

In the directory /var/www, enter the following commands:

ln -s drupal site_1
ln -s drupal site_2


Where exactly do I include these commands? Is there a file I should open in the directory /var/www?

Thanks
------------------------------------------
Solutions for interactive design™
www.ss-interactive.com

Dan

HansBKK’s picture

This document is written with assumptions that you have access to your server via ssh / telnet

Note that I've set up many multi-sites without using the link command, haven't gone through this doc carefully enough to judge but it's just one person's recipe, not a standard way of doing things.

Note also it sounds like you're doing the opposite "sharing profile" in that you want to have site-specific user/role/permission etc tables but share the data.

Regarding your desire to share "most but not all of the data" (ie have different prices for different sites), I've seen comments from people that know a lot more than I do that this is very difficult if not impossible to accomplish via shared tables.

You might want to consider other ways of meeting your goal. I don't see why you even need to have two different user databases. Maybe implement user profiles as nodes and add a CCK field for US vs Canada and retrieve the price from the appropriate CCK field in the product node based on that?

Keep in mind you probably won't be able to keep the different pricing "secret" unless you're going to depend on IP geolocation - but what about when one of your Canadian customers is accessing your site Stateside?

Hope this helps.

NToronto’s picture

Step 3 assumes you have telnet or SSH access to your server to create the static links.

I only have FTP access to my server. Can anyone suggest an alternative to static links using PHP?

HansBKK’s picture

The support staff of a decent hosting service should be happy to fullfill this type of request.

svdoord’s picture

I'm not sure if you can (and are allowed to) do this in your .htaccess, but the Apache Alias directive can serve as an alternative to symlinks. For example:

Alias /site_1 /var/www/drupal

Maybe worth to try. If you do, please post your findings here :)

nikmahajan’s picture

Can you explain more on this "Note that I've set up many multi-sites without using the link command". I mean how can you share usernames, logins, profiles etc in multisite without using SSH.

websitetec’s picture

Drupal 6.8/Linux/PHP5.2/MySQL 5.0

I had the same problem as one of the previous commentors(djbdjb-all of the table exists warnings) and the install wouldn't finish but I found a solution so I will share it here.

I did all of the above except that I did not use the shared_ prefix for both of my sites, in the site1 settings.php I used shared_, then in site2 I used shared1_. This effectively created 2 sets of shared tables (shared_ and shared1_) After I finished the installs I went into the database and executed the following query to move the user that was setup in site2 over to the shared_users table from the shared1_users table:

INSERT INTO `shared_users` (name,pass,mail,mode,sort,threshold,theme,signature,created,access,login,`status`,language,picture,init,data)SELECT name,pass,mail,mode,sort,threshold,theme,signature,created,access,login,`status`,language,picture,init,data FROM `shared1_users` WHERE ( `shared1_users`.`uid` = 1 )

Now, the next issue was that the user created in site2 was no longer the default admin for the site. If you look in the menu_router table for site2 you can pretty much understand how the user id is used to grant the rights but I didn't want to have to change a text field in dozens of rows in the menu_router table for each site so I created a role named Administrator and assigned the site2 user to it. Since the roles table is one of the shared tables it was in every site BUT, I had to log in to both sites as the adminstrator of site1(the first installed site) and set up all permissions for the role. Once I did that it saved all of the site2 user's information correctly in the site2_menu_router table and gave him full perms on site2. I did take it 1 step further after the fact by creating a separate administrator role for each site so I didn't have to give the admin of 1 sight administrator rights to another site.

So now I have a "master" user which was the initial user setup in the first site install and then regular admins for each site. I haven't done any more configuring yet so I don't know if there will be other issues but I doubt it because I am only sharing 4 tables and they are all about users and perms.

nikmahajan’s picture

I have cpanel hosting and also an access to SSH. My drupal is installed in the root directory and not in the "Drupal" folder. It is drupal 6 and not 5.

I was trying to install multisite with shared login at site1.example.com according to the guide above but couldn't achieve it. Actually I don't know how to run SSH commands. I can login at SSH but I couldn't go to var/www because no such directory exists there. My drupal is installed in home/user/public_html/ and not in var/www which is not supported by my host. However when I try to open home/user/public_html in SSH using 'open' command, it says permission denied. And I am no good at SSH.

My goal is to achieve shared login among all the multi sites including the parent site at www.example.com. If one person registers at www.example.com, he/she can login to other sites also with same login credentials and vice a versa. I can do multi site as guided at http://drupal.org/node/257661#comment-841411 but couldn't achieve shared login.

Please guide me on achieving the shared login in multisite. Your help will be appreciated.

nikmahajan’s picture

After lot of workarounds, I managed to install multi site sub1.example.com and sub2.example.com with shared user tables but got following problems also.
1) Shared sign on didn't work. It gives invalid username/password message.
2) User gets logged into the site but when click on any link, gets logged out. Then he again logs in, and automatically goes to the previously clicked link but again when he tries to navigate gets logged out. This is happening after every click.

These are the only problems I got until now because navigating through the sites is not yet easy. I automatically gets logged out after each click.

Thing to be noticed is that putting same prefix shared_ in both the sites give few database errors so I used shared1_ for the second site as mentioned by websitetec at http://drupal.org/node/147828#comment-1177560.

Please help.

nelsonlee’s picture

I just setup my website and it works.

A) For the above procedure (and comments), SKIP modify part 2.2.2 when setup site 2, until you have finish setup your database (in part 4):
$db_prefix = array(
'default' => 'site_2_',
'users' => 'shared_',
'sessions' => 'shared_',
'role' => 'shared_',
'authmap' => 'shared_',
'sequences' => 'shared_',
'profile_fields' => 'shared_',
'profile_values' => 'shared_',
'users_roles' => 'shared_',
);

The reason is, it will return a lot of errors on "duplicate table already exists" during setup of site 2. Even worst, it just create some tables and then terminate the script in the middle. In this case, you need to drop the tables to retry (or you may manually create the remaining tables).

My advice is, change the script to:
$db_prefix = array(
'default' => 'site_2_',
);

Let Drupal creates duplicate tables in the database first, then modify the script back to
$db_prefix = array(
'default' => 'site_2_',
'users' => 'shared_',
'sessions' => 'shared_',
'role' => 'shared_',
'authmap' => 'shared_',
'sequences' => 'shared_',
'profile_fields' => 'shared_',
'profile_values' => 'shared_',
'users_roles' => 'shared_',
);

Done! You may or may not delete the 8 duplicate tables (site_2_users, site_2_sessions, ...).

B) For multisites single DB, there is no need to install additional module to login both sites. Just uncomment the line and change to your domain name:
$cookie_domain = 'www.yourdomain.com';
in the subdomain's settings.php file.

Users can login multisites with one username/password with single login. Once logout, all sites are logout.

spiritkarma’s picture

This works great except for ONE thing that I had to do in Drupal 6.17 at least:
I had to DROP the previously used tables for _sitea, and _siteb that had been "replaced" (in function!) by the shared_ tables... now, I don't know exactly WHICH table it was (probably Users table), but if I just told site_a to start using "shared_users", while site_a_users still existed, then I was done! Maybe some people this step is optional, but not on my host/install/setup combination.
p.s. I'm using 100% sub-dirs for all (3) sites, no root domains (in fact same root domain for all 3).

Also:
I would like to add that if you want to share permissions as well, then just add the line
'permission' => 'shared_',
to your array.
This works for me since all the admins are 1) trustworthy, 2) generally the same people.
Additionally, I can change permissions for different roles on ALL sites WITHOUT having to change which site I am at!

NewZeal’s picture

I'm working on a system to split a site in order to achieve a performance gain in sites that use a lot of modules (80 or more). Rather than share a small number of tables as shown in this example I want to share as many tables as possible but separate out system, blocks, menu, caches, node_access and sufficient tables to reduce the module load on each subdomain so that each subdomain carries a subset (about 40 or less) of the modules used in the site overall rather than all of them. For instance I want to have:

store.example.com - ecommerce
jobs.example.com - jobs section
www.example.com - has front page and main section

I have set up so that the following tables are not shared:

menu
blocks
blocks_roles
boxes
all caches
variable
system
node_access

Having done that I had to find a way to share the main menu systems across the subdomains so that the user ostensibly remains on the same site. For that I wrote a module that propagates menu systems selected from the master domain to the subdomains. This module can be found here: http://webdev.passingphase.co.nz/?q=project/site-splitter. Currently it works well, only doesn't always retain the menu in the active block depending on what changes are made to the master menu or the subdomain menu systems.

cfgauss’s picture

I've been trying to setup a multisite on my development Linux box where http://localhost/drupal maps to the file /var/www/localhost/htdocs/drupal so that I could setup several sites, one per chapter, of Using Drupal by Byron et. al (a wonderful text, by the way), and your method is the only one I could understand and the only one that actually worked after two solid days of reading all the multisite documentation I could find here.

Thanks!