What's the best way, assuming there's any way, to have a Drupal multi-site installation work in both dev and production when a site is identified by subdomain? For instance, it's easy to name your site folder "mygreatdomain.org" and have dev.mygreatdomain.org point to the dev server: Subdomains are a convenient workaround. But this is not possible if the sites folder must be named "sub.mygreatdomain.org."

So, is there any way to properly do this? Also, is there a better way, period, to do dev/production environments than using subdomains for dev, and site folders with no subdomain?

Any help would be greatly appreciated, as well as advice on other dev/production environments.

Comments

cog.rusty’s picture

So, you need "sub.mygreatdomain.org" for the production sites?
Why can't you have "devsub.mygreatdomain.org" for the dev sites, with different "sites/" subdirectories for each site's settings.

If the problem is the "files" directory paths, just don't use "/sites/sub.mygreatdomain.org/files" for the files. It is fine to use "files/site-nickname". There is no benefit in putting the uploads directory under sites/real-domain-name/.

markDrupal’s picture

I had a similar problem that required patching the drupal core.

We have dev/prestaging/staging/integration/production servers
we have URLs like
dd.dp.dev.example.com
dd.dp.prestaging.example.com
dd.dp.staging.example.com
dd.dp.integration.example.com
dumbdoctors.com

The site's url is scanned and then, a configuration array is scanned to see what folder in the sites directory to use.

in a file dp.site.config.inc we have the following:

$sc_links['dumbdoctors'] = array(
  'production' => array('slave' => 'dumbdoctors.com dumbdoctors.example.com'),
  'staging' => array('slave' => 'dd.dp.staging.example.com'),
  'integration' => array('default' => 'dd.dp.integration.example.com'),
  'prestaging' => array('default' => 'dd.dp.prestaging.example.com'),
  'dev' => array('default' => 'dd.dp.dev.example.com'),
  'local' => array('default' => 'dd.dp.local.example.com'),
); 

The main key "dumbdoctors" will be used as the directory name in sites, "drupal/sites/dumbdoctors/settings.php". The keys 'production, staging, integration, etc' are to determine which database connection we should establish. Finally the 'default' => 'dd.dp.integration.example.com' says this is a normal database connection and the URL is dd.dp.integration.example.com. This also allows for Master/Slave Database partitioning, e.g. ''slave' => 'dumbdoctors.com dumbdoctors.example.com'' says for those 2 urls 'dumbdoctors.com and dumbdoctors.example.com' we should use master slave setup. We also have to setup a different DB connection based on the URL, so we have an array of DB connections, notice the key 'local' above match with key 'local' below and so on

$sc_dbs['dev']['default']['default'] =  array(
  'driver' => 'mysql',
  'database' => 'Drupal',
  'username' => 'drupal',
  'password' => 'rrrrrrr3334234sdf',
  'host' => 'db-host:3306',
);
$sc_dbs['local']['default']['default'] =  array(
  'driver' => 'mysql',
  'database' => 'Drupal',
  'username' => 'drupal',
  'password' => 'drupal6',
  'host' => 'localhost',
);

Finally I had to make a big patch to drupal's bootstrap process to run my custom code.

function conf_path($require_settings = TRUE, $reset = FALSE) {
  static $conf = '';

  if ($conf && !$reset) {
    return $conf;
  }

  $confdir = 'sites';
  $user_entered_url = preg_replace("/^work-[^.]+\./","",$_SERVER['HTTP_HOST']);
  $user_entered_url = str_replace("www.","",$user_entered_url);
  require($confdir ."/dp.site.config.inc");
  foreach($sc_dbs as $db_type => $db_conf){
    foreach($sc_links as $dir => $link){
      foreach($link[$db_type] as $db_key => $url_host){
        if(strpos($url_host, $user_entered_url) !== FALSE){
          if (file_exists("$confdir/$dir/settings.php") || (!$require_settings && file_exists("$confdir/$dir"))) {
            $conf = "$confdir/$dir";
            //in Drupal 7 we can just assign $db_conf to the global $db_url
            global $db_url;
            global $sc_conf;
            if($db_key == 'slave' && basename($_SERVER['SCRIPT_NAME']) == 'index.php'){
              $key = array_rand($sc_dbs[$db_type]['default']['slave']);//randomly pick a slave
              $db = $sc_dbs[$db_type]['default']['slave'][$key];              
              $dm = $sc_dbs[$db_type]['default']['default'];
              $db_url['master'] = "{$dm['driver']}://{$dm['username']}:{$dm['password']}@{$dm['host']}/{$dm['database']}";
              $sc_conf['db_replication_master'] = FALSE; //special case, this is set in the sites/global.settings.inc
            }
            else{
              $db = $sc_dbs[$db_type]['default']['default'];
              $sc_conf['db_replication_master'] = TRUE; //special case, this is set in the sites/global.settings.inc
            }
            $db_url['default'] = "{$db['driver']}://{$db['username']}:{$db['password']}@{$db['host']}/{$db['database']}";
            
            $sc_conf['securepages_enable'] = ($db_type == 'production' ? TRUE : FALSE); //Enable SSL only on production
            $sc_conf['file_directory_path'] = "/var/drupal/$dir/files";
            return $conf;
          }
          else {
            require_once './includes/database.inc';
            _db_error_page("The dp.site.config.inc file expected to find  the settings file at $confdir/$dir/settings.php, but it wasn't found there.");
            exit();
          }
        }
      }
    }  
  }

  header('HTTP/1.1 404 Not Found');
  echo "404 Site Not Found. The site you are trying to access has not yet been properly installed.";
  exit();
 # $conf = "$confdir/default";
 # return $conf;
}

That code scan the URL and finds the Database to connect to.

There are some custom bits you probably wouldn't need, like the $sc_conf variable that contains settings such as to enable SSL connections only on production
Also $user_entered_url = preg_replace("/^work-[^.]+\./","",$_SERVER['HTTP_HOST']); removes our custom dev URLs for users working in sandboxes, you could remove that.

finally the $db_key == 'slave' bit of code is for our other custom patch to drupal to allow master/slave database partitioning, which requires a separate patch.

I'm also interested in any other configuration changes you may have required. This setup has been working great for us for a while now.