While the amount of documentation and support surrounding Drupal as a whole is fabulous, there's a surprising dearth of information regarding management paradigms. Lots of people talk about small parts of the puzzle, like using SVN and vendor branching to track custom changes to modules, but there's not a lot of talk about how to efficiently manage large numbers of Drupal sites. So I figured I would share the architecture that I came up with, in the hopes that it'll help other maintainers as well!
My needs
I manage a dedicated server with a number of Drupal installations on it for various individuals and organizations. The sites are generally either "research" sites or "personal" sites (each type has a different set of modules and configurations). My goals are primarily to:- Conserve server resources (i.e. disk space)
- Keep the server secure (a real toughie when dealing with PHP)
- Minimize administrative overhead
Drupal's native multi-site handling
This certainly handles goal (1) well, but fails at pretty much everything else. Security becomes a nightmare, as does anything beyond basic maintenance. I don't think I need to elaborate on this point. :)Aegir
Let me just say that Aegir looks absolutely fabulous, and I can't wait to see it mature, but it still fails on point (2), and to some extent (3) as well. As mentioned in this Aegir group post, there's really no way to set permissions such that Aegir is free to do its thing and their aren't gaping security holes (assuming clients have read/write access to their own files). Additionally, I'd like for all of the clients' files to reside in their home directories, to simplify backups and quota management. There's just no way to do this and use Aegir.Drush
Drush is another fabulously useful tool that satisfies points (2) and (3), but doesn't deal well with "non-vanilla" setups, such as multiple sites sharing a single module repository. However, I found a way to bend it to my will...The solution: Proto-sites
Let's say I have four Drupal installs on my server:/home/client1/research-site
/home/client2/research-site
/home/client3/personal-site
/home/client4/personal-site
What I did was simply create two new Drupal installs called "Personal proto-site" and "Research proto-site":
/var/www/drupal/research
/var/www/drupal/personal
I then symlinked the sites/all
directory of each client site to it's respective proto-site, i.e.
/home/client1/research-site/sites/all -> /var/www/drupal/research/sites/all
Now, to update modules for ALL of the research sites at once, I simply cd into the research proto-site directory and run
sudo drush up
I then run a simple shell script* that runs drush updatedb
on each client site. And voila - you have no wasted space from duplicated modules, good security (inasmuch as PHP allows), and minimum administrative overhead - just two commands to run per proto-site (which could easily be combined into one with a shell script).
What's awesome about this setup is that it's quite extensible. For instance, if a client wants to override the shared version of the module, they can just put their own version in their sites/danepowell.com/modules
. You can also use the proto-site to develop and distribute Features. Finally, you can also share copies of Drupal core, e.g.
ls -al /home/client1/research-site
/home/client1/research-site/cron.php -> /var/www/drupal/research/cron.php
/home/client1/research-site/includes -> /var/www/drupal/research/includes
etc...
I'm really digging this new architecture and how much time it saves me. The only other tough nut that I need to crack is how to maintain stock modules alongside custom/patched ones. I want to use the drush scripts to quickly update stock modules en masse, but I need to use SVN and vendor branching to update the patched ones. Unfortunately, there's no way to discriminate between the two when they're all sitting in the same directory on a proto-site... Update: problem solved - see my post on updating side-by-side stock and hacked modules
I'd love to hear how you manage multiple Drupal sites, and any suggestions on improving this workflow - please leave a comment below!
* drush-update-all
#!/usr/bin/env bash
installpath[1]=/var/www/drupal/research
installpath[2]=/var/www/drupal/personal
installpath[3]=/home/client1/research
installpath[4]=/home/client2/research
installpath[5]=/home/client3/personal
installpath[6]=/home/client4/personal
for index in 1 2 3 4 5 6
do
filepath=${installpath[index]}
printf "Updating %s\n" "$filepath"
cd $filepath
drush updatedb
drush pm-refresh
done
Comments