SECURITY ALERT - The Shared Sign-On module this tutorial formerly relied on has been withdrawn because of security risks. It is no longer available at all. There is a replacement module called Single Sign On. It should replace the Shared Sign-On module, but currently reports problems with user registration and recommends registration happens through the master site. If your solution requires branded registration pages, you could create a suite of registration pages on the master site and use the Theme Key module to apply the correct theme to each one, for a seamless user experience (except for the URL, obviously).

WARNING - Following this approach will make updates potentially trickier. It's not a major issue, but you must be mindful that you are sharing some tables amongst several Drupal instances, so you will need to be aware of install and update hooks which want to make changes to any shared tables. For example, it is possible for the update or install scripts of a module unique to one instance to break other instances if it makes changes to shared tables. There are other multi-site solutions, so plan carefully before selecting which one is right for you.

This tutorial makes two assumptions:

  1. You are _not_ a total newbie
  2. You have downloaded MySQL Workbench (to make life easier) - clearly this is not a pre-requisite - if you know and prefer command line MySQL then you can replicate the steps I provide easily enough

Make a copy of /sites/default to /sites/site1 and another to /sites/site2. You may add modules and themes directories in these new directories in the usual way for site-specific configurations. A files directory should be there already but create it if not. Rename /sites/site1/default.settings.php to settings.php and /sites/site2/default.settings.php to settings.php (and, for Linux, make sure both new files directories are writeable by the web user).

Add these lines to your hosts files:

127.0.0.1      site1
127.0.0.1      site2

Create three empty MySQL databases:

drupal_site1
drupal_site2
drupal_shared_tables

Go to http://site1 and run through the install process in the normal way, using the database name 'drupal_site1'.

In MySQL Administrator create a new back-up project of the 'drupal_site1' database containing _only_ the tables you want to share, save it and run it. The result should be a .sql file somewhere on your computer. For reference, the Drupal 6.x tables for sharing users are as follows:

authmap
profile_fields
profile_values
role
sessions
users

The absolute basic essential tables (if you don't want to share any data except for the users and sessions, no profile data, roles, etc.) are:

sessions
users

IMPORTANT: if you have Open ID authentication enabled you will also need to share the openid_associations table.

(This is not a definitive list. Nothing stops you from sharing taxonomy, etc. For example, with this configuration permissions are _not_ shared - each site has its own permissions matrix - but you might want to share one across all sites. Ditto with enabled modules.)

Edit the .sql script you created and update the database name within to 'drupal_shared_tables'. Using the Restore interface, run the .sql script. You should now have a database called 'drupal_shared_tables' containing only the list of tables above.

Go to http://site2 and run through the install process in the normal way, using the database name 'drupal_site2'.

Go back to your original 'drupal_site1' database and drop the same list of tables from the schema. Ditto for the 'drupal_site2' database.

Now our databases are ready.

Browse to your Drupal application and edit /sites/site1/settings.php. Change these lines (usually starting at line 93 in Drupal 6.3):

$db_url = 'mysqli://user:password@localhost/drupal_site1';
$db_prefix = '';

To:

$db_url = 'mysqli://user:password@localhost/drupal_site1';
$db_prefix = array(
    'default' => '',
    'authmap' => 'drupal_shared_tables.',
    'profile_fields' => 'drupal_shared_tables.',
    'profile_values' => 'drupal_shared_tables.',
    'role' => 'drupal_shared_tables.',
    'sessions' => 'drupal_shared_tables.',
    'users' => 'drupal_shared_tables.',
);

Note the all important trailing dot on the end of drupal_shared_tables - this is vital! You're pre-pending table name info to Drupal's default table name, so you need the dot or Drupal will try to select:

drupal_site_1.drupal_shared_tablesauthmap

Instead of the desired:

drupal_shared_tables.authmap

Do the same for /sites/site2/settings.php, but with $db_url set to drupal_site2.

You should now be able to login as the super user on both sites separately (http://site1/user or http://site2/user), using the credentials you entered when you installed site1, give them both different settings, modules, permissions and content but use the same user credentials. Moreover, if you create a user on site1, you will see them in users in site2, but with an entirely independent set of permissions you can decide on a site level.

Now for the shared logins. Download and unzip the Single Sign On module in to /sites/all/modules.

Enable the Single Sign On Controller module on the site you want to use as the master for logins (the controller) - in our case, site1. Enable the Single Sign On Client module on all other sites, for this example just site2.

Then IMMEDIATELY add the following line to settings.php for both sites (see the Single Sign-On README) or you will get PHP errors:

# Single Sign On settings:
$conf['session_inc'] = 'sites/all/modules/sso/session.singlesignon.inc';

Copy and paste the Controller information on site1 (found at admin/settings/singlesignon-controller) over to the Client settings on site2 (go to admin/settings/singlesignon-client). Save settings on site2 and logout of both sites. Clear your cookies to avoid any hang-overs from pre-single-sign-on days.

Go to http://site1/user and login. Now go to http://site2. You should stay logged in. Logout again and see you are logged out in both locations. Reverse it so you login on site2 and visit site1. Neat, huh? =)

Need a new site? Take a copy of /sites/default to /sites/new-site, make the necessary vhosts (optional, see below) and DNS/hosts changes, create a blank database, run the Drupal installer, drop the tables you don't want from your new database (the shared ones), edit settings.php adding the $db_prefix array as above, configure Single Sign-On and you're done!

Optional Apache settings

If you would like to set different Apache settings for your various sites (e.g. different access and error logs for each) add a vhost entry to Apache looking something like this:

<VirtualHost *:80>
    DocumentRoot "c:/path/to/drupal"
    ServerName site1
    ServerAlias site2
    <IfModule log_config_module>
        CustomLog logs/d6_access_log.log common
    </IfModule>
    ErrorLog logs/d6_error_log.log
    <Directory "c:/path/to/drupal">
        Options +Indexes
        AllowOverride All
        Allow from all
    </Directory>  
</VirtualHost>

This is not usually necessary.

IMPORTANT - if any of your client sites have any URLs that need to be accessed without an authentication check, the site concerned _must_ have a line in the 'Request paths' box of Single Sign On Client settings to exclude that URL from being redirected to the controller site for authentication. These settings can be found under 'Bot recognition' settings (admin/settings/singlesignon-client). For example, if one of your clients uses the Services module to expose Drupal-based web services you would add a line like this to that box, in order to exclude all your endpoints from the authentication check:

services/*

Remember, this only applies to client sites, not the controller, and must be done on all sites.

Comments

plebe’s picture

If you have a separate MySQL user for each site database, you must grant both users privileges to use the shared_db. For instance, if you have db_user1 using db1, you must grant db_user1 privileges for both db1 AND shared_db. Same with db_user2, must have privileges on both db2 AND shared_db.

nikmahajan’s picture

It is very difficult to understand for newbie like me. Can you explain on how to do it on cPanel based hosting such as Hostmonster. I mean where to put

127.0.0.1      site1
127.0.0.1      site2

and how to do this in cpanel

In MySQL Administrator create a new back-up project of the 'drupal_site1' database containing _only_ the tables you want to share, save it and run it. The result should be a .sql file somewhere on your computer.

greg.harvey’s picture

Right at the top...

This tutorial makes two assumptions:

1. You are _not_ a total newbie

Too hard to explain to a newbie. If you want to do such a complex setup, you really need to hire an expert if you can't do it yourself. Sorry. =(

It shouldn't cost more than $200, probably less.

nikmahajan’s picture

ok at least you can guide on how to do this in cpanel hosting environment.

sunshinee’s picture

You should be able to accomplish this through CPanel by using PhpMyAdmin and/or MySQL Database Wizard to create/modify the databases. Changes in the settings.php and directory structure can be handled through your file manager or FTP access. With respect to

127.0.0.1       site1
127.0.0.1       site2

just make sure the domains/subdomains you're using with multisite are all pointed to the same directory.

Disclaimer: While I do have a couple of customers on shared hosting, I haven't tried this myself. That said, I can't offer much specific help, but don't see any reason it shouldn't work.

Hope this helps.
~Joy

strellman’s picture

I found helpful documentation here http://drupalcode.org/viewvc/drupal/contributions/modules/sso/README.txt... (the readme.txt for the sso module)
It seems that SSO is required to make this work. Before this I couldn't understand how one '$db_url =' could handle multiple databases.
This statement in particular was what I needed:
On MySQL, you can use 'database_name.' as a prefix to share the tables directly from the controller's database, and use a blank prefix for the client tables (which reside in the client database):

Aha. So that $db_url is the database for the default prefix (possibly null), and as long as the other prefix is a valid database that can be opened by the same database.user and password, we are in business!

lelizondo’s picture

I wonder if it's necessary to create the drupal_shared_tables database to store the users data.

What's the difference between creating a 'drupal_shared_tables' db and using the tables 'authmap, users, profiles_, etc' from the database 'site1' to share with site2, site3...

wouldn't this make easier and risk less this part?:

"so you will need to be aware of install and update hooks which want to make changes to any shared tables"

I'm also guessing that 'drupal_shared_tables' db needs to have the same username/password combination from site1 and site2... Because I don't see anywhere settings for the 'drupal_shared_tables' db, so I'm assuming that the same username/password are necessary.

Luis

greg.harvey’s picture

It could be the site1 users, etc. shared across - but it's easier to have a shared table cos then you know where everything is. And where you are not correct is about the risk - it makes no difference to the risk of screwing up an install, cos you still have several sites trying to make the same db structural changes in turn in any case, even though the first site already made them. No change.

Regarding username/password, I think you are again correct.

lelizondo’s picture

I'm still worried about the risk issue. If I understand you, you're saying the greatest risk is when a module updates some of the shared tables. If that's the question, how many serious modules update/alter the users, roles, sequences, authmap and profiles tables? I don't really know but I'm guessing there's only a few. They usually work with their own tables.

What other risks are? I think that if I update every site in the multisite installation every time there's an update, I reduce the risk to a minimum.

And also, I would like to know some opinions in the next case, if I have 10 multisites, what's the best way to go for optimal performance, having one huge database with 10 multisites or having 10 databases plus 1 with the shared tables? The 11 databases will live on the same server.

I don't know, my guess is that 1 huge database could be a problem with performance, but I'm probably wrong about this.

Luis

greg.harvey’s picture

The risk is minimal really, but worth noting. Mainly, the first site you run the update on will succeed and all the other updates will show an error when they try to repeat the database structure changes (because they're already done). Normally this won't matter, but it might in edge cases, hence it being worth checking the update hooks beforehand to convince yourself there is nothing that might break.

Regarding performance, to be honest, if traffic on all 10 sites is not too high then one database is probably better. But if traffic is high and there's a chance you'll want to scale out to other servers in the future, you should use separate databases. Your call. You know your likely traffic requirements. For most people one db is fine, which is why this is an advanced only, edge-case HOWTO.

saquib123’s picture

Now that sharing users between two separate drupal installations is clear, is there a way of telling the users apart? How can we tell which site (Drupal installation) a user has registered on?
This is really important for finding out the amount of registrees to one site compared to the other(s) for marketing / analysis purposes. A conceptual answer as to how to target this issue will prove useful too.

greg.harvey’s picture

You could write a simple module that saves the registering site against the uid in a database table using hook_user().

Or you could create a private profile field to hold the data and hide it on the reg form and pre-populate it.

Both solutions would be simple to implement for a n00b module developer. =)

cog.rusty’s picture

I wonder where Drupal connects to the "drupal_shared_tables" database. The dot seems fine for running queries, but where does the database connection happen?

Is anyone using this successfully?

lelizondo’s picture

I'm using this and it works great, it's even easier than having one big database with everything on it. This way I could just backup one site, backup only the users, or even drop an entire site without compromising the rest of the sites.

The only difference is that I actually have a full site only to manage users, it's something like users.mydomain.com, it's not only some tables but a full installation of drupal. Then with single-signon (don't remember the name) a user automatically login in every site across my multisite installation.

Answering your question, drupal connects to the 'users' tables whenever drupal needs to connect (almost all the time). the connection to the database I think it's handled by bootstrap.inc..

Luis

cog.rusty’s picture

Let me rephrase the question. Connecting to a database requires some information: a database name, a user of this database, and a password for this user. Where are these connection information provided for the "drupal_shared_tables" database? I can only see connection information for the databases "drupal_site1" and "drupal_site2".

greg.harvey’s picture

The database user set for connection to the default database (e.g. drupal_site1) must also have permissions to access the shared database as those credentials will be used by Drupal to connect to all databases defined in the array of tables outside of the default database.

There may be a way to set different credentials for these databases, but if there is I haven't seen it and don't know. You could try asking in #drupalsupport on IRC - someone may know.

iwhy’s picture

I have two sites, and the file-structure like below:
..drupal/sites/all/
--------------------default/ : example.com db_example
--------------------site1/ : site1.a db_site1
--------------------site2/ : site2.b db.site2

the domains are: example.com,site1.a,site2.b
the corresponsive databases are:
db_example, to store the user infomation(only to handle the user login)
db_site1, to blog entry,articles and so on
db_site2 : a Ubercart site

i want to use example.com set as the master site,
my question is: what are the tables need to be shared? Is there a list about this?

lelizondo’s picture

Luis

chastytilayne’s picture

RE: I'm using this and it works great, it's even easier than having one big database with everything on it. This way I could just backup one site, backup only the users, or even drop an entire site without compromising the rest of the sites.

with this scheme are you sharing any other tables besides the ones suggested above? i get a shared user list, but it seems to break the single sign on functionality?? when i change the prefixing back to normal, single sign on works fine. i am using the domain modules as well.

thanks

lelizondo’s picture

I'm using this settings

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

The 'domain' module and a multisite installation are not compatible (anyone correct me if I'm wrong), so that's probabbly why signon it's breaking. Also, sharedsignon won't work with subdirectories, only with domains and subdomains

Luis

lelizondo’s picture

The 'shared' site it's a full working drupal site. It handles the master site for sharedsignon and the users, nothing more.

Luis

chastytilayne’s picture

just saw that note there about domain not working with multisite installs.

so you are doing all your domains/ sub domains manually? i am starting to regret using the domain module before i ran into this. its nice and easy to implement, but hard to update or maintain the domains once you get the set up. i am trying to merge content and users and have a bunch of domain specific tables numbered. im not good enough with sql to do it programmatically so its an issue.

just for the record i did get it to work with a pseudo "multisite" install. seperate code bases, but modules and themes shared across the installs via symbolic links.

domain module doesnt pick up individual settings/SITENAME/modules or themes folders. but it does allow shared modules via sites/all/modules. "globally" linked to the same folder, with the sites/default folder for shared modules/themes/whatever per domain group.

back to the topic of this post (most excellent using multiple databases with nifty . prefixing) i dont see why you couldnt take a setup like this and use separate(but identical) core code base to get indivudal settings.php files w/ single contributed code base and table prefixed single database or dot notated seperate database table prefixes like this for the domain "trees" in each settings.php file to share taxonomy or whatever really, per group of domains or across ALL the domains.. while still using the domain module.... (and of course the same database user credentials to have rights to all the differet databases you are referencing)

kinda like multi site with domain module??

thanks for your help. i will wait till i de-"domain"ify things and hopefully shared sign on will work again.

chastytilayne’s picture

i am guessing this is drifting away from the main topic of the post, which is most excellent info.
and thanks for replying so quick. i am still having issues though..

i am using pretty much your exact same setup. except the inclusion of the domain module.. :(

whats happening is the shared sign on module is going into a infinite redirect loop when those same tables are shared the same way. i went ahead and created a whole new install. on a seperate domain, subdomain, all different ways. no subdirectory deals, even tried setting the $cookie var in settings.php and got the same redirect loop when sharing the sessions table.

i have read here in the comments that sharing tables is somewhat sketchy with shared sign on. anyways. so i have another question. i am trying to merge three user bases together . and ideally allow single sign on. when i just share the users table alone, (or more specifically omit the sessions table) it seems to work more. in that each group of domains only require one login that persists across them all.

i am also using the domain module, and when i share the sessions tables (i think thats gotta be it) SSon goes into a loop. at first i was using the array you describe, including the users, profiles, etc.. tables.

I tried the 3 releases of sson for D6, clean urls enabled / disabled ,, etc.. sometimes creating the page not found issue which came up just before the last release of share sign on... ie redirecting to a page not found on the master url when trying to confirm the login... sometimes getting page not found on the slave url...

So back to the question. if the sequence ids are unique and random enough to sync to Uids securely; and if the user table itself still works to generate unique Userids/account logins/etc.. for folks across domain "trees", people are still signing up on all three sites and using the same passwords, etc. I havent tried the other tables, i would suspect that its in the sessions bit.

So looking at the table strucure, each session hash has a corresponding Uid entry. So each session would still only map to the proper id. As all of the users have unique Uids, even across all the domains, so you arent gonna log into "site a" with "userid 32" and have it map to a session on site b that is supposed to be unique and somehow map to a different "userid 32" or anything, no??? or for that matter any other session at all ??

sorry if this makes no sense. i cant explain it clearly.. if as admin i log into each master domain, a session entry for Uid 1 is created local to that domain. AFAIK that isnt causing security trouble is it?? this seems to be the best i can get out of the combination of modules for now.

by NOT sharing the sessions table it preserves single sign on per domain "tree", allows for a shared user base / logins /etc... and people just have to log in to each group of sites where share sign on will work within each group of domains... ???

anyways
thanks again. i can live with this. i am just jealous of the setup you describe. using a main users.foo.com site as the master domain for any number of other toplevel domains. if the multisite conflict with domain module is causing the problem i am bogarted. but the redirect loop seems like something that is specific to Single Sign, no??

i intend to re-merge the 3 domain trees into 1, so eventually it will get back to a unified login. sooner or later. if someone else is trying something similiar maybe this will help a little?

lelizondo’s picture

ok that was really long :) here are my thoughts

first, multisites and domain do the same thing, domain can share content across multiple sites, even with different domains.. multisite it's probably easier but it doesn't have all the functionality of domain.. with multisites you can easily share users, profiles, and roles, but I think that's the limit.. sharing content might not be as easy as with domain (I'm not saying it's impossible, I'm just saying that it's easier with domain).

domain it's also good when you didn't planned to have multisites and you have a working site... with multisites if you didn't create the tables with a prefix, you better go get some coffee because you're gonna be reading and breaking things for a long time before you make something works. if you try this, there's almost no help or reference in the entire universe about this so you're on your own, you just have to know that you have to change many things and you better have some basic experience with mysql..

About the infinite loop with singlesingon, I had that problem. To be honest, I don't remember how I solve it, I just know I did. I spent some time reading issues and I think I solved with the subdomain as master, an not a subdirectory. I don't remember having any issues with the sessions table, but that's probably not your case since you're using the 'domain'..

Finally, I'm not using multiple domains, just one single domain and multiple subdomains. If you're trying to set up a multiple domain installation, I guess things could get a little more complicated.

As for the administration of the whole network, it's really simple. I just have to install a site normally, I just use a prefix for the tables when I'm installing. After I have the site running, I edit the settings.php and change the settings (the code I posted in one of my comments) to join the sites. Drupal will end my session and I have to login again, but that's the biggest problem. I also get errors when installing the profile module, but that's just because drupal it's trying to create tables that already exists. Whay I do it's install, then I get the errors, then I disable the module, then I enable the module again and the errors are gone.

Good luck.

Luis

cjscullyca’s picture

I'm currently running 5 different sites I am planning to migrate over to Drupal. Two of them are very database intensive. I'm planning to use pgsql for my database for various reasons. The techniques you describe are pretty standard sql and php operations from what I can see. Have these steps been tested with pgsql? Is there anything different I need to do vs mysql?

lelizondo’s picture

I never used pgsql but I don't think they should be different. Since less people are using pgsql than those who are using mysql, sometimes there's bugs who haven't been reported for pgsql.. Only use pgsql if it's absolutely necessary.

Luis

cjscullyca’s picture

Thanks. I've got my test server set up so I'll have a whack.

cjscullyca’s picture

I tested the above with pgsql and got the following errors:

Warning: pg_query() [function.pg-query]: Query failed: ERROR: schema "drupal" does not exist in /drupal/includes/database.pgsql.inc on line 139

Warning: ERROR: schema "drupal" does not exist query: SELECT u.*, s.* FROM drupal.users u INNER JOIN drupal.sessions s ON u.uid = s.uid WHERE s.sid = 'f0c3e5bdb9e099f3d2cf66fcbf002ce4' in /drupal/includes/database.pgsql.inc on line 160

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /drupal/includes/database.pgsql.inc:139) in /drupal/includes/bootstrap.inc on line 1031

Warning: Cannot modify header information - headers already sent by (output started at /drupal/includes/database.pgsql.inc:139) in /drupal/includes/bootstrap.inc on line 630

Warning: Cannot modify header information - headers already sent by (output started at /drupal/includes/database.pgsql.inc:139) in /drupal/includes/bootstrap.inc on line 631

Warning: Cannot modify header information - headers already sent by (output started at /drupal/includes/database.pgsql.inc:139) in /drupal/includes/bootstrap.inc on line 632

Warning: Cannot modify header information - headers already sent by (output started at /drupal/includes/database.pgsql.inc:139) in /drupal/includes/bootstrap.inc on line 633

Looks like pgsql is interpreting the database.table notation as a reference to a schema that doesn't exist. Gonna dig into the pgsql documentation on this.

greg.harvey’s picture

If that turns out to be the case, please do raise a bug report with the core team. There should be no difference between the behaviour of Drupal with mysql or pgsql - that's the point of having a database abstraction layer! And especially in this case. There's no sensible reason why the database selection code should behave differently... =/

cjscullyca’s picture

It turns out this problem is an integral feature of pgsql. Here is what the pgsql documentation has to say.

5.7. Schemas

A PostgreSQL database cluster contains one or more named databases. Users and groups of users are shared across the entire cluster, but no other data is shared across databases. Any given client connection to the server can access only the data in a single database, the one specified in the connection request.

Note: Users of a cluster do not necessarily have the privilege to access every database in the cluster. Sharing of user names means that there cannot be different users named, say, joe in two databases in the same cluster; but the system can be configured to allow joe access to only some of the databases.

A database contains one or more named schemas, which in turn contain tables. Schemas also contain other kinds of named objects, including data types, functions, and operators. The same object name can be used in different schemas without conflict; for example, both schema1 and myschema can contain tables named mytable. Unlike databases, schemas are not rigidly separated: a user can access objects in any of the schemas in the database he is connected to, if he has privileges to do so.

The key thing is that pgsql will only allow you to access the database you connect to. So, if you point your browser to site2 and Drupal opens a connection to "site2db" to access "sit2db.public.anytable", it will not also be able to connect to "shareddb.public.users". Pgsql won't allow it. It doesn't matter whether you sent your prefix array in settings.php so all prefixes are set using the "database.schema. syntax above.

You could have Drupal create 2 database connections for each site. One would be to the shared database, the other would be to the content database.

The unique namespace pgsql schemas provide can be utilized in a similar fashion to this technique for mysql. However, it presents some upgrade issues as noted here http://drupal.org/node/45332.

I'll raise the issue with the core team as you suggest.

greg.harvey’s picture

Nice research! =)

I would definitely raise it. Probably two separate issues:

1. Documentation bug report ... (unless I'm mistaken - check) the documentation doesn't warn this approach will not work for pgsql.
2. Feature request to make it work! It is possible using db_connect(), as your research turns up, so the core code for managing db connections initiated from settings.php ought to do the heavy lifting and connection swapping necessary for pgsql to work.

Shame it doesn't work for pgsql but good to know why. Thanks for contributing. =)

cjscullyca’s picture

I raised the issue. About to run a test using the schema namespaces. Will post issues/success.

chrisa625’s picture

I'm having the same issue after following these instructions. I am using drupal 6.12 and mysql version 5.0.51a-community on apache 2.2.11. After updating the settings.php and removing the tables I get the above error also? Since I am using mysql is there a step I might have missed? The db user has access to both dbs.

Warning: Table 'devSite1.users' doesn't exist query: SELECT u.*, s.* FROM users u INNER JOIN sessions s ON u.uid = s.uid WHERE s.sid = '65377cb95b2aa378e012b39b5abb42e8' in /mysite/includes/database.mysqli.inc on line 128

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /mysite/includes/database.mysqli.inc:128) in /mysite/includes/bootstrap.inc on line 1031

Warning: Cannot modify header information - headers already sent by (output started at /mysite/includes/database.mysqli.inc:128) in /mysite/includes/bootstrap.inc on line 630

Warning: Cannot modify header information - headers already sent by (output started at /mysite/includes/database.mysqli.inc:128) in /mysite/includes/bootstrap.inc on line 631

Warning: Cannot modify header information - headers already sent by (output started at /mysite/includes/database.mysqli.inc:128) in /mysite/includes/bootstrap.inc on line 632

Warning: Cannot modify header information - headers already sent by (output started at /mysite/includes/database.mysqli.inc:128) in mysite/includes/bootstrap.inc on line 633

Thanks for any help.
Chris

el senor juju’s picture

Hello,
I tried this tuto and it works, but i've got a question:
If you have 4 sites, the site 1 is the master (in SSO module) the others are the slaves, so fisrtly you have to be log in site 1, then you are log in all of your sites. But if you begin to log in site 2 (site3, or 4), the sso doesn't work.
So, how do you ensure that you can log into the site 2 (or the site 3 or site 4) and the SSO still works on all your sites?

That's the only problem i have, if someone can help me, thanks.

ajayg’s picture

see may comments at the bottom. I have got this working.
http://drupal.org/node/291373#comment-2012680

lelizondo’s picture

Does anybody know any possible consequences when not sharing the 'role' table?

$db_prefix = array(
    'default' => 'main_',
    'authmap' => 'drupal_shared_tables.',
    'profile_fields' => 'drupal_shared_tables.',
    'profile_values' => 'drupal_shared_tables.',
    'sessions' => 'drupal_shared_tables.',
    'users' => 'drupal_shared_tables.',
);

I already have a multisite installation and I don't want to stop sharing the roles since is getting complicated...

Luis

el senor juju’s picture

If you doesn't share the role table, you have to keep all your role's table of all of your websites and to remove the line: 'role' => 'drupal_shared_tables.'.
Your roles will be differents in all your websites.

lelizondo’s picture

Yes, but does it have any consequences? My situation would be something like this:

The Role has an id which is unique. If I share the roles table there's no problem since the role id is unique, but with different sites/multiple databases and multiple roles tables, could I have different roles with the same role id? and if this is true, could a user having role id = 2 on one site would have that role on a different site even if is another role but that is sharing the same role id?.. That could be a big security issue.

Luis

cog.rusty’s picture

If you also have separate "users_roles" tables, which map the (shared) user IDs to the (non-shared) role IDs, that shouldn't be a problem.

Obviously you should also keep separate all database tables which contain role IDs (from contributed modules etc).

ajayg’s picture

I have a simplified setup that works for me. It has worked for multisite as well seperate drupal installations on different servers

0. Please look at this page above and read the instructions first.

1. In your settings.php I have the shared tables as above but I am sharing only following tables
users, sessions, profile_fields, profile_values.

2. I have turned off registrations on all subdomains. You can register only on one domain I call master subdomain. All links to register point to master domain URL. I use www.domain.com as master domain.

3. I have turned off permission to change passwords on all sundomains. You can change password only on master domain.

4. Make sure you have correctly set your cookie domain to top level domain in all settings.php. That is "domain.com" and NOT "www.domain.com". This will be same in all settings.php

5. Also set the base url correctly for each subdomain in settings.php. So this will be different in each settings.php. Subdomain1 will have base_url=subdomain1.domain.com

6. There is no need to install any contributed module. The key to save sessions from one subdomain to another, is cookie_domain variable.

7. This works in both 5.x and 6.x. In fact I have a muiltisite on one server using 6.x and another server using 5.x all sharing same user database. This gives me flexibility to upgrade each subdomain seperately. I started with all 5.x sites and slowly upgrading as time permits.

8. You don't need to login first from master domain. You can login to any subdomain and the sessions will be carried over. You can logout anywhere and you will be logged out everywhere.

9. Works only if all sites share same top level domain. You can have as many subdomains as you want.

lelizondo’s picture

Your setup looks pretty much to what I have, only one question..

When you say:

I have turned off registrations on all subdomains. You can register only on one domain I call master subdomain. All links to register point to master domain URL. I use www.domain.com as master domain.

is there any reason for that? or is it just some politics from your multisite network?

Luis

ajayg’s picture

I turned off registration from other sites as it would complicate the user experience and confuse them. Each subdomain has a different theme. From user's point they are registering for domain.com and not subdomain.domain.com. This is way there is more uniform user experience since for registering they get forwarded to main site.

rpsu’s picture

So basically sharing users and sessions -tables is all that is needed when I want to have a shared-codebase, separate databases BUT shared users? As pointed out here Drupal 6.x does not use sequences table, which needs to be also shared with Dupal 5.x (node-id's and user id's etc. were previously kept in there, Drupal 6.x is basically asking database "which is next available user id?").

If you have only sub-domains, you can also share session-cookies (cookie_domain variable in settings.php) but with mixed setup:

Or is there a module which would share (throug downloadin an image from example.com or so) logging with all these domains? I think I've read about this kind of module/solution, but just can't find it anymore.

--
Perttu Ehn

ukrdrupal’s picture

I tried the main tutorial on this page, with the sso module. I was very successful, right up until entering the data in the slave/client settings page. Every time, I was getting a page not found, upon submission of the settings page form. The data was getting entered into the DB, but sending me to a page not found, back to the controller site. Not sure why.

I found this tutorial sufficient for my needs: http://www.lullabot.com/articles/drupal-single-sign-across-sub-domains

As long as you are all on the same domain, then it is absolutely no problem. ...I had already done most of the work, based on the main tutorial from this page, so I was able to get the rest done rather quickly.

...I *may* try this sso module again in the future, but would want further clarification on getting it working. And maybe the *symptoms* sound familiar, to the module creator, so that they can assist further.

The main thing I found missing, in all of the comments here and in the tutorial here, which I found on the lullabot site, is this necessary point:

Make sure you include the leading period before the domain.

$cookie_domain = '.example.com';

Could it be that this is what is missing from the main tutorial, to get the sso module working for me? I don't know. I don't want to bother at this point, because the lullabot tutorial works for my present situation. However, if the sso module author wants to investigate more or confirm, that would be helpful.

Overall, folks, this is not a hard process, if you have ANY sincere experience in coding and server based installations.

...More thoughts from others? Maybe the sso module creator can chime in?

espirates’s picture

What did lullabot mean by "Your sites must be on the same hardware cluster to be able to query each other's databases." Wish Drupalers would speak in plain english lol.
Does this mean to have all the databases in one ?

rpsu’s picture

Make sure you include the leading period before the domain.
$cookie_domain = '.example.com';

This was just changed pretty recently. Thats why it is not mentioned before.

--
Perttu Ehn

drvdt’s picture

Above, we understand that: Drupal can connect because the databases have the same database_name and same password and same server.
In your case, your sites on different servers. That means: 2 or 3 databases maybe in 2 or 3 different servers.
How to connect the "drupal_shared_tables" database?
Many thanks

My sites: Medicare

jim_at_miramontes’s picture

A minor note: As the author notes, the user profile information is kept in the tables profile_fields and profile_values. The default Drupal 6 installation does not have the profile module turned on, so those tables won't exist in the default database. If you want shared profiles, turn on the profile module, and the tables will be created.

iori57’s picture

though hard to grasp at first, I managed to follow this guide step by step and got my multisites working :) Thanks!!

The part where I got stuck (hopefully useful to someone in the same situation) are below:

Stuck point 1: Add these lines to your hosts files:
127.0.0.1 site1
127.0.0.1 site2
Resolution: is to point both your site1.com and site2.com to the same folder location, for example if your site1.com points to /document_root/ , don't let cpanel auto insert /document_root/site2.com! Manually change it back to /document_root/ ... big thanks to rjoy for pointing this out in the comments :)

Stuck point 2: Make a copy of /sites/default to /sites/site1 and another to /sites/site2.
Resolution: it is actually /sites/site1.com/ and /sites/site2.com , the '.com' is very important or it won't detect as multisites... no one told me this.. T-T

Stuck point 3: don't have profile_fields and profile_values in my database..
Resolution: Not everyone has these two tables unless you enabled the profiles module.. if you don't have it just leave it out. Thanks to jim_at_miramontes for pointing this out :)

espirates’s picture

I vote for Drupal making this easier, as it stands, setting up multi-site on Drupal is a piece of cake, couldn't be more simpler. Now if there was only a simple way to share content, blocks, without having pull teeth that would be over the top.

spicyguy’s picture

Do we need SSO actually, if we have domains like:

sample.com
a.sample.com
b.sample.com
c.sample.com

Can we just set domain_cookie to be main domain?

Can someone explain?

Also, I don't see profile* tables in Drupal 6. Should I be sharing something else?

rpsu’s picture

We're havign a situation like that and have a setup without using SSO.
www.example.com
secure.example.com
another.example.com

I've also redirected user login and user profile modifications (using .htaccess) from sites to secure site to keep user passwords secured. Now, when user is trying to login from www.example.com he or she will be redirected to secure.example.com. Once logged in user may choose to get back using appropriate menu. So far I've not figured out a module to use or a different way to redirect user back to another site after login like user gets redirected inside one site, using
http://www.example.com/user/login?destination=node%2F111 or so. I guess usign .htaccess rewrite module more efficiently this could be achieved. It seems like Drupal does not support redirecting back to another domain:
http://www.example.com/user/login?destination=http%3A%2F%2Fwww.example.com%2Fnode%2F111 --> does not work as I hope
There is probably a good reason for that...

Anyway, back to the setup without SSO-module. I've setup cookie_domain in settings.php
$cookie_domain = 'example.com';

and also share some tables (user, profiles, sessions, openid). I have every site in different database and one database for shared tables:

$db_prefix = array(
  'default'              => '',
  'authmap'              => 'shared.', //note ending period
  'openid_associations'  => 'shared.',
  'role'                 => 'shared.',
  'sessions'             => 'shared.',
  'users'                => 'shared.',
  'users_roles'          => 'shared.',
  'users_uid_seq'        => 'shared.',  // for pgsql, MySQL does not require this
);

If you're using only one database and using table prefix inside this one database, you may use it this way:

$db_prefix = array(
  'default'              => 'site1_prefix_',
  'authmap'              => 'shared_prefix_', 
  'openid_associations'  => 'shared_prefix_',
  'role'                 => 'shared_prefix_',
  'sessions'             => 'shared_prefix_',
  'users'                => 'shared_prefix_',
  'users_roles'          => 'shared_prefix_',
  'users_uid_seq'        => 'shared_prefix_',  // for pgsql, MySQL does not require this
);

--
Perttu Ehn

k_and_j’s picture

I set up two site multi-site mostly following the instructions here except I did not modify the hosts file with 127.0.0.1, etc... because I am on a shared web-server. Instead, I have a symbolic link from sub.site1.com -> public_html/drupal, so my sites are:

1st site: site1.com/drupal
2nd site: sub.site1.com

Everything worked fine, so I went to install the SSO module. I got all the way through the installation and then got this error when entering the controller url into the client SSO module settings:

The controller URL must be at the root of a domain.

So, I deleted sso from sites/all/modules until I felt like dealing with the trailing "drupal" in the controller url...

NOW, I have done two things:
1) removed the trailing "drupal"
and 2) changed the domain name of the 2nd site from sub.site1.com -> site2.com

To do (1), I modified public_html/.htaccess to:

Options -Indexes
RewriteEngine on
Options +FollowSymLinks
RewriteRule ^$ drupal/index.php [L]
RewriteCond %{DOCUMENT_ROOT}/drupal%{REQUEST_URI} -f
RewriteRule .* drupal/$0 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* drupal/index.php?q=$0 [QSA]

I did not need to modify public_html/drupal/.htaccess, but here it is:

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</IfModule>

Finally, I modified /sites/site1.com/settings.php to have the following:

$base_url = 'http://www.site1.com';

To do (2), I created symbolic links from public_html/site2 -> public_html/drupal and sites/site2.com -> sites/sub.site1.com

At this point, everything works as expected.

Now to install SSO...
I put sso into sites/all/modules. site1.com works fine. site2.com now gives a page not found error and redirects to the following URL:

http://site1.com/singlesignon/associate?origin=http%3A%2F%2Fsite2.com%2F...

(XXX is a unique alphanumeric string)

Note that I haven't done *anything* except extract the sso module - it hasn't been enabled on any site, etc...

I suspect that because I previously went through the entire activation of SSO, something was modified somewhere and it is causing this problem - is this correct? If so, what do I need to do to reverse it?

mikeytown2’s picture

For those of you wondering how this works here's the quick rundown
http://api.drupal.org/api/function/db_prefix_tables/6 is the function where all the action happens

...
    if (array_key_exists('default', $db_prefix)) {
      $tmp = $db_prefix;
      unset($tmp['default']);
      foreach ($tmp as $key => $val) {
        $sql = strtr($sql, array('{'. $key .'}' => $val . $key));
      }
      return strtr($sql, array('{' => $db_prefix['default'], '}' => ''));
    }
...

strtr($string, $replace_pairs_array) (strtr — Translate certain characters) is the magic part of this operation. I'll use a role query as an example.

$db_prefix = array(
    'default' => '',
    'role' => 'drupal_shared_tables.',
);

SELECT * FROM {role} becomes SELECT * FROM drupal_shared_tables.role. This is important because we are using db_name.tbl_name syntax (http://dev.mysql.com/doc/refman/5.1/en/select.html). If you wanted 1 shared database but with different prefixes then you could do something like this

$db_prefix = array(
    'default' => '',
    'role' => 'drupal_shared_tables.prefix_a_',
);
$db_prefix = array(
    'default' => '',
    'role' => 'drupal_shared_tables.prefix_b_',
);

Which would result in SELECT * FROM drupal_shared_tables.prefix_a_role or SELECT * FROM drupal_shared_tables.prefix_b_role
I hope this explanation makes how the dot hack works a little bit clearer.

Jumoke’s picture

*Subscribing to thread*

Jumoke’s picture

I have successfully installed my multisite (subdomains) using the instructions on this page and i just want to say THANK YOU!!!!!!!!!!!!! :)

nirvanesque’s picture

Hi all,

Thank you for all your explanations and ideas! I am in the process of a multi-site installation using Drupal 6.19. Not a total newbie (have used Joomla for the last 6 years since it was Mambo), but now considering moving to Drupal for more flexibility and serious functionalities (one main being multi-site).

My site is structured as:
domain.com - where users login
sub.domain.com - 10 total
I am using a shared-hosting solution in a LAMP environment. Do not have access to php.ini nor can restart apache daemons. Only control is through .htaccess

After reading the how-to and the discussions, I have a few questions as follows:

The author (Greg Harvey) explains that the following tables are to be shared to achieve the desired functionality (subject of this how-to):
authmap
profile_fields
profile_values
role
sessions
users
openid_associations (if using openID)

I do acknowledge the author's remarks that any set of tables can be shared.
My first question is related to some of the tables listed above. If we were to move the last 2 tables into the "drupal_shared_tables" then should we not also move the 2 tables below?
openid_nonce
users_roles
In other words, the question is: Do the above set of tables consist a necessary and sufficient minimal set of tables for using the shared userID functionality?

My second question: Following the explanations of Ajay-Luis-RPSU, is it then confirmed that the SSO module is NOT required to be installed/enabled?

Thanks in advance for your clarifications!
Anirvan

ukrdrupal’s picture

Anirvan, I believe if you read this post of mine, you'll get your multi-site up and running the quickest:

http://drupal.org/node/291373#comment-3417276

The *ideas* are not *mine*. However, some conclusions and the link provided there, I believe will help you most.

You do not need the sso module, if you have everything on the same domain, with sub-domains. I have a similar set-up to yours, right now, with the main domain and 10 sub-domains, all set-up as multi-site. I was able to do this within a short period of time. If you are fairly competent, you should be able to do it in an afternoon.

The only thing I suggest is, make sure you have no distractions! :-) It does take some real concentration.

r2b2’s picture

If for example I have site1.com and site2.com in one server , I can then create a MySQL VIEW of the users table from site1.com's database and store in site2.com's database. In that way, any changes to the users table will be seamlessly 'shared' across these 2 sites.

Thats my theory but i dont know if it will work . I should try it out :D

freq’s picture

Hi, i tried this tutorial on my local machine. It works very well. But now i want to set it up on my webspace. I have a shared hosting package with multiple datebase and each database has a new user and password. Is there a way to handle it?

best regards
freq

lelizondo’s picture

I would recommend you to get a VPS, there are really cheap options like http://burst.net/

Luis

mesas’s picture

If you want to make some test you can contact this company vpswebserver.com (http://www.vpswebserver.com)and ask them to give you trial vps for few days.

radamiel’s picture