No-fuss Drupal multi-site deployment with symlinks

When creating a Drupal site for clients, many people use a temporary hostname for development purposes. What's more, that hostname is not generally on the same domain as the production site. I'm sure I'm not the only one to use client,mydomain.com to develop the www.client.com site.

[[wysiwyg_imageupload:21:]]

When you — like me — use Drupal in a multisite setup, where the same codebase is shared between many sites, you'll have per-site settings, files and images. These are located in a directory structure that's based on the hostname you're accessing the site under. Eg: the files and settings for client.mydomain.com live in the sites/client.mydomain.com/ directory.

However, when the time comes to deploy the site to its production hostname, those settings and files need to live somewhere else. Moving them can result in link and image breakage on the front-end, which is never a good look and means you might need to painstakingly update links and images on all your pages.

There is a simple way to avoid all that hassle by using a UNIX filesystem feature that's been around since the dawn of time: symbolic links. These are files that point at another file or directory, elsewhere on the system and — unlike Windows shortcuts — all applications will magically access whatever file or directory the symbolic link points at when trying to access the link.

By creating a settings directory named for the production site and creating a symlink to it, named for the development site, you can have Drupal use both, which can make life nice and easy down the line.

In my example, when first installing Drupal, you create a client.com directory for the settings files and copy the default settings into it. I don't use the default directory that comes with Drupal, so I always have a pristine copy of the default settings in there — much in the way that /etc/skel works on Linux.

# cd /path/to/drupal/
# cd sites 
# cp -a default client.com
# cd client.com 
# mv default.settings.php settings.php
# chmod 666 settings.php
# mkdir files
# chmod 777 files

And we can quickly check that the settings.php file and files directory exist with the correct permissions to let us install Drupal.

# ls -l
drwxrwxrwx 2 root www 4096 2010-07-31 12:25 files
-rw-rw-rw- 1 root www 9485 2009-09-14 22:59 settings.php

Excellent. Now for the symbolic link.

# cd ..
# ln -s client.com client.mydomain.com

And another check to see that we created the link correctly.

# ls -l
drwxrwxr-x 3 root www 4096 2010-07-30 13:50 all
drwxrwxr-x 3 root www 4096 2010-07-31 12:25 client.com
lrwxrwxrwx 1 root root   10 2010-07-31 12:27 client.mydomain.com -> client.com
drwxrwxr-x 3 root www 4096 2010-07-30 13:50 default

The l at the start of the line with "client.mydomain.com" on it indicates this is a link. The shell also shows what directory the link points at. You can now install Drupal normally by visiting http://client.mydomain.com/

When doing its bootstrap, Drupal will loads its settings from sites/client.mydomain.com/settings.php. Because  that directory is a symbolic link, it will load the same settings file when it bootstraps sites/client.com/settings.php.

There's one thing left to do now. Because we installed Drupal via client.mydomain.com, it will default to using the sites/client.mydomain.com/files directory to store uploads like images and attachments. To avoid this, you can set a different file system path.

Browse to Administration » Site configuration » File system and replace the file system path with the path that you will want to use on the production site, then click Save configuration.

[[wysiwyg_imageupload:25:]]

Because of the symbolic link, the files live in the same location on the disk, but Drupal will now use the name of the production site to create links. That means you no longer need to change them when you roll out the site on a new URL.

Unavoidable Caveats

Of course, there are caveats, what would life be without them. If you put themes any modules into a site-specific directory, Drupal will use the site-specific directory path to access them. In the example I used that means if you remove the symbolic link client.mydomain.com, Drupal may suddenly be unable to load modules or themes from sites/client.mydomain.com/modules and sites/client.mydomain.com/themes.

You fix this by logging in as Administrator and visiting the modules list page and the themes list page. Doing this will make Drupal re-scan all available directories for the module and theme files it needs to load.

If there are still files missing after that, you may need to update the system table in the database to manually update paths. Precisely how to go about doing that is material for a future blog.

Comments

Does CPanel allow you to execute shell commands via a web form? If so, you could use the 'ln -s' command to create the links.

This is a a great tip for development and makes perfect sense. It seems so obvious but yet I went through the process of updating image links on a site tonight after moving it to production because I didn't think about this tip. What would be nice to see is a module or addition to the Drupal core that automatically pulled requests from the correct location. There is no reason a request for a file located in sites/mydomain.com/files can't be requested from mydomain.com/files just by basing the mapping on the domain name. e.g. map mydomain.com/sites/mydomain.com/files to /files. Of course this would need to handle subdomains as in your example.

Commenting on an older post, but this might be helpful. I've had issues with symlinks because some things write the paths into the database and having both caused problems.

In Drupal 7, you can use the sites/sites.php file to specify "alternate" sites/ directories to use for a particular domain. For example, if you are on example.local, but you want to use /sites/example.com you specify $sites['example.local'] = 'example.com'.

In Drupal 6, you can do the same thing with a small core patch: http://drupal.org/node/231298

It's the only patch I put on core so far and I use it on my local and dev servers.

Add new comment