HOWTO: mirror several drupal installs from a single source

Most web server applications are constrained by their design to mix upstream source together with local configuration and possibly local storage all together in the same directory hierarchy. This clearly creates maintenance problems, which each project deals with in its own fashion. Modern web servers are more than sophisticated enough to merge the web visible hierarchy of urls from several different root directories, so the ideal solution to this problem is not to have it in the first place — namely, by keeping upstream and local source well separated on disk. But historical baggage and coding conventions lock us into situations which are less than ideal. It’s the system administrators job to deal with it anyway.

Drupal has developed from a very small php server app which mixed everything into one pot; simple to design — horrible to administer. A modern drupal install is a highly modular and all local information is kept together in a single subdirectory called sites. Built-in logic allows drupal to load a configuration file (and site specific modules and themes) from a subdirectory of ‘sites/’ named after the virtual server’s domain. This allows a single upstream source to serve for many virtual servers. Subdirectory ‘all’ is common to all virtual server’s and ‘default’ for any that fall through unrecognized. The recommended upgrade procedure is to copy out the entire ‘sites’ directory, replace the drupal root with a upgraded instance and copy ‘sites’ back in. Manageable with one caveat. I keep a copy of the entire server tree on an offline machine and rsync it to the server. (‘rsync -rlz –delete drupal-6 root@example.com:/srv/’) If you also mirror more than a single server you are out of luck. I have a development server configuration that I would like to keep separate from the production server mirror but cannot do so without polluting a single shared ‘sites’ directory in ways which may or may not work. In order to be able to use tools of my choice the mirror must be entire and not stitched together by an upload script.

So this is problem. We need several separate ‘sites’ directories that share a parent directory. This is ‘Plan 9’ territory and clearly impossible in a standard Posix set-up. It is however quite easy to set up on Linux using bind mounts.

  • I will install a virgin upstream tarball into '~/Upstream/drupal-6'
  • Copy two 'sites' directories '~/Drupal_Sites/development-sites' and '~/Drupal_Sites/production-sites'
  • Create mount points '/srv/Local_Test_Server/drupal-6' and '/srv/Server_Mirror/drupal-6'
  • Then the bind mount magic as root:
    • sudo mount --bind ~/Upstream/drupal-6 /srv/Local_Test_Server/drupal-6
    • sudo mount --bind ~/Drupal_Sites/development-sites /srv/Local_Test_Server/drupal-6/sites
    • sudo mount --bind ~/Upstream/drupal-6 /srv/Server_Mirror/drupal-6
    • sudo mount --bind ~/Drupal_Sites/production-sites /srv/Server_Mirror/drupal-6/sites

And that’s it. On upgrade, with the bind mounts are already in place, you can empty and pour a tarball directly into ~/Upstream/drupal-6. You can add the bind mounts to your /etc/fstab as such:

(after mounting home and srv)

/home/luser/Upstream/drupal-6                 /srv/Local_Test_Server/drupal-6          none bind
/home/luser/Drupal_Sites/development-sites    /srv/Local_Test_Server/drupal-6/sites    none bind
/home/luser/Upstream/drupal-6                 /srv/Server_Mirror/drupal-6              none bind
/home/luser/Drupal_Sites/production-sites     /srv/Server_Mirror/drupal-6/sites        none bind