a more secure drupal [multisite] install

I love the Drupal CMS. One of my favorite features of Drupal is the ability to do a multisite install. This site and my other blog, i <3 stella, are hosted on the same box, using the same Drupal install. Several sites can share one codebase. Updates are easily rolled out to every site simultaneously. Overall, it's a wonderful idea. But I have some problems with the implementation...

The standard way to set up a multisite install is to point each of the domain names at the Drupal install folder and let Drupal sort out which domain each request is coming from. It does a good job, too. But this method introduces some complications. For example, any content uploaded to site a is accessible from site b. A user that visits http://site1.com/myimage.jpg will find the same image as she finds at http://site2.com/myimage.jpg. Websites can't have domain specific .htaccess or robots.txt files either, which might hurt search engine optimization of individual sites.

An interesting side effect of this is if you want to install something in a subdirectory of your site, for example a WordPress blog at http://site1.com/blog, that exact same WordPress blog will exist in its full glory at http://site2.com/blog...

Another, and perhaps more grave, problem is that all that stands between the interweb and your very own personal settings is an .htaccess file. Install scripts, includes, site configurations and database passwords are in web accessible directories, and that is never a good thing.

We'll look at one solution to these problems.

I assume here that you are using Linux hosting, that you have shell access, and that you have at least a passing acquaintance with symlinks. If you're looking for a webhost that meets these requirements, check out 1and1 shared hosting. I've been happy with them, and all of their packages above $9.99/mo will do what you need.

Microsoft/IIS guys, you can't do a symlink. You're looking for something called a junction... good luck with that.

Directory structure

We'll start by creating a couple of directories. The exact location will depend on your hosting situation. Since we want to restrict access to Drupal, it's best if these directories aren't accessible from the internet. In my case, this means i'll use my home directory. Anything you type will be relative to this base directory.

mkdir drupal
mkdir site1
mkdir site2

You should prob'ly replace "site1" and "site2" with something a little more creative. Like the domain name of the sites or something...

You'll now have three folders in your base directory: drupal, site1 and site2.

Unzip the latest version of Drupal to the drupal directory. Normally, each of the domain names using this Drupal install would point to this directory. We don't want that, however. This folder will not be accessible from the interweb.

We will point site1.com at the site1 folder, and site2.com at the site2. How exactly to do this depends on your server and your webhost. For example, my webhost has a page in their control panel where I can select the destination for each domain name...

Now we will set up drupal for multisite themes and modules.

mkdir drupal/sites/all/modules
mkdir drupal/sites/all/themes

mkdir drupal/sites/site1.com
mkdir drupal/sites/site1.com/files
mkdir drupal/sites/site1.com/modules
mkdir drupal/sites/site1.com/themes

mkdir drupal/sites/site2.com
mkdir drupal/sites/site2.com/files
mkdir drupal/sites/site2.com/modules
mkdir drupal/sites/site2.com/themes

mkdir site1/sites
mkdir site1/sites/site1.com
mkdir site2/sites
mkdir site2/sites/site2.com

Make sure the files directories are writable (Drupal will remind you about this later if you don't do it now):

chmod ug+w drupal/sites/site1.com/files
chmod ug+w drupal/sites/site2.com/files

So far, we've got a standard drupal multisite installation. The difference here is that nobody can access the drupal directory from the internet.

Our directory structure should now look something like this:

Directory structure

Copy some important files to the site directories.

cp drupal/.htaccess site1/
cp drupal/robots.txt site1/
cp drupal/.htaccess site2/
cp drupal/robots.txt site2/

Add a settings.php file to each of the sites directories. If you don't do this, your sites will all use the "default" settings.php, and you'll be all sorts of confused.

cp drupal/sites/default/settings.php drupal/sites/site1.com/
cp drupal/sites/default/settings.php drupal/sites/site2.com/

A little magic

There are a few things in the Drupal install folder that site visitors will need to have access to. Some images and CSS files, mostly. Here's where the symlinks come in. These are special files that act like an alias to other another directory. This allows us to save disk space and upkeep time with a central codebase. But each site thinks it has it's own copy of the code.

We'll create symlinks to the shared resources we want to expose on the web.

ln -s /path/to/drupal/misc/ site1/misc
ln -s /path/to/drupal/modules/ site1/modules
ln -s /path/to/drupal/themes/ site1/themes
ln -s /path/to/drupal/sites/all/ site1/sites/all

ln -s /path/to/drupal/misc/ site2/misc
ln -s /path/to/drupal/modules/ site2/modules
ln -s /path/to/drupal/themes/ site2/themes
ln -s /path/to/drupal/sites/all/ site2/sites/all

Add symlinks to the files directory, so that uploaded content will be accessible as well.

ln -s /path/to/drupal/sites/site1.com/files/ site1/sites/site1.com/files
ln -s /path/to/drupal/sites/site2.com/files/ site2/sites/site2.com/files

If you plan to install site specific themes or modules they need to be linked as well.

ln -s /path/to/drupal/sites/site1.com/modules/ site1/sites/site1.com/modules
ln -s /path/to/drupal/sites/site1.com/themes/ site1/sites/site1.com/themes

ln -s /path/to/drupal/sites/site2.com/modules/ site2/sites/site2.com/modules
ln -s /path/to/drupal/sites/site2.com/themes/ site2/sites/site2.com/themes

Directory structure with symbolic links added

PHP files

Now we need to be able to access Drupal's PHP files from the internet (files like index.php and update.php). Since we want to change the working directory before executing Drupal's PHP files, a simple symlink isn't quite enough. Instead, we will use a PHP file that changes to the Drupal directory then includes the file we care about.

Create a new file in the site1 directory called index.php. Edit the contents of this file:

<?php
	chdir('/path/to/drupal/');
	include('./index.php');
?>

Now create a couple more almost exactly like those ones.

cron.php:

<?php
	chdir('/path/to/drupal/');
	include('./cron.php');
?>

update.php:

<?php
	chdir('/path/to/drupal/');
	include('./update.php');
?>

xmlrpc.php:

<?php
	chdir('/path/to/drupal/');
	include('./xmlrpc.php');
?>

and install.php (delete this one after the first run! you won't need it anymore...):

<?php
	chdir('/path/to/drupal/');
	include('./install.php');
?>

Copy all of these wrapper files to the site2 directory as well.

cp site1/*.php site2/

The final result

Final file structure

You now have the basis for a more secure Drupal multisite install. Now files uploaded to one domain will only be accessible to that domain. Configuration and install files won't be accessible to the bad guys so you can sleep better at night. Third party software installation is a cinch, since a subdirectory in the site1 folder won't show up on site2.com.

This technique is not just for multisite installations. It can be used for a more secure single site Drupal install as well... Just ignore everything about site2 :-).

A few last touches

Set up the site1.com domain to point at the site1 folder, and site2.com to point at site2. If you can't figure out how to do this with your web host company, drop me a line or leave a comment and i'll try to help you out.

When you configure your sites remember to let Drupal know that your file system paths are sites/site2.com/files and sites/site2.com/files respectively.

When you add shared themes and modules, put them in drupal/sites/all/modules and themes. To install site-specific themes and modules, add them to drupal/sites/site1.com/modules or themes...

Now go build your sites! Visit each site in a browser, and the magical Drupal setup process will begin. Isaac Bowman has a pretty good guide for setting up Drupal in about 10 minutes.

Comments

Hi,

I currently use drupal in a multi-site config and definately want to try your suggestion for securing drupal. Just a couple of clarifying questions:

1. Are the top level directories created outside of the public_html directory?
If yes then how do we get users to view site1/index.php?
If no, then how do we make drupal not visible from the web?

2. Is it best to use a vanilla drupal install from drupal.org or can I get cpanel/fantastico script to install?

Thanks In Advance,

JamieT

yes, the top level directory is outside of the public_html folder. this is the best case scenario. if you can't manage this, you might be able to use .htaccess or access control to limit the access to the drupal folder. but you definitely want it somewhere where it isn't web-accessible.

the way you point the domains at your subfolders is webhost specific, so i can't really answer that one. i know in Cpanel, for example, you go to "addon domain maintenance" and direct the domain name to the subfolder (i.e. site1).

i've never tried this with an automated install, since the vanilla install is so slick and easy to use... it should work just fine though. be sure to tell the installer to install drupal to the non-web accessible folder (you might have to move it afterward, if the installer defaults to a web accessible location).

I just stumbled on this thread and frankly I'm more confused than ever. I realize this entire discussion assumes a shared server. I am configuring a multi-site installation where I own the server (FreeBSD), so my current file web accessible directory that contains all of the Drupal file structure is: /usr/local/www/apache22/data

I am assuming your assertions re security of a public_html directory apply equally here, but I'd like to know exactly why this is dangerous given that the .htaccess file contains directives that prevent doing anything bad in the web accessible directory. Why is that not sufficient?

that's a dangerous assumption to make. the .htaccess file prevents doing most bad things... but not everything. it's still best to keep settings, libraries, etc. out of public view.

for example, say you edit your settings.php file from a terminal, using vim or pico. by default the old version is often saved as settings.php~. since this is no longer a .php file, apache and most other web servers will serve it as plain text. and this is a bad thing.

remember when facebook leaked a bunch of source code? any time your server forgets to run things through php first, or any time something sneaks past your .htaccess rules, you've got a security risk.

Hi again,

Everything's working ok but I noticed that the Garland theme doesn't work right as it saves its custom colors file in /drupal/files/color and not in a site specific folder even when the theme files are in the site specific folder. Did I miss something?

jeff

it sounds like your file system path is pointing to /files instead of /files/sitename. check your site settings in admin > settings > file system and make sure it's pointing to your site's files directory.

Ah yes, that was the problem. I had set the file system path back to /files from /files/site1 because I had installed WebFM and wanted the root directory for that to be /files/site1 but that only works if the file system path is /files. So I had to change the WebFM root to: /files/site1/webfm.

Hi,

Well, all is not quite well.

Before I made the changes you outlined the cron job ran fine, and it still works if you access http://example.com/cron.php with an ordinary browser, but if you use lynx or curl or even wget, it won't run the cron script. I had previously been using the cron-lynx.sh script with no problems.

For example, I tried running this from the command line:
/usr/local/bin/lynx http://example.com/cron.php

It started lynx and returned:

FRAME: http://example.com/cron.php
FRAME: /pop-src-page.script
------------------

Any idea why this doesn't work?

Also, accessing site1/cron.php only updates site1 and not all of the sites in spite of the fact that the same central script gets run regardless of which site calls it. How does that work?

Tnx, Jeff

Well, I solved the mystery. It was because I'm using IP based addressing with a domain name alias in ZoneEdit. I'm running several Drupal sites from a common code base and separate databases. I simply changed the lynx script to use the IP address rather than the domain alias "example.com" and it worked.

Here's what I posted in the Drupal forums:

-----------------------------

One point I haven't seen mentioned elsewhere with regards to a multi-site setup: Each site has to run its own cron script. In my case I have a common code base and separate databases for each site. This might not be necessary if the database is shared.

Now for the next question - on a presumably related subject...

I noticed that the browser tab (Firefox in this case) does not show the title tag supplied by Drupal - it shows:

http://example.com rather than "Example | Imagine That!". Actually that's both the title and the site slogan - not sure how that happens.

In fact the address bar only shows http://example.com, and never any appended subdirectories. I used the developer plug-in for FF to look at the source code. There are two available under "frame source", one for http://example.com and one for http://68.107.24.241:8082.

I can't show the code here because your site is apparently not recognizing the code tags, so you can see the rest of this post here:
http://drupal.org/node/216613#comment-714359

Another interesting quirk is that the favicon never makes it and is probably related as well.

I suspect the way around this problem is not to use the alias domain name in the "C" record, but then the address bar will show the IP address which isn't especially desirable. Either way it's ugly, I guess.

This is all because I'm trying to host several websites from one IP address on my Cox cable connection. Cox as well as many other internet providers of course block port 80, otherwise this wouldn't be an issue since you could just use name based resolving in Apache. I'm using trickery to get around this by implementing IP forwarding in ZoneEdit, with the domain alias, and a separate port number for each site. Then Apache sorts it out according to the port numbers and forwards the traffic to each separate Drupal subdirectory, each with its own settings.php, etc.

It's just weird how Drupal uses frames like this and the browser sees the meta tags but possibly not the DOCTYPE. Hmmm, maybe I'll be forced to drop the alias, not that this will ever be anything close to a production site - just fooling around on the cheap to learn Drupal. Then I'll move the whole shooting match to a real server.

Wish there was another way around this... Jeff

I was wondering if you would be willing to share the script you use on your server to host multiple drupal sites that you mention in the above instructions. I am working on setting up ISPconfig and Drupal and and would like to see if I can utilize the script with ISPconfig.

Thank You in Advance.
Marty

honestly, this script was the basis for my writeup, so it's nothing you haven't seen...

#!/bin/sh

if [ $# -lt 1 -o $# -gt 1 -o "$1" = "--help" ]; then
	echo 1>&2 Usage: $0 example.com
	exit 127
fi

# set up the site directory
#	(i have .htaccess, robots.txt, and all the php include files mentioned in
#	http://justinhileman.info/blog/2007/06/a-more-secure-drupal-multisite-install
#	saved in a folder called ~/drupal/base)
cp -r ~/drupal/base ~/public_html/$1

# make the file directory
mkdir ~/drupal/files/$1
chmod ug+w ~/drupal/files/$1

# set up some symlinks
ln -s ~/drupal/themes ~/public_html/$1/themes
ln -s ~/drupal/modules ~/public_html/$1/modules
ln -s ~/drupal/misc ~/public_html/$1/misc
ln -s ~/drupal/sites/all ~/public_html/$1/sites/all
ln -s ~/drupal/files/$1 ~/public_html/$1/files/$1

# make the site file and edit it
mkdir ~/drupal/sites/$1
cp -r ~/drupal/sites/default/* ~/drupal/sites/$1

# append some stuff to the end of the new settings file
echo "\$conf = array('file_directory_path' => 'files/$1', 'file_directory_temp' => 'tmp');" >> ~/drupal/sites/$1/settings.php

# i usually enter the db config by hand in vim. you could easily
# echo the db config to the end of the settings file kinda like above.
vim ~/drupal/sites/$1/settings.php
I have adjusted the script a bit for use with ISPconfig. I placed the base drupal install in var/drupal Still some manual things to do after running the script. The folders inside the "sites" folder have to be rename to their corresponding domain names. Hope you like it so far.

#!/bin/sh

if [ $# -lt 2 -o $# -gt 2 -o "$1" = "--help" ]; then
	echo 1>&2 Usage: $0 webname example.com
	exit 127
fi

# set up the site directory
#	(i have .htaccess, robots.txt, and all the php include files mentioned in
#	http://justinhileman.info/blog/2007/06/a-more-secure-drupal-multisite-install
#	saved in a folder called ~/drupal/base)
cp  /var/drupal/base/* /var/www/$1/web/

# make the file directory
mkdir /var/drupal/files/$1
chmod ug+w /var/drupal/files/$1

# set up some symlinks

ln -s /var/drupal/includes /var/www/$1/web/includes
ln -s /var/drupal/misc /var/www/$1/web/misc

ln -s /var/drupal/modules /var/www/$1/web/modules
ln -s /var/drupal/profiles /var/www/$1/web/profiles

ln -s /var/drupal/themes /var/www/$1/web/themes
ln -s /var/drupal/sites /var/www/$1/web/sites
ln -s /var/drupal/sites/all /var/www/$1/web/sites/all
ln -s /var/drupal/files/$1 /var/www/$1/web/files

# make the site file and edit it
mkdir /var/drupal/sites/$2
cp -r /var/drupal/sites/default/* /var/www/$1/web/sites/$2/

# append some stuff to the end of the new settings file
echo "\$conf = array('file_directory_path' => 'files/$1', 'file_directory_temp' => 'tmp');" >> /var/www/$1/web/sites/$2/settings.php

# i usually enter the db config by hand in vim. you could easily
# echo the db config to the end of the settings file kinda like above.
vim /var/www/$1/web/sites/$2/settings.php

martijn,

thanks for sharing your modified script. i just have a couple of thoughts. first, what did you mean about having to rename the sites folder after the script finishes? i might be able to help tweak the script for that.

second, if you're using the wrapper .php files like i described in my writeup you don't need (nor do you want) symlinks to the following folders:

drupal/sites
drupal/profiles
drupal/includes

The argument to pass to the script is the "webname" for ispconfig. Like web5 or something. This will make the right folders, and copy the files to the "web5" folder. For a Drupal multi site environment, there should be a second argument, the domain name(s??)
That's why you will have to rename the folder /sites/web5 to /sites/somedomain.com

To bad I don't understand shell scripting enough to add this parameter. Maybe you can help me out here??

I will look into the symlinks to drupal/sites, drupal/profiles and drupal/includes. What i remembered is that it resulted in a server error 500 without them, but i will test some more soon.

Thanks for this setup, and delivering the script to the drupal community

rather than post another copy, i adjusted the script you posted above. it will take two arguments instead of one and name the sites subfolder appropriately, so it should work for you now.

What can is say, You are the man!!!!

Thanks, this script works great.

I was not able to install the child sites until I added the install.php file to the redirected files.

install.php

<?php
chdir('/path/to/drupal/');
include('./install.php');
?>

This worked for me but was there another way for me to do this?

you're absolutely right... i completely forgot install.php

now that it's installed, you won't need install.php anymore, so i'd delete that file.

thanks, original post updated :)

Your instructions are clearly written. And I'm a reasonably intelligent person. At least I should be intelligent enough to follow these instructions. So how come I get a messed up configuration? When I go to one of my new sites I get the same site as the root Drupal, except no theming.

Hi Cutter,

I have just performed a multisite Drupal test install using the method Justin Hileman outlines above and have noticed the same themes issue you noticed. I also noticed a similar issue with modules, and that got me thinking about the original install instructions and that's where I noticed the bug.

Where Justin says, under the heading of "A little magic" the following:

We'll create symlinks to the content we want to expose on the web.

ln -s drupal/files/site1 site1/files
ln -s drupal/sites/all site1/sites
ln -s drupal/misc site1
ln -s drupal/modules site1
ln -s drupal/themes site1
If you have installed site specific themes or modules you will need to link to them as well.

mkdir site1/sites/site1
ln -s drupal/sites/site1/modules site1/sites/site1
ln -s drupal/sites/site1/themes site1/sites/site1
Rinse and repeat for site2.

he has made a mistake in the softlink creation statements. If you have a look in the "themes" directory of the sites, you'll notice they are empty. Same with misc and modules. To fix this, you'll need to remove the softlinks - go into each /site/ directory and run the rollowing commands:

rm modules; rm misc; rm themes

and then re-create the links correctly:

ln -s ../drupal/modules modules
ln -s ../drupal/misc misc
ln -s ../drupal/themes themes

After doing this in each /site/ directory, you'll get back the themes, misc and modules that are install-wide which was broken by following Justin's original instructions.

PLEASE NOTE that the reason this may be working for some people (Justin's steps) and broken for others (needing my steps) is most likely because of the configuration of the actual server itself. For example, in all of the php files that we create and copy above, I needed to use:

chdir('../drupal/');

as my path whereas others may well get away with:

chdir('/drupal/');

Anyway, there's muy input and hopefully this will help your themes issue.

I'm going to have a look at site-specific themes and modules a little later today as right now, if I add a theme for one site it is available to all sites, which isn't necessariloy what I want to have happen, especially where customized and/or commercial themes, modules and so on may be used.

Regards,
HiltonT
http://hiltont.blogspot.com/

HiltonT,

thanks for pointing that out. i'm sure that's what cutter was running into. perhaps i was a bit unclear in my explanation... sorry about that.

i ran each of those symlink commands from the parent directory (i.e. the one with 'drupal', 'site1', and 'site2' in it). if you run them from that directory, they should work without '../' at the front.

Hi Justin,

Yeah, that's where I initially ran them from as well, and things didn't go well. Running from in the dir worked. Weird, and totally not what I expected.

What it did (from the partne dir) was to work fine for the "site1" site but not for subsequent ones. Even weirder. I know the syntax was right as all I did was scroll back through the command history and change "sitex" names. :S

Anyway, I'm looking at maybe scripting this whole process and I'll look at those scripts already posted first, and if I come up with anything interesting, I'll post that up here.

Regards,
HiltonT
http://hiltont.blogspot.com/

weird. what's your development environment? are you running this on linux/apache/mysql/php? if so, do you know what linux distro it is?

Hi Justin,

This is a FreeBSD box that we're running it on. So, it is a BAMP box. :)

Aahhh, watching the Harmony module relocation on NASA TV right now! :)

Regards,
HiltonT
\http://hiltont.blogspot.com/

Hi Justin,

I also think that you missed one vital difference between what I did and what you did. I performed the following (from the www root successfully):

ln -s drupal/files/site1 site1/files
ln -s drupal/sites/all site1/sites/all
ln -s drupal/misc site1/misc
ln -s drupal/modules site1/modules
ln -s drupal/themes site1/themes

The difference is that I created the links INSIDE the "site1" and "site2" folders whereas you created the links TO the "site1" and "site2" folders. I also changed the "all" to be inside the "sites" dir, instead of to the "sites" dir.

Basically, I tried to keep the "sitex" directory structure pretty much the same as the original Drupal installation whereas your instructions will result in themes and modules being mixed up into the same place inside the "sitex" directories.

Regards,
HiltonT
http://hiltont.blogspot.com/

actually, we did the exact same thing... i was using a shortened form of the ln syntax:

ln [-fhinsv] source_file target_dir

since the directory (site1, site2) already existed, the command will actually create a symlink with the same name as the source file inside the target directory (site1, site2, etc.)

check out the screenshots of the resulting directory. it should look about the same as yours. unless, of course, i'm completely misunderstanding what you did...

yeah. that's exactly the problem. i just tried creating a symlink on a BSD box, and the BSD ln command doesn't allow the shortcut style syntax... i'll change my writeup to reflect that :)

Can you put the modules and themes on each site separately? Will it still work...? The rest are shared, but the modules ad themes are not.

yep. do it just like drupal suggests: create two directories inside drupal/sites/sitename. one called "themes", the other called "modules". make sure to create symlinks to these folders, otherwise the themes and modules will work, but any assets like css and image files won't show up on your site.

Thanks Justin. You rule. I will try it today and hopefully get it right. I will create a /home/drupalmulti and then do the domains there so I can use one ftp login to upload and edit stuff. It can get complicated with multiple sites especially when it comes to updating modules etc.

Thanks again,

Do you accept Paypal should I screw up? It could be the easiest $100 ever :-)

I have worked my way through the above guide TWICE with no success I cannot get a theme to load at all. After the 1st failure I deleted it all and started fresh and then when it still didn't work I followed HiltonT's directions above, still with no joy, just the same miserable results, text/no theme. So any help would be appreciated, please.

I am with Bluehost and have it set up the following way:
home/xxx/drupal
/sites/
/sites/all/
/sites/default/
/sites/default/settings.php
/sites/site1/
/sites/site1/modules/
/sites/site1/themes/
/sites/site1/settings.php
/sites/site2/ - not worrying about this one yet, trying to get site1 working

home/xxx/public_html/site1
home/xxx/public_html/site1/files 72 Bytes httpd/unix-directory 0755
home/xxx/public_html/site1/files/modcraft 0 Bytes text/x-generic 0000 (symlink)
home/xxx/public_html/site1/sites 104 Bytes httpd/unix-directory 0755
home/xxx/public_html/site1/sites/modcraft 96 Bytes httpd/unix-directory 0755
home/xxx/public_html/site1/sites/modcraft/modules 0 Bytes text/x-generic 0000 (symlink)
home/xxx/public_html/site1/sites/modcraft/themes 0 Bytes text/x-generic 0000 (symlink)
home/xxx/public_html/site1/sites/all 0 Bytes text/x-generic 0000 (symlink)
home/xxx/public_html/site1/.htaccess 4 KB text/x-generic 0644
home/xxx/public_html/site1/cron.php 66 Bytes application/x-httpd-php 0644
home/xxx/public_html/site1/index.php 67 Bytes application/x-httpd-php 0644
home/xxx/public_html/site1/install.php 69 Bytes application/x-httpd-php 0644
home/xxx/public_html/site1/misc 0 Bytes text/x-generic 0000
home/xxx/public_html/site1/modules 0 Bytes text/x-generic 0000
home/xxx/public_html/site1/robots.txt 2 KB text/plain 0644
home/xxx/public_html/site1/themes 0 Bytes text/x-generic 0000
home/xxx/public_html/site1/update.php 68 Bytes application/x-httpd-php 0644
home/xxx/public_html/site1/xmlrpc.php
home/xxx/public_html/site2

I have spent all day on this, driving me nuts so I have tried to be as explicit as possible, any help would be appreciated, thanks.

Failing this I would use the script supplied to set it up, but I am new to ssh, so if directions could be given on how to do it that would be fantastic too.

Thank you :)

Okay, after another day of playing the only way I could get it working was to move the drupal directory from /home to /home/xxx/public_html/drupal.. walla it works.. very annoying I would really rather have it the other way.

Now a problem, site1 is my main account on bluehost, which I have set up in a directory /sub/ with htaccess redirecting it. When I go to site1.com it actually brings up site1.com/sub, I have fiddled with htacess and settings. I was looking at Richard's problem above and tried adding
and files/site1
Order deny,allow
Deny from all

neither were successful I am still gaining access through both site1.com/sub/ and site1.com - to acheive the latter I have to manually drop the /sub/ in the address bar though.

Any ideas please?

NOTE: The article has been revised to resolve the symlink problems mentioned here. Thanks, HiltonT, for pointing it out :)

Well, first I wanted to thank you for providing a more secure option for a multi-site installation.
Everything just worked fine although I'm facing the same problem as mentioned in the previous comment: everything is working, except the page is text only - no theme nor image at all. They are listed though in the administer-section as well as a additional folder containing a theme-to-be-costumized.
I can exclude that it's a installation failure because the same drupal-codebase workes fine for the first domain Iused it for.
Any idea what might cause this problem?

Great article. I have followed the steps and have a couple of questions:

1. From your write-up and reading the questions/answers it appears that there are no files in public_html. All files are to be stored in some other directory (like the /home directory). Is this correct?

2. My sites are hosted with bluehost.com which also uses cPanel. The addon domain procedure you refer allows me to add any domain except my original domain. This makes sense since it already exists. Currently my original domain (linguaetc.com) is pointing to public_html. Have you found a way to point your main domain to site1?

Yours truly,
Richard

did you try using a redirect?

Thank you Tom for the great suggestion. Unfortunately, on the Bluehost.com redirect page they state "You cannot use a Wild Card Redirect to redirect your main domain to a different directory on your site." Accordingly, I left the main site in public_html as suggested above by Justin.

1. that's right. we don't want drupal to be publicly accessible. in my case, that means something like this:

home/
  drupal
    ...
  site1
  site2
  site3

2. i'm not sure (i don't usually use cPanel) but you don't need to actually call the file site1. you can use your public_html directory anywhere you see "site1" in my writeup and it should work just fine:

home/
  drupal
    ...
  public_html
  site2
  site3

Thank you very much Justin. I now have two working websites setup very close to your suggested setup. I have only two further questions:

1. You state to tell drupal that the files are in files\rdhamilton. However, when I do this in the Site configuration screen it creates a new folder called files\rdhamilton under drupal. How do I get the program to know that my files are stored in a subdirectory of files called rdhamilton?

2. I have themes working on both websites. However, I cannot change the themes through Site building - Themes. The only way I can change it is in the settings.php file. Any suggestions?

The following are a few observations that I would like to share for anyone else using this setup (I also welcome comments and suggestions):

1. Per your suggestion I used public_html as site1. I had thought we wanted everything out of public_html this is why I was trying to find an alternative.

2. Bluehost.com insists on pointing the add-on domains to public_html. Therefore, I created a symlink pointing rdhamilton in public_html to rdhamilton (aka site2) under the /home directory.

3. I created new databases and ran install.php for each website. I thought I would try to use the existing databases but it kept throwing errors. If someone has done this with existing databases maybe they can share how they did it for others.

Thank you again.

1. try telling it the directory is files/rdhamilton (forward slash instead of back). let me know if that works.

2. i know if you set it in settings.php you can't change it through the drupal admin panel. if you remove the line in settings.php, does it let you change it via drupal?

You are good...

1. Drupal accepted the files/rdhamilton without any errors or creating a new directory.

a. But when I try to access the file through http://www.rdhamilton.com/drupal/files/ it gives me a 404 error. I even tried to include a file in the directory and access it with http://www.rdhamilton.com/drupal/files/actualfile I have the temporary directory set to /tmp and download to public.

b. For security, do you set the download to private?

2. Removing the line in settings.php allowed me to change it via drupal. Thank You!

the files should actually be at

http://rdhamilton.com/files/rdhamilton/actualfile

and i don't use private download, personally.

so your directory setup looks something like:

drupal
public_html
  ... all the basic multisite files
  rdhamilton -> link to rdhamilton
rdhamilton
  ... all the basic multisite files

and domain 1 points to public_html, domain 2 points to public_html/rdhamilton, right?

if this is the case, you'll get weirdness if anyone ever goes to site1.com/rdhamilton ... it will still be site 1's content, since drupal decides what content to serve based on the domain you ask for. but it will essentially give you two different paths to every page in your main drupal site. try it. site1.com/rdhamilton should look identical to site1.com.

if this is the case, you're going to want to block /rdhamilton for traffic coming to site1. that'll make sure none of the weirdness ever surfaces. add the following to your site1 .htaccess file

<FilesMatch "^rdhamilton">
  Order deny,allow
  Deny from all
</FilesMatch>

You are absolutely correct in my setup. You are also correct, when I go to linguaetc.com/rdhamilton I see the linguaetc.com content.

I have added the lines in the linguaetc.com .htaccess file (located in /public_html). I tried adding them below and then above the existing FilesMatch lines:

FilesMatch "(\.(engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)|code-style\.pl|Entries.*|Repository|Root|Tag|Template)$">
Order allow,deny
/FilesMatch

Now when I type linguaetc.com/rdhamilton I get a 403 error...Actually this turned off all access to rdhamilton.com With the suggested FilesMatch lines I receive a 403 error message when I try to access any of the rdhamilton.com website.

Any ideas?

Great job! I really appreciate the time you took placing the pics and images. I found your post off of your comment on my older article Installing a multi-site system on Drupal in less than 10 minutes. I would like to use Drupal as my own personal DM (document management) Sys the same way some people use Gmail to store and search for notes.

thanks :)

i actually have a local drupal installation that i use for document management, personal wiki, etc. it's working out great for me.

Hi, thank you so much for sharing this tip. Though I'm a relative newbie, I can see that this is a better way to do a multisite installation...except that I run into the same problem that a couple of folks here have mentioned in the comments (for which I didn't see any reply... :)
- that is, I get an installation page (and all subsequent pages) without any theming at all! I tried making additional symlinks (just in case) for the 'script's and 'profiles' folders, too...but no luck. Would really appreciate some help - if you can think of a reason why there's no theming...Thanks.

the scripts and profiles folders shouldn't have symlinks. those include only back end code...

if you run into unthemed pages, whether in installation or in your actual site, you've most likely got a missing or malformed symlink.

the good news is that your site will work just fine without the symlinks. it'll just be ugly. the bad news is that sometimes symlink issues are a bit of a pain to track down.

here's how i usually do it:

  1. view source on the page that's missing styling
  2. find the css includes, and open up each css file in a new tab/window
  3. if none of them load, start over with the symlinks (basically redo everything under the heading "a little magic" above)
  4. if some of them load, look for a common theme: are the broken ones under "sites/all"? am i mostly missing module or theme css files? this usually tells me which symlink needs to be fixed

Hi Justin,

Great tutorial! You got my multi-site started up and it seems to be working but this same problem of no theming at all (installation nor homepage).

I've double checked and have redone the symlinks but still not working. And the only clue is that E.g. drupal/themes/garland/logo.png shows but not site1/themes/garland/logo.png Can you advise? Thanks in advance!

that is almost always a symlink problem... does your ssh program use color? if so, a broken symlink will be red, possibly blinking. if not, you can try navigating through a symlink on the command line:

cd site1
cd themes
cd garland
ls

if you make it to the directory, and actually see something, then you're doing alright... otherwise, you need to redo your symlinks.