The Power of Drupal Multisite - Part 1: Code Management

Drupal has a fantastically useful feature called Multisite - it allows you to serve many sites from a single Drupal codebase. This can greatly reduce the overhead of managing code across multiple sites, and enables great agility in launching new sites quickly.

In this article, I'll go into the detail of multi-site and try to demonstrate how it could be useful for your organisation, and in a follow up post, I'll talk about the infrastructure considerations you'll need to make when planning to deploy your multisite installation.

Overview

With multi-site, you only need to maintain one copy of Drupal core and your contributed modules (except for some special cases which I'll go into later). Each site shares the same code, but has a different database. This means that content, configuration, and appearance can be vastly different, but the code can be consistent, and managed centrally.

A great example of multi-site in action is Acquia's Site Factory implementation for Warner Music Group. Implementing multi-site in Drupal 7, paramore.net, davidbowie.com, and www.bieberfever.com are all served from a single codebase. Three very different artists, with different editorial and creative teams - but one centrally managed, centrally updated and centrally maintained codebase.

Read about how Site Factory works here.

Multi-site can greatly reduce the management burden of maintaining code for a range of sites.

Throughout this article, there's lots of links to documentation on drupal.org and acquia.com. Click through whenever you need more detail - and tell me about your experiences with multi-site in the comments.

So how does it work?

Each site’s configuration lives in its own subdirectory in the Drupal sites folder. Each directory contains a custom settings.php with database connectivity parameters.

Drupal analyses the domain in an incoming HTTP request, and searches for a matching site-specific directory. If one is found, the settings.php in that directory is loaded.

You're probably familiar with the /sites/all and /sites/default directories. There's a reason they're named that way:

/sites/default

is the default site that is served if no mapping is specified.

/sites/all

is a shared directory that all sites will have access to.

/sites/[sitename]

is the configuration for your custom site.

We could make a directory at /sites/example.com/, and any request to our webserver for example.com will check in that directory first to see if there is a settings.php. If one is found, it is loaded, the specified database is connected to. Any files saved by Drupal (like uploads and aggregated CSS and JS) will be saved in /sites/example.com/files instead of the default /sites/default/files.

Thats it! This is all you need to do to get multi-site set up - and there's no limit to the number of sites you can add in this way. But there is a lot more that you can do with multi-site if you dig a little deeper.

Site-specific modules and themes

Each site in a multi-site install contains at least a settings.php and a /files directory. But each multi-site directory can contain modules and themes too - and any modules or themes in those directories will only be available to that site.

For example, imagine I have two sites, example.com and example2.com:

  • /sites/all/modules/contrib contains all of the community contributed modules that I want both sites to share. For example, Views might live there.
  • /sites/all/modules/custom contains all of my custom modules, written specifically for my Drupal installation.
  • /sites/example2.com/themes contains any themes you want to only be available on example2.com.
  • /sites/example2.com/modules contains any modules you want to only be available on example2.com.

When Drupal looks for available themes and modules, it searches in the following order:

/modules/ /profiles/ /sites/all/ /sites/[sitename]/

So, when I write my custom theme for example2.com, I can put it into the example2.com multi-site directory:

/sites/example2.com/themes/chicken

And the "Chicken" theme will only be available to users of example2.com. Users of example2.com will still have access to all of the themes in /sites/all and /themes, but example.com won't be able to see the "Chicken" theme at all.

Local overrides

Drupal only “sees” the most specific version of a module. That means that if you need to override a module just for a single site, you can install it in that site’s directory.

For example, let’s say that you are upgrading Views to 7.x-3.7. In your testing, all of your sites work perfectly except for example.com, which relies on something in Views 7.x-3.5.

cat /sites/example.com/modules/contrib/views/views.info | grep ^version 7.x-3.5 
cat /sites/all/modules/contrib/views/views.info | grep ^version 7.x-3.7

So, example.com gets Views 7.x-3.5, and every other site gets Views 7.x-3.7. This applies to themes too.

Specifying domain mappings with sites.php

Drupal 7 introduced a file, sites.php, that allows you to specify domain to site mappings.

Deploying a new site with multi-site can be a very simple process as we've seen - all we need to do is add a directory. That's great for when we go live - but what about during development and testing? They don't use the live domain - but we need to test before we go live. Enter sites.php.

With sites.php, you specify a domain, port, directory, or combination of those three, and map it to a directory in the /sites directory. Eg:

<?php
// An array with domains as keys and directories as values.
$sites = array(
    'example.com' => 'example.com',
    'example.com.localhost' => 'example.com',
    'example.com.dev.mytestingdomain.com' => 'example.com',
    'example.com.stage.mytestingdomain.com' => 'example.com',
);
?>

This gives you a lot of flexibility and control over which domains or directories map to which sites.

Install Profiles

A good approach when beginning a project based on multi-site is to create your own custom Drupal install profile. An install profile sets up Drupal with the modules and configurations you prefer when you install Drupal.

Drupal distributions often have their own install profile. When you download Commons 3, the download contains a copy of Drupal 7, and a collection of modules and Features. When you install Commons, these modules and Features are enabled, and (optionally), sample content is installed.

Creating an install profile means that when you roll out new sites on your multi-site platform, you don’t need to configure them from scratch - you only need to change things specific to that site.

You can even install common modules and themes in your install profile’s directory - leaving your /sites folder free for only site-specific modules. This is the approach that Commons, Drupal Commerce, and almost every other Drupal distribution takes.

Incorporating Features module

Features module allows you to package Drupal configuration as code. You then save those configurations in your module directory, and they can be imported simply by enabling their module.

Now think about incorporating that with Install Profiles and Local Overrides.

I setup a new content type - Acquia Blogposts - and export it to a Feature module called acquia_blogpost. I put it into /sites/default/features/acquia_blogpost. In our install profile, I add this to the list of modules I want to install. Now, every time I install a new site, I can guarantee that the acquia_blogpost content type is setup just the way I like it.

But now I want to add a new field for a picture of my cat. but only on example2.com. No problem - I make the changes, export the new feature to a module, put it into /sites/example2.com/features/acquia_blogpost, and I'm done.

My install profile will pick up the new field only on example2.com - but all other sites will continue to have the default.

This is very powerful!

Consolidated Codebase Management

In cases where sites are broadly similar in functionality, multi-site can greatly simplify the effort of managing code.

Acquia has a client that runs 300 sites in multi-site - if each had a separate codebase, that would be 300 codebases to manage. With multi-site, each site's codebase only need contain the delta of the base code and per-site customisations.

Speed of deployment

Deploying a new site in a multi-site installation is very simple. Just create a new database, specify your DB connection parameters in settings.php, deploy your code, and install. Compare this to forking a new copy of a codebase - there's a lot more code to manage, check, and test.

Code divergence

If sites begin to become very functionally different, then managing one codebase for those sites can become onerous. At that point, its probably better to fork your codebase and develop those sites independently.

For example, your site may have a great community of registered users who want to interact and collaborate. If you don't want them doing this on your main site, then maybe starting a new community with Drupal Commons is a good option. While you could run your .com site and a community like Commons from the same codebase, its probably best to create a new docroot and migrate your users across.

So...multi-site or multiple codebases?

While it would be nice if there was one answer to that question, there isn't. What's important is to choose the right solution for your use case. Multi-site is a mature, proven site architecture - and we are happy to support it. But sometimes, its not the right fit. There's no silver bullet - but leveraging the lessons learned by the huge, experienced, successful Drupal community can help you to avoid getting bitten.

Whatever you choose, Acquia can support it. Feel free to get in touch if you're trying to decide what is the best path for you - we're always happy to help.

The second article in this series is now available: The Power of Drupal Multi-site Part 2: Hosting Infrastructure