diff --git a/core/INSTALL.txt b/core/INSTALL.txt
index b753f3a..9302945 100644
--- a/core/INSTALL.txt
+++ b/core/INSTALL.txt
@@ -150,12 +150,12 @@ INSTALLATION
       which is normally in the directory sites/default (to avoid problems when
       upgrading, Drupal is not packaged with this file). If auto-creation fails,
       you will need to create this file yourself, using the file
-      sites/default/default.settings.php as a template.
+      core/default.settings.php as a template.
 
       For example, on a Unix/Linux command line, you can make a copy of the
       default.settings.php file with the command:
 
-        cp sites/default/default.settings.php sites/default/settings.php
+        cp core/default.settings.php sites/default/settings.php
 
       Next, grant write privileges to the file to everyone (including the web
       server) with the command:
diff --git a/core/UPGRADE.txt b/core/UPGRADE.txt
index f035b6c..57021fb 100644
--- a/core/UPGRADE.txt
+++ b/core/UPGRADE.txt
@@ -163,10 +163,6 @@ following the instructions in the INTRODUCTION section at the top of this file:
    no longer need their data, then you can uninstall them under the Uninstall
    tab after disabling them.
 
-8. On the command line or in your FTP client, remove the file
-
-     sites/default/default.settings.php
-
 9. Remove all old core files and directories, except for the 'sites' directory
    and any custom files you added elsewhere.
 
diff --git a/sites/default/default.settings.php b/core/default.settings.php
similarity index 91%
rename from sites/default/default.settings.php
rename to core/default.settings.php
index 5a46b12..ab603d0 100644
--- a/sites/default/default.settings.php
+++ b/core/default.settings.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Drupal site-specific configuration file.
+ * Drupal global configuration file.
  *
  * IMPORTANT NOTE:
  * This file may have been set to read-only by the Drupal installation program.
@@ -11,10 +11,8 @@
  * security risk.
  *
  * The configuration file to be loaded is based upon the rules below. However
- * if the multisite aliasing file named sites/sites.php is present, it will be
- * loaded, and the aliases in the array $sites will override the default
- * directory rules below. See sites/example.sites.php for more information about
- * aliases.
+ * if the multisite aliasing is enabled, the aliases in the $sites array will
+ * override the default directory rules below.
  *
  * The configuration directory will be discovered by stripping the website's
  * hostname from left to right and pathname from right to left. The first
@@ -47,10 +45,61 @@
  * hostname with that number. For example,
  * http://www.drupal.org:8080/mysite/test/ could be loaded from
  * sites/8080.www.drupal.org.mysite.test/.
+ */
+
+/**
+ * Multi-site functionality and aliases.
+ *
+ * Uncomment the $sites variable below to enable Drupal's multi-site
+ * functionality, which allows to serve multiple different sites from the same
+ * code-base.
+ *
+ * An empty $sites variable just enables the sites directory discovery process.
+ * You can additionally define aliases that map hostnames, ports, and path names
+ * to specific site directories. These aliases are applied prior to scanning for
+ * directories and exempt from the discovery rules.
+ *
+ * Aliases are useful on development servers, where the domain name may not be
+ * the same as the domain of the live server. Since Drupal stores file paths in
+ * the database (files, system table, etc.) this will ensure the paths are
+ * correct when the site is deployed to a live server.
+ *
+ * Aliases are defined in an associative array named $sites. The array is
+ * written in the format: '<port>.<domain>.<path>' => 'directory'. As an
+ * example, to map http://www.drupal.org:8080/mysite/test to the configuration
+ * directory sites/example.com, the array should be defined as:
+ * @code
+ * $sites = array(
+ *   '8080.www.drupal.org.mysite.test' => 'example.com',
+ * );
+ * @endcode
+ * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or
+ * an Apache Alias directive that points to the Drupal root containing
+ * index.php. An alias could also be created for a subdomain. See the
+ * @link http://drupal.org/documentation/install online Drupal installation guide @endlink
+ * for more information on setting up domains, subdomains, and subdirectories.
+ *
+ * The following examples look for a site configuration in sites/example.com:
+ * @code
+ * URL: http://dev.drupal.org
+ * $sites['dev.drupal.org'] = 'example.com';
+ *
+ * URL: http://localhost/example
+ * $sites['localhost.example'] = 'example.com';
+ *
+ * URL: http://localhost:8080/example
+ * $sites['8080.localhost.example'] = 'example.com';
+ *
+ * URL: http://www.drupal.org:8080/mysite/test/
+ * $sites['8080.www.drupal.org.mysite.test'] = 'example.com';
+ * @endcode
  *
- * @see example.sites.php
- * @see conf_path()
+ * @see default.settings.php
+ * @see \Drupal\Core\Utility\Site::getPath()
+ * @see http://drupal.org/documentation/install/multi-site
  */
+# $sites = array();
+# $sites['localhost.example'] = 'example.com';
 
 /**
  * Database settings:
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 51f4446..f7de151 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -12,6 +12,7 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Utility\Title;
 use Drupal\Core\Utility\Error;
+use Drupal\Core\Utility\Site;
 use Symfony\Component\ClassLoader\ApcClassLoader;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Container;
@@ -247,160 +248,6 @@ function timer_stop($name) {
 }
 
 /**
- * Returns the appropriate configuration directory.
- *
- * Returns the configuration path based on the site's hostname, port, and
- * pathname. Uses find_conf_path() to find the current configuration directory.
- * See default.settings.php for examples on how the URL is converted to a
- * directory.
- *
- * @param bool $require_settings
- *   Only configuration directories with an existing settings.php file
- *   will be recognized. Defaults to TRUE. During initial installation,
- *   this is set to FALSE so that Drupal can detect a matching directory,
- *   then create a new settings.php file in it.
- * @param bool $reset
- *   Force a full search for matching directories even if one had been
- *   found previously. Defaults to FALSE.
- *
- * @return
- *   The path of the matching directory.
- *
- * @see default.settings.php
- */
-function conf_path($require_settings = TRUE, $reset = FALSE) {
-  $conf_path = &drupal_static(__FUNCTION__, '');
-
-  if ($conf_path && !$reset) {
-    return $conf_path;
-  }
-
-  // Check for a simpletest override.
-  if ($simpletest_conf_path = _drupal_simpletest_conf_path()) {
-    $conf_path = $simpletest_conf_path;
-    return $conf_path;
-  }
-
-  // Otherwise, use the normal $conf_path.
-  $script_name = $_SERVER['SCRIPT_NAME'];
-  if (!$script_name) {
-    $script_name = $_SERVER['SCRIPT_FILENAME'];
-  }
-  $http_host = $_SERVER['HTTP_HOST'];
-  $conf_path = find_conf_path($http_host, $script_name, $require_settings);
-  return $conf_path;
-}
-
-/**
- * Determines whether to use an overridden value for conf_path().
- *
- * Simpletest may provide a secondary, test-specific settings.php file to load
- * after the primary one used by the parent site and override its variables.
- * - If the child settings.php does not override $conf_path, then this function
- * returns FALSE and conf_path() returns the directory of the primary
- * settings.php.
- * - If the child settings.php does override $conf_path, then
- * _drupal_load_test_overrides() sets the 'simpletest_conf_path' setting, and
- * this function returns that to conf_path(), causing installations and
- * upgrades to act on that one.
- *
- * @return string|false
- *   The overridden $conf_path, or FALSE if the $conf_path should not currently
- *   be overridden.
- *
- * @see conf_path()
- * @see _drupal_load_test_overrides()
- */
-function _drupal_simpletest_conf_path() {
-  // Ensure that the settings object is available. conf_path() is called once
-  // before the Settings class is included, and at that point it should still
-  // load the primary $conf_path. See drupal_settings_initialize().
-  if (!class_exists('Drupal\Component\Utility\Settings', FALSE)) {
-    return FALSE;
-  }
-
-  // If no $simpletest_conf_path is set, use the normal $conf_path.
-  if (!($simpletest_conf_path = settings()->get('simpletest_conf_path'))) {
-    return FALSE;
-  }
-
-  // Ensure that this is actually a simpletest request. We can't check this
-  // before settings.php is loaded.
-  if (!drupal_valid_test_ua()) {
-    return FALSE;
-  }
-
-  // When the $simpletest_conf_path is set in a valid test request,
-  // return that path.
-  return $simpletest_conf_path;
-}
-
-/**
- * Finds the appropriate configuration directory for a given host and path.
- *
- * Finds a matching configuration directory file by stripping the website's
- * hostname from left to right and pathname from right to left. By default,
- * the directory must contain a 'settings.php' file for it to match. If the
- * parameter $require_settings is set to FALSE, then a directory without a
- * 'settings.php' file will match as well. The first configuration
- * file found will be used and the remaining ones will be ignored. If no
- * configuration file is found, returns a default value '$confdir/default'. See
- * default.settings.php for examples on how the URL is converted to a directory.
- *
- * If a file named sites.php is present in the $confdir, it will be loaded
- * prior to scanning for directories. That file can define aliases in an
- * associative array named $sites. The array is written in the format
- * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
- * directory alias for http://www.drupal.org:8080/mysite/test whose configuration
- * file is in sites/example.com, the array should be defined as:
- * @code
- * $sites = array(
- *   '8080.www.drupal.org.mysite.test' => 'example.com',
- * );
- * @endcode
- *
- * @param $http_host
- *   The hostname and optional port number, e.g. "www.example.com" or
- *   "www.example.com:8080".
- * @param $script_name
- *   The part of the URL following the hostname, including the leading slash.
- * @param $require_settings
- *   Defaults to TRUE. If TRUE, then only match directories with a
- *   'settings.php' file. Otherwise match any directory.
- *
- * @return
- *   The path of the matching configuration directory.
- *
- * @see default.settings.php
- * @see example.sites.php
- * @see conf_path()
- */
-function find_conf_path($http_host, $script_name, $require_settings = TRUE) {
-  // Determine whether multi-site functionality is enabled.
-  if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
-    return 'sites/default';
-  }
-
-  $sites = array();
-  include DRUPAL_ROOT . '/sites/sites.php';
-
-  $uri = explode('/', $script_name);
-  $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
-  for ($i = count($uri) - 1; $i > 0; $i--) {
-    for ($j = count($server); $j > 0; $j--) {
-      $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
-      if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
-        $dir = $sites[$dir];
-      }
-      if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
-        return "sites/$dir";
-      }
-    }
-  }
-  return 'sites/default';
-}
-
-/**
  * Returns the path of a configuration directory.
  *
  * @param string $type
@@ -451,11 +298,12 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) {
  *   excluding any GET request but including the script name
  *   (e.g., http://www.example.com/mysite/index.php).
  *
- * @see conf_path()
+ * @see \Drupal\Core\Utility\Site::getPath()
  * @see request_uri()
  * @see \Symfony\Component\HttpFoundation\Request::getClientIP()
  */
 function drupal_override_server_variables($variables = array()) {
+  // @todo \Drupal::request() is not available when this function is called.
   $request = \Drupal::request();
   $server_vars = $request->server->all();
   // Allow the provided URL to override any existing values in $_SERVER.
@@ -484,7 +332,10 @@ function drupal_override_server_variables($variables = array()) {
   // Replace elements of the $_SERVER array, as appropriate.
   $request->server->replace($variables + $server_vars + $defaults);
 
-  // @todo remove once conf_path() no longer uses $_SERVER.
+  // @todo Inject a global Request object for all CLI executions + use the
+  //   manipulated $request->server as basis for any subsequently instantiated
+  //   Request objects. Alternatively, sub-class Request or fix it upstream to
+  //   account for CLI environments.
   $_SERVER = $request->server->all();
 }
 
@@ -523,7 +374,7 @@ function drupal_environment_initialize() {
   error_reporting(E_STRICT | E_ALL | error_reporting());
 
   // Override PHP settings required for Drupal to work properly.
-  // sites/default/default.settings.php contains more runtime settings.
+  // default.settings.php contains more runtime settings.
   // The .htaccess file contains settings that cannot be changed at runtime.
 
   // Deny execution with enabled "magic quotes" (both GPC and runtime).
@@ -569,14 +420,25 @@ function drupal_settings_initialize() {
   global $databases, $cookie_domain, $conf, $db_prefix, $drupal_hash_salt, $base_secure_url, $base_insecure_url, $config_directories;
   $conf = array();
 
-  // Make conf_path() available as local variable in settings.php.
-  $conf_path = conf_path();
-  if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
-    include_once DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
+  // Read the global /settings.php file.
+  // Exclude it for test requests to prevent settings of the parent site/
+  // test-runner to leak into the test environment.
+  if (!drupal_valid_test_ua() && is_readable(DRUPAL_ROOT . '/settings.php')) {
+    require DRUPAL_ROOT . '/settings.php';
+  }
+
+  // Discover the site directory.
+  Site::init(DRUPAL_ROOT, isset($sites) ? $sites : NULL, isset($conf_path) ? $conf_path : NULL);
+
+  // Make $conf_path available as local variable in settings.php.
+  // Concatenation is safe here, since $conf_path is known to be not empty.
+  $conf_path = Site::getPath();
+  if ($conf_path !== '' && is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
+    require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
   }
-  require_once __DIR__ . '../../lib/Drupal/Component/Utility/Settings.php';
 
   new Settings(isset($settings) ? $settings : array());
+
   $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
 
   if (isset($base_url)) {
@@ -1956,7 +1818,15 @@ function _drupal_bootstrap_configuration() {
   drupal_settings_initialize();
 
   // Make sure we are using the test database prefix in child Drupal sites.
-  _drupal_initialize_db_test_prefix();
+  if ($test_prefix = drupal_valid_test_ua()) {
+    if (!empty($GLOBALS['databases']) && strpos($GLOBALS['databases']['default']['default']['prefix'], $test_prefix) === FALSE) {
+      throw new Exception('Bad prefix.');
+    }
+    // @todo Move into initial (unset) getter logic of drupal_valid_test_ua()?
+    $test_info = &$GLOBALS['drupal_test_info'];
+    $test_info['test_run_id'] = $test_prefix;
+    $test_info['in_child_site'] = TRUE;
+  }
 
   // Activate the class loader.
   drupal_classloader();
@@ -2046,39 +1916,6 @@ function _drupal_bootstrap_page_cache() {
 }
 
 /**
- * In a test environment, get the test db prefix and set it in $databases.
- */
-function _drupal_initialize_db_test_prefix() {
-  // The user agent header is used to pass a database prefix in the request when
-  // running tests. However, for security reasons, it is imperative that we
-  // validate we ourselves made the request.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    // Set the test run id for use in other parts of Drupal.
-    $test_info = &$GLOBALS['drupal_test_info'];
-    $test_info['test_run_id'] = $test_prefix;
-    $test_info['in_child_site'] = TRUE;
-
-    foreach ($GLOBALS['databases']['default'] as &$value) {
-      // Extract the current default database prefix.
-      if (!isset($value['prefix'])) {
-        $current_prefix = '';
-      }
-      elseif (is_array($value['prefix'])) {
-        $current_prefix = $value['prefix']['default'];
-      }
-      else {
-        $current_prefix = $value['prefix'];
-      }
-
-      // Remove the current database prefix and replace it by our own.
-      $value['prefix'] = array(
-        'default' => $current_prefix . $test_prefix,
-      );
-    }
-  }
-}
-
-/**
  * Loads system variables and all enabled bootstrap modules.
  */
 function _drupal_bootstrap_variables() {
@@ -2215,84 +2052,56 @@ function drupal_valid_test_ua($new_prefix = NULL) {
 
   if (isset($new_prefix)) {
     $test_prefix = $new_prefix;
+    // A new prefix is only explicitly set within the parent site/test runner.
+    // Set the global test run ID and info accordingly.
+    if ($new_prefix) {
+      $test_info = &$GLOBALS['drupal_test_info'];
+      $test_info['test_run_id'] = $test_prefix;
+      if (!isset($test_info['in_child_site'])) {
+        $test_info['in_child_site'] = FALSE;
+      }
+    }
+    else {
+      unset($GLOBALS['drupal_test_info']);
+    }
   }
   if (isset($test_prefix)) {
     return $test_prefix;
   }
-
+  $test_prefix = FALSE;
   if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
     list(, $prefix, $time, $salt, $hmac) = $matches;
     $check_string =  $prefix . ';' . $time . ';' . $salt;
-    // We use the salt from settings.php to make the HMAC key, since
-    // the database is not yet initialized and we can't access any Drupal variables.
+    // Read the hash salt prepared by drupal_generate_test_ua().
+    require DRUPAL_ROOT . '/sites/simpletest/' . substr($prefix, 10) . '/key.php';
     // The file properties add more entropy not easily accessible to others.
-    $key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
+    $key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
     $time_diff = REQUEST_TIME - $time;
-    // We can't use Crypt::hmacBase64() yet because this can be called in very
-    // early bootstrap when autoloader has not been initialized yet.
-    $test_hmac = base64_encode(hash_hmac('sha256', $check_string, $key, TRUE));
-    $test_hmac = strtr($test_hmac, array('+' => '-', '/' => '_', '=' => ''));
+    $test_hmac = Crypt::hmacBase64($check_string, $key);
     // Since we are making a local request a 5 second time window is allowed,
     // and the HMAC must match.
-    if ($time_diff >= 0 && $time_diff <= 5 && $hmac == $test_hmac) {
+    if ($time_diff >= 0 && $time_diff <= 5 && $hmac === $test_hmac) {
       $test_prefix = $prefix;
-      _drupal_load_test_overrides($test_prefix);
-      return $test_prefix;
     }
   }
-
-  $test_prefix = FALSE;
   return $test_prefix;
 }
 
 /**
- * Overrides low-level and environment-specific configuration.
- *
- * Very strictly for internal use only.
- *
- * Loads settings.php from the simpletest public files directory. These files
- * can change the global $conf, the global $config_directories, the return
- * value of conf_path(), and settings().
- *
- * @param string $test_prefix
- *   The simpletest prefix.
- */
-function _drupal_load_test_overrides($test_prefix) {
-  global $conf, $config_directories;
-
-  // Do not use the parent site's config directories. Use only the child site's.
-  // @see \Drupal\simpletest\TestBase::prepareConfigDirectories()
-  $path_prefix = 'simpletest/' . substr($test_prefix, 10);
-  $config_directories = array();
-  foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) {
-    $config_directories[$type] = conf_path() . '/files/' . $path_prefix . '/config_' . $type;
-  }
-
-  // Check for and load a settings.php file in the simpletest files directory.
-  $filename = conf_path() . '/files/' . $path_prefix . '/settings.php';
-  if (file_exists($filename)) {
-    $settings = settings()->getAll();
-    $conf_path = &drupal_static('conf_path');
-    // This can override $conf, $conf_path, $settings, and $config_directories.
-    include $filename;
-    // Keep the overriden $conf_path alive across drupal_static_reset() calls.
-    // @see conf_path()
-    $settings['simpletest_conf_path'] = $conf_path;
-    new Settings($settings);
-  }
-}
-
-/**
  * Generates a user agent string with a HMAC and timestamp for simpletest.
  */
 function drupal_generate_test_ua($prefix) {
   static $key;
 
   if (!isset($key)) {
-    // We use the salt from settings.php to make the HMAC key, since
-    // the database is not yet initialized and we can't access any Drupal variables.
+    // Generate and save a hash salt for a test run.
+    // Consumed by drupal_valid_test_ua() before settings.php is loaded.
+    $private_key = Crypt::randomStringHashed(55);
+    $key_file = "<?php\n\$private_key = '$private_key';\n";
+    file_put_contents(DRUPAL_ROOT . '/sites/simpletest/' . substr($prefix, 10) . '/key.php', $key_file);
+
     // The file properties add more entropy not easily accessible to others.
-    $key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
+    $key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
   }
   // Generate a moderately secure HMAC based on the database credentials.
   $salt = uniqid('', TRUE);
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 6dfc270..ab8b17d 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -12,6 +12,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\StringTranslation\Translator\FileTranslation;
+use Drupal\Core\Utility\Site;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -281,25 +282,30 @@ function install_begin_request(&$install_state) {
     drupal_override_server_variables($install_state['server']);
   }
 
-  // Initialize conf_path().
-  // This primes the site path to be used during installation. By not requiring
-  // settings.php, a bare site folder can be prepared in the /sites directory,
-  // which will be used for installing Drupal.
-  conf_path(FALSE);
-
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+  // Initialize the Site directory.
+  // This primes the site path to be used during installation, to allow a bare
+  // site folder to be prepared in the /sites directory, which will be used for
+  // installing Drupal.
+  require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/Utility/Site.php';
+  Site::initInstaller(DRUPAL_ROOT);
 
   // If the hash salt leaks, it becomes possible to forge a valid testing user
-  // agent, install a new copy of Drupal, and take over the original site. To
-  // avoid this yet allow for automated testing of the installer, make sure
-  // there is also a special test-specific settings.php overriding conf_path().
-  // _drupal_load_test_overrides() sets the simpletest_conf_path in-memory
-  // setting in this case.
-  if ($install_state['interactive'] && drupal_valid_test_ua() && !settings()->get('simpletest_conf_path')) {
+  // agent, install a new copy of Drupal, and take over the original site.
+  // The user agent header is used to pass a database prefix in the request when
+  // running tests. However, for security reasons, it is imperative that no
+  // installation be permitted using such a prefix.
+  if ($install_state['interactive'] && strpos($request->server->get('HTTP_USER_AGENT'), 'simpletest') !== FALSE && !drupal_valid_test_ua()) {
     header($request->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
     exit;
   }
 
+  // Perform a minimal bootstrap.
+  // During installation, drupal_settings_initialize() will not attempt to load
+  // settings.php, so as to prime the site path to be used during installation.
+  // By not requiring settings.php, a bare site folder can be prepared in the
+  // /sites directory, which will be used for installing Drupal.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+
   // If we have a language selected and it is not yet saved in the system
   // (eg. pre-database data screens we are unable to persistently store
   // the default language), we should set language_default so the proper
@@ -1067,9 +1073,7 @@ function install_verify_database_settings() {
   global $databases;
   if (!empty($databases)) {
     $database = $databases['default']['default'];
-    drupal_static_reset('conf_path');
-    $settings_file = './' . conf_path(FALSE) . '/settings.php';
-    $errors = install_database_errors($database, $settings_file);
+    $errors = install_database_errors($database);
     if (empty($errors)) {
       return TRUE;
     }
@@ -1090,9 +1094,6 @@ function install_verify_database_settings() {
 function install_settings_form($form, &$form_state, &$install_state) {
   global $databases;
 
-  drupal_static_reset('conf_path');
-  $conf_path = './' . conf_path(FALSE);
-  $settings_file = $conf_path . '/settings.php';
   $database = isset($databases['default']['default']) ? $databases['default']['default'] : array();
 
   drupal_set_title(t('Database configuration'));
@@ -1139,7 +1140,6 @@ function install_settings_form($form, &$form_state, &$install_state) {
   );
 
   $form['errors'] = array();
-  $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
 
   return $form;
 }
@@ -1154,9 +1154,9 @@ function install_settings_form_validate($form, &$form_state) {
   $database = $form_state['values'][$driver];
   // When testing the interactive installer, copy the database password and
   // the test prefix.
+  // @todo Remove this; pass prefix in POST data instead.
   if ($test_prefix = drupal_valid_test_ua()) {
     $database['prefix'] = $test_prefix;
-    $database['password'] = $GLOBALS['databases']['default']['default']['password'];
   }
   $drivers = drupal_get_database_types();
   $reflection = new \ReflectionClass($drivers[$driver]);
@@ -1167,13 +1167,13 @@ function install_settings_form_validate($form, &$form_state) {
 
   // @todo PIFR uses 'db_prefix' instead of 'prefix'. Remove this when it gets
   //   fixed.
-  if (!$test_prefix) {
+  if (!$test_prefix && isset($database['db_prefix'])) {
     $database['prefix'] = $database['db_prefix'];
   }
   unset($database['db_prefix']);
 
   $form_state['storage']['database'] = $database;
-  $errors = install_database_errors($database, $form_state['values']['settings_file']);
+  $errors = install_database_errors($database);
   foreach ($errors as $name => $message) {
     form_set_error($name, $form_state, $message);
   }
@@ -1182,7 +1182,7 @@ function install_settings_form_validate($form, &$form_state) {
 /**
  * Checks a database connection and returns any errors.
  */
-function install_database_errors($database, $settings_file) {
+function install_database_errors($database) {
   global $databases;
   $errors = array();
 
@@ -1190,7 +1190,11 @@ function install_database_errors($database, $settings_file) {
   $database_types = drupal_get_database_types();
   $driver = $database['driver'];
   if (!isset($database_types[$driver])) {
-    $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $driver));
+    $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array(
+      '%settings_file' => Site::getPath('settings.php'),
+      '@drupal' => drupal_install_profile_distribution_name(),
+      '%driver' => $driver,
+    ));
   }
   else {
     // Run driver specific validation
@@ -1231,33 +1235,15 @@ function install_settings_form_submit($form, &$form_state) {
   // Update global settings array and save.
   $settings = array();
   $database = $form_state['storage']['database'];
-  // Ideally, there is no difference between the code executed by the
-  // automated test browser and an ordinary browser. However, the database
-  // settings need a different format and also need to skip the password
-  // when testing. The hash salt also needs to be skipped because the original
-  // salt is used to verify the validity of the automated test browser.
-  // Because of these, there's a little difference in the code following but
-  // it is small and self-contained.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    foreach ($form_state['storage']['database'] as $k => $v) {
-      if ($k != 'password') {
-        $settings['databases']['default']['default'][$k] = (object) array(
-          'value'    => $v,
-          'required' => TRUE,
-        );
-      }
-    }
-  }
-  else {
-    $settings['databases']['default']['default'] = (object) array(
-      'value'    => $database,
-      'required' => TRUE,
-    );
-    $settings['drupal_hash_salt'] = (object) array(
-      'value'    => Crypt::randomStringHashed(55),
-      'required' => TRUE,
-    );
-  }
+
+  $settings['databases']['default']['default'] = (object) array(
+    'value'    => $database,
+    'required' => TRUE,
+  );
+  $settings['drupal_hash_salt'] = (object) array(
+    'value'    => Crypt::randomStringHashed(55),
+    'required' => TRUE,
+  );
 
   // Remember the profile which was used.
   $settings['settings'] = array(
@@ -1488,7 +1474,7 @@ function install_translations_directory() {
     $directory = $GLOBALS['conf']['locale.settings']['translation.path'];
   }
   else {
-    $directory = conf_path() . '/files/translations';
+    $directory = Site::getPath('files/translations');
   }
   return $directory;
 }
@@ -2070,8 +2056,8 @@ function install_configure_form($form, &$form_state, &$install_state) {
   drupal_set_title(t('Configure site'));
 
   // Warn about settings.php permissions risk
-  $settings_dir = conf_path();
-  $settings_file = $settings_dir . '/settings.php';
+  $settings_dir = Site::getPath();
+  $settings_file = Site::getPath('settings.php');
   // Check that $_POST is empty so we only show this message when the form is
   // first displayed, not on the next page after it is submitted. (We do not
   // want to repeat it multiple times because it is a general warning that is
@@ -2080,7 +2066,7 @@ function install_configure_form($form, &$form_state, &$install_state) {
   // distract from the message that the Drupal installation has completed
   // successfully.)
   $post_params = \Drupal::request()->request->all();
-  if (empty($post_params) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) {
+  if (empty($post_params) && (!drupal_verify_install_file(Site::getAbsolutePath('settings.php'), FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(Site::getAbsolutePath(), FILE_NOT_WRITABLE, 'dir'))) {
     drupal_set_message(t('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the <a href="@handbook_url">online handbook</a>.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning');
   }
 
@@ -2226,8 +2212,8 @@ function install_check_translations($install_state) {
   $readable = FALSE;
   $writable = FALSE;
   // @todo: Make this configurable.
-  $files_directory = conf_path() . '/files';
-  $translations_directory = conf_path() . '/files/translations';
+  $files_directory = Site::getPath('files');
+  $translations_directory = Site::getPath('files/translations');
   $translations_directory_exists = FALSE;
   $translation_available = FALSE;
   $online = FALSE;
@@ -2380,15 +2366,14 @@ function install_check_requirements($install_state) {
   if (!$install_state['settings_verified']) {
     $readable = FALSE;
     $writable = FALSE;
-    $conf_path = './' . conf_path(FALSE, TRUE);
-    $settings_file = $conf_path . '/settings.php';
-    $default_settings_file = './sites/default/default.settings.php';
-    $file = $conf_path;
+    $conf_path = Site::getPath();
+    $settings_file = Site::getAbsolutePath('settings.php');
+    $default_settings_file = './core/default.settings.php';
+    $file = Site::getPath('settings.php');
     $exists = FALSE;
     // Verify that the directory exists.
-    if (drupal_verify_install_file($conf_path, FILE_EXIST, 'dir')) {
+    if (drupal_verify_install_file(Site::getAbsolutePath(), FILE_EXIST, 'dir')) {
       // Check if a settings.php file already exists.
-      $file = $settings_file;
       if (drupal_verify_install_file($settings_file, FILE_EXIST)) {
         // If it does, make sure it is writable.
         $readable = drupal_verify_install_file($settings_file, FILE_READABLE);
@@ -2397,20 +2382,11 @@ function install_check_requirements($install_state) {
       }
     }
 
-    // If default.settings.php does not exist, or is not readable, throw an
-    // error.
-    if (!drupal_verify_install_file($default_settings_file, FILE_EXIST|FILE_READABLE)) {
-      $requirements['default settings file exists'] = array(
-        'title'       => t('Default settings file'),
-        'value'       => t('The default settings file does not exist.'),
-        'severity'    => REQUIREMENT_ERROR,
-        'description' => t('The @drupal installer requires that the %default-file file not be modified in any way from the original download.', array('@drupal' => drupal_install_profile_distribution_name(), '%default-file' => $default_settings_file)),
-      );
-    }
     // Otherwise, if settings.php does not exist yet, we can try to copy
     // default.settings.php to create it.
-    elseif (!$exists) {
-      $copied = drupal_verify_install_file($conf_path, FILE_EXIST|FILE_WRITABLE, 'dir') && @copy($default_settings_file, $settings_file);
+    if (!$exists) {
+      $copied = drupal_verify_install_file(Site::getAbsolutePath(), FILE_EXIST|FILE_WRITABLE, 'dir');
+      $copied = $copied && @copy($default_settings_file, $settings_file);
       if ($copied) {
         // If the new settings file has the same owner as default.settings.php,
         // this means default.settings.php is owned by the webserver user.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 67c18b7..10fb016 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DrupalKernel;
+use Drupal\Core\Utility\Site;
 
 /**
  * Requirement severity -- Informational message only.
@@ -195,7 +196,7 @@ function drupal_get_database_types() {
  */
 function drupal_rewrite_settings($settings = array(), $settings_file = NULL) {
   if (!isset($settings_file)) {
-    $settings_file = conf_path(FALSE) . '/settings.php';
+    $settings_file = Site::getPath('settings.php');
   }
   // Build list of setting names and insert the values into the global namespace.
   $variable_names = array();
@@ -449,11 +450,11 @@ function drupal_install_config_directories($mode = NULL) {
     $config_directories_hash = Crypt::randomStringHashed(55);
     $settings['config_directories'] = array(
       CONFIG_ACTIVE_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_' . $config_directories_hash . '/active',
+        'value' => Site::getPath('files/config_' . $config_directories_hash . '/active'),
         'required' => TRUE,
       ),
       CONFIG_STAGING_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_' . $config_directories_hash . '/staging',
+        'value' => Site::getPath('files/config_' . $config_directories_hash . '/staging'),
         'required' => TRUE,
       ),
     );
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 24f6583..e56cca1 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -15,6 +15,7 @@
 use Drupal\Core\Config\ConfigException;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Utility\Error;
+use Drupal\Core\Utility\Site;
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Component\Utility\NestedArray;
 use Symfony\Component\HttpFoundation\Request;
@@ -124,7 +125,7 @@ function update_prepare_d8_bootstrap() {
   // If any of the required settings needs to be written, then settings.php
   // needs to be writable.
   if (!$settings_exist) {
-    $settings_file = conf_path() . '/settings.php';
+    $settings_file = Site::getPath('settings.php');
     $writable = drupal_verify_install_file($settings_file, FILE_EXIST | FILE_READABLE | FILE_WRITABLE);
     $requirements['settings file']['title'] = 'Settings file';
     if ($writable) {
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
index 633edc6..3f2147e 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Driver\sqlite\Connection;
 use Drupal\Core\Database\DatabaseNotFoundException;
 use Drupal\Core\Database\Install\Tasks as InstallTasks;
+use Drupal\Core\Utility\Site;
 
 /**
  * Specifies installation tasks for SQLite databases.
@@ -49,7 +50,7 @@ public function getFormOptions(array $database) {
     // Make the text more accurate for SQLite.
     $form['database']['#title'] = t('Database file');
     $form['database']['#description'] = t('The absolute path to the file where @drupal data will be stored. This must be writable by the web server and should exist outside of the web root.', array('@drupal' => drupal_install_profile_distribution_name()));
-    $default_database = conf_path(FALSE, TRUE) . '/files/.ht.sqlite';
+    $default_database = Site::getPath('files/.ht.sqlite');
     $form['database']['#default_value'] = empty($database['database']) ? $default_database : $database['database'];
     return $form;
   }
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 0160119..d1badfb 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -342,6 +342,7 @@ public function updateModules(array $module_list, array $module_filenames = arra
   protected function getClassName() {
     $parts = array('service_container', $this->environment);
     // Make sure to use a testing-specific container even in the parent site.
+    // @todo Obsolete by drupal_valid_test_ua()?
     if (!empty($GLOBALS['drupal_test_info']['test_run_id'])) {
       $parts[] = $GLOBALS['drupal_test_info']['test_run_id'];
     }
diff --git a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
index 90f17b3..cbb596c 100644
--- a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
+++ b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\Core\StreamWrapper;
+use Drupal\Core\Utility\Site;
 
 /**
  * Defines a Drupal public (public://) stream wrapper class.
@@ -37,14 +38,7 @@ public function getExternalUrl() {
    *   The base path for public:// typically sites/default/files.
    */
   public static function basePath() {
-    $base_path = settings()->get('file_public_path', conf_path() . '/files');
-    if ($test_prefix = drupal_valid_test_ua()) {
-      // Append the testing suffix unless already given.
-      // @see \Drupal\simpletest\WebTestBase::setUp()
-      if (strpos($base_path, '/simpletest/' . substr($test_prefix, 10)) === FALSE) {
-        return $base_path . '/simpletest/' . substr($test_prefix, 10);
-      }
-    }
+    $base_path = settings()->get('file_public_path', Site::getPath('files'));
     return $base_path;
   }
 
diff --git a/core/lib/Drupal/Core/SystemListing.php b/core/lib/Drupal/Core/SystemListing.php
index 20d95cb..6d895a2 100644
--- a/core/lib/Drupal/Core/SystemListing.php
+++ b/core/lib/Drupal/Core/SystemListing.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\Core;
+use Drupal\Core\Utility\Site;
 
 /**
  * Returns information about system object files (modules, themes, etc.).
@@ -85,7 +86,6 @@ function scan($mask, $directory, $key = 'name') {
     if (!in_array($key, array('uri', 'filename', 'name'))) {
       $key = 'uri';
     }
-    $config = conf_path();
 
     // Search for the directory in core.
     $searchdir = array('core/' . $directory);
@@ -100,9 +100,12 @@ function scan($mask, $directory, $key = 'name') {
     $searchdir[] = $directory;
     $searchdir[] = 'sites/all/' . $directory;
 
-    if (file_exists("$config/$directory")) {
-      $searchdir[] = "$config/$directory";
+    if (Site::getPath() !== '') {
+      if (file_exists(Site::getPath($directory))) {
+        $searchdir[] = Site::getPath($directory);
+      }
     }
+
     // @todo Find a way to skip ./config directories (but not modules/config).
     $nomask = '/^(CVS|lib|templates|css|js)$/';
     $files = array();
diff --git a/core/lib/Drupal/Core/SystemListingInfo.php b/core/lib/Drupal/Core/SystemListingInfo.php
index d302699..3575adc 100644
--- a/core/lib/Drupal/Core/SystemListingInfo.php
+++ b/core/lib/Drupal/Core/SystemListingInfo.php
@@ -28,6 +28,7 @@ protected function profiles($directory) {
     // For SimpleTest to be able to test modules packaged together with a
     // distribution we need to include the profile of the parent site (in
     // which test runs are triggered).
+    // @todo !drupal_installation_attempted() defeats the whole purpose?
     if (drupal_valid_test_ua() && !drupal_installation_attempted()) {
       $testing_profile = \Drupal::config('simpletest.settings')->get('parent_profile');
       if ($testing_profile && $testing_profile != $profile) {
diff --git a/core/lib/Drupal/Core/Utility/Site.php b/core/lib/Drupal/Core/Utility/Site.php
new file mode 100644
index 0000000..6711562
--- /dev/null
+++ b/core/lib/Drupal/Core/Utility/Site.php
@@ -0,0 +1,343 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Utility\Site.
+ */
+
+namespace Drupal\Core\Utility;
+
+use Drupal\Component\Utility\Settings;
+
+/**
+ * A utility class for easy access to the site path.
+ */
+class Site {
+
+  /**
+   * The absolute path to the Drupal root directory.
+   *
+   * @var string
+   */
+  private $root;
+
+  /**
+   * The relative path to the site directory.
+   *
+   * May be an empty string, in case the site directory is the root directory.
+   *
+   * @var string
+   */
+  private $path;
+
+  /**
+   * Whether the Site singleton was instantiated by the installer.
+   *
+   * @var bool
+   */
+  private $isInstaller;
+
+  /**
+   * The original Site instance of the test runner during test execution.
+   *
+   * @see \Drupal\Core\Utility\Site::setUpTest()
+   * @see \Drupal\Core\Utility\Site::tearDownTest()
+   *
+   * @var \Drupal\Core\Utility\Site
+   */
+  private $original;
+
+  /**
+   * The Site singleton instance.
+   *
+   * @var \Drupal\Core\Utility\Site
+   */
+  private static $instance;
+
+  /**
+   * Initializes the Site singleton.
+   *
+   * @param string $root_directory
+   *   The root directory to use for absolute paths; i.e., DRUPAL_ROOT.
+   * @param array $sites
+   *   (optional) A multi-site mapping, as defined in settings.php.
+   * @param string $custom_path
+   *   (optional) An explicit site path to set; skipping site negotiation.
+   *   This can be defined as $conf_path in the root /settings.php file.
+   *
+   * @see drupal_settings_initialize()
+   */
+  public static function init($root_directory, array $sites = NULL, $custom_path = NULL) {
+    if (!isset(self::$instance)) {
+      new self($root_directory);
+    }
+    // Only the installer environment is allowed instantiate the Site singleton
+    // prior to drupal_settings_initialize().
+    // @see initInstaller()
+    elseif (!self::$instance->isInstaller()) {
+      throw new \BadMethodCallException('Site path is initialized already.');
+    }
+    // Force-override the site directory in tests.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      $custom_path = 'sites/simpletest/' . substr($test_prefix, 10);
+    }
+    self::$instance->initializePath($sites, $custom_path);
+  }
+
+  /**
+   * Initializes the Site singleton for the early installer environment.
+   *
+   * The installer uses this function to prime the site directory path very
+   * early in the installer environmnt. This allows the application to be
+   * installed into a new and empty site directory, which does not contain a
+   * settings.php yet.
+   *
+   * @param string $root_directory
+   *   The root directory to use for absolute paths; i.e., DRUPAL_ROOT.
+   *
+   * @see install_begin_request()
+   */
+  public static function initInstaller($root_directory) {
+    // WebTestBase::setUp() invokes Site::setUpTest() prior to invoking the
+    // non-interactive installer, in order to override the singleton and prime
+    // a custom site directory.
+    if (drupal_valid_test_ua()) {
+      return;
+    }
+    if (isset(self::$instance)) {
+      throw new \BadMethodCallException('Site path is initialized already.');
+    }
+    // Set a global state flag to denote that we are operating in the special
+    // installer environment. initializePath() is unnecessary, as init() will be
+    // called by drupal_settings_initialize(), possibly passing new values from
+    // the newly created settings.php file.
+    new self($root_directory, TRUE);
+  }
+
+  /**
+   * Re-initializes the Site singleton for a test run.
+   *
+   * Called by WebTestBase::setUp() prior to invoking the non-interactive
+   * installer for a test.
+   *
+   * @param string $root_directory
+   *   The root directory to use for absolute paths; i.e., DRUPAL_ROOT.
+   * @param string $custom_path
+   *   The relative site directory path to use during the test run; e.g.,
+   *   'sites/simpletest/123456'.
+   */
+  public static function setUpTest($root_directory, $custom_path) {
+    if (!drupal_valid_test_ua()) {
+      throw new \BadMethodCallException('Site is not executing a test.');
+    }
+    if (!file_exists($root_directory . '/' . $custom_path)) {
+      throw new \InvalidArgumentException("Test site directory '$custom_path' does not exist.");
+    }
+    new self($root_directory, TRUE, $custom_path);
+  }
+
+  /**
+   * Reverts the Site singleton to the original after a test run.
+   */
+  public static function tearDownTest() {
+    if (!isset(self::$instance->original)) {
+      throw new \RuntimeException('No original Site to revert to. Missing invocation of Site::setUpTest()?');
+    }
+    self::$instance = self::$instance->original;
+  }
+
+  /**
+   * Constructs the Site singleton.
+   */
+  private function __construct($root_directory, $is_installer = FALSE, $custom_path = NULL) {
+    if (isset(self::$instance->original)) {
+      throw new \RuntimeException('Site is overridden for a test already. Duplicate invocation of Site::setUpTest()?');
+    }
+    if (isset(self::$instance)) {
+      $this->original = clone self::$instance;
+    }
+    $this->root = $root_directory;
+    $this->isInstaller = $is_installer;
+    $this->path = $custom_path;
+    self::$instance = $this;
+  }
+
+  /**
+   * Returns whether the Site singleton was instantiated for the installer.
+   *
+   * @todo Leverage this to eliminate drupal_installation_attempted()?
+   */
+  private function isInstaller() {
+    return $this->isInstaller;
+  }
+
+  /**
+   * Initializes the site path.
+   *
+   * @param array $sites
+   *   (optional) A multi-site mapping, as defined in settings.php.
+   * @param string $custom_path
+   *   (optional) An explicit site path to set; skipping site negotiation.
+   */
+  private function initializePath(array $sites = NULL, $custom_path = NULL) {
+    // When executing the non-interactive installer in the parent site/
+    // test-runner, WebTestBase::setUp() primes the site directory path via
+    // Site::setUpTest() already.
+    // @todo Remove this case by adding a 'site' parameter to drupal_install().
+    if (isset($this->path)) {
+      return;
+    }
+
+    // An explicitly defined $conf_path in /settings.php takes precedence.
+    if (isset($custom_path)) {
+      $this->path = $custom_path;
+    }
+    // If the multi-site functionality was enabled in /settings.php, discover
+    // the path for the current site.
+    // $sites just needs to be defined; an explicit mapping is not required.
+    elseif (isset($sites)) {
+      $this->path = $this->determinePath($sites, !$this->isInstaller());
+    }
+    // If the multi-site functionality is not enabled, the Drupal root
+    // directory is the site directory.
+    else {
+      $this->path = '';
+    }
+  }
+
+  /**
+   * Finds the appropriate configuration directory for a given host and path.
+   *
+   * Finds a matching configuration directory file by stripping the website's
+   * hostname from left to right and pathname from right to left. By default,
+   * the directory must contain a 'settings.php' file for it to match. If the
+   * parameter $require_settings is set to FALSE, then a directory without a
+   * 'settings.php' file will match as well. The first configuration
+   * file found will be used and the remaining ones will be ignored.
+   *
+   * The settings.php file can define aliases in an associative array named
+   * $sites. For example, to create a directory alias for
+   * http://www.drupal.org:8080/mysite/test whose configuration file is in
+   * sites/example.com, the array should be defined as:
+   * @code
+   * $sites = array(
+   *   '8080.www.drupal.org.mysite.test' => 'example.com',
+   * );
+   * @endcode
+   *
+   * @see default.settings.php
+   *
+   * @param array $sites
+   *   A multi-site mapping, as defined in settings.php.
+   * @param bool $require_settings
+   *   Only configuration directories with an existing settings.php file
+   *   will be recognized. Defaults to TRUE. During initial installation,
+   *   this is set to FALSE so that Drupal can detect a matching directory,
+   *   then create a new settings.php file in it.
+   *
+   * @return string
+   *   The path of the matching configuration directory. May be an empty string,
+   *   in case the site configuration directory is the root directory.
+   *
+   * @todo Inject a Request object in instead of relying on globals?
+   */
+  private function determinePath(array $sites, $require_settings) {
+    // The hostname and optional port number, e.g. "www.example.com" or
+    // "www.example.com:8080".
+    $http_host = $_SERVER['HTTP_HOST'];
+    // The part of the URL following the hostname, including the leading slash.
+    $script_name = $_SERVER['SCRIPT_NAME'] ?: $_SERVER['SCRIPT_FILENAME'];
+
+    $uri = explode('/', $script_name);
+    $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
+    for ($i = count($uri) - 1; $i > 0; $i--) {
+      for ($j = count($server); $j > 0; $j--) {
+        $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
+        // Check for an alias in $sites.
+        if (isset($sites[$dir])) {
+          $dir = $sites[$dir];
+          // A defined site alias from /settings.php should be valid.
+          // @todo Even skip the settings.php check?
+          if (!$require_settings) {
+            return "sites/$dir";
+          }
+        }
+        if ($require_settings) {
+          if (file_exists($this->root . '/sites/' . $dir . '/settings.php')) {
+            return "sites/$dir";
+          }
+        }
+        elseif (file_exists($this->root . '/sites/' . $dir)) {
+          return "sites/$dir";
+        }
+      }
+    }
+    return '';
+  }
+
+  /**
+   * Prefixes a given filepath with the site directory, if any.
+   *
+   * @param string $filepath
+   *   The filepath to prefix.
+   *
+   * @return string
+   *   The prefixed filepath.
+   */
+  private function resolvePath($filepath) {
+    if ($filepath !== '' && $filepath[0] === '/') {
+      $filepath = substr($filepath, 1);
+    }
+    if ($this->path !== '') {
+      if ($filepath !== '') {
+        $filepath = $this->path . '/' . $filepath;
+      }
+      else {
+        $filepath = $this->path;
+      }
+    }
+    return $filepath;
+  }
+
+  /**
+   * Returns a given path as relative path to the site directory.
+   *
+   * Use this function instead of appending strings to the site path manually,
+   * because the site directory may be the root directory and thus the resulting
+   * path would be an absolute filesystem path.
+   *
+   * @param string $filepath
+   *   (optional) A relative filepath to append to the site path.
+   *
+   * @return string
+   *   The given $filepath, potentially prefixed with the site path.
+   *
+   * @see \Drupal\Core\Utility\Site::getAbsolutePath()
+   */
+  public static function getPath($filepath = '') {
+    return self::$instance->resolvePath($filepath);
+  }
+
+  /**
+   * Returns a given path as absolute path in the site directory.
+   *
+   * @param string $filepath
+   *   (optional) A relative filepath to append to the site path.
+   *
+   * @return string
+   *   The given $filepath, potentially prefixed with the site path, as an
+   *   absolute filesystem path.
+   *
+   * @see \Drupal\Core\Utility\Site::getPath()
+   */
+  public static function getAbsolutePath($filepath = '') {
+    $filepath = self::$instance->resolvePath($filepath);
+    if ($filepath !== '') {
+      return self::$instance->root . '/' . $filepath;
+    }
+    else {
+      return self::$instance->root;
+    }
+  }
+
+}
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 960381c..c37fdd7 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Language\Language;
+use Drupal\Core\Utility\Site;
 
 /**
  * Implements hook_install().
@@ -13,7 +14,7 @@
 function locale_install() {
   // Create the interface translations directory and ensure it's writable.
   if (!$directory = \Drupal::config('locale.settings')->get('translation.path')) {
-    $directory = conf_path() . '/files/translations';
+    $directory = Site::getPath('files/translations');
     \Drupal::config('locale.settings')->set('translation.path', $directory)->save();
   }
   file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 560afb1..8fb43bc 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -19,6 +19,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Utility\Error;
+use Drupal\Core\Utility\Site;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -36,6 +37,13 @@
   protected $testId;
 
   /**
+   * The site directory of this test run.
+   *
+   * @var string
+   */
+  protected $siteDirectory = NULL;
+
+  /**
    * The database prefix of this test run.
    *
    * @var string
@@ -837,7 +845,9 @@ public function run(array $methods = array()) {
    * @see WebTestBase::setUp()
    */
   protected function prepareDatabasePrefix() {
-    $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
+    $suffix = mt_rand(1000, 1000000);
+    $this->databasePrefix = 'simpletest' . $suffix;
+    $this->siteDirectory = 'sites/simpletest/' . $suffix;
 
     // As soon as the database prefix is set, the test might start to execute.
     // All assertions as well as the SimpleTest batch operations are associated
@@ -925,7 +935,7 @@ protected function prepareEnvironment() {
     // Save further contextual information.
     // Use the original files directory to avoid nesting it within an existing
     // simpletest directory if a test is executed within a test.
-    $this->originalFileDirectory = settings()->get('file_public_path', conf_path() . '/files');
+    $this->originalFileDirectory = settings()->get('file_public_path', Site::getPath('files'));
     $this->originalProfile = drupal_get_profile();
     $this->originalUser = isset($user) ? clone $user : NULL;
 
@@ -946,10 +956,10 @@ protected function prepareEnvironment() {
 
     // Create test directory ahead of installation so fatal errors and debug
     // information can be logged during installation process.
-    // Use temporary files directory with the same prefix as the database.
-    $this->public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10);
-    $this->private_files_directory = $this->public_files_directory . '/private';
-    $this->temp_files_directory = $this->private_files_directory . '/temp';
+    // @todo Do not execute this for WebTestBase.
+    $this->public_files_directory = $this->siteDirectory . '/files';
+    $this->private_files_directory = $this->siteDirectory . '/private';
+    $this->temp_files_directory = $this->siteDirectory . '/temp';
     $this->translation_files_directory = $this->public_files_directory . '/translations';
 
     // Create the directories
@@ -960,7 +970,14 @@ protected function prepareEnvironment() {
     $this->generatedTestFiles = FALSE;
 
     // Create and set new configuration directories.
-    $this->prepareConfigDirectories();
+    // @todo Only valid for tests not executing the installer (in any way).
+    if (!$this instanceof WebTestBase) {
+      $this->prepareConfigDirectories();
+    }
+    else {
+      $GLOBALS['config_directories'] = array();
+      $this->configDirectories = array();
+    }
 
     // Reset statics before the old container is replaced so that objects with a
     // __destruct() method still have access to it.
@@ -1013,7 +1030,7 @@ protected function prepareConfigDirectories() {
     include_once DRUPAL_ROOT . '/core/includes/install.inc';
     foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) {
       // Assign the relative path to the global variable.
-      $path = conf_path() . '/files/simpletest/' . substr($this->databasePrefix, 10) . '/config_' . $type;
+      $path = $this->siteDirectory . '/config_' . $type;
       $GLOBALS['config_directories'][$type] = $path;
       // Ensure the directory can be created and is writeable.
       if (!install_ensure_config_directory($type)) {
@@ -1106,8 +1123,8 @@ protected function tearDown() {
     // log to pick up any fatal errors.
     simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE);
 
-    // Delete temporary files directory.
-    file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10), array($this, 'filePreDeleteCallback'));
+    // Delete test site directory.
+    file_unmanaged_delete_recursive($this->siteDirectory, array($this, 'filePreDeleteCallback'));
 
     // Restore original database connection.
     Database::removeConnection('default');
@@ -1138,6 +1155,9 @@ protected function tearDown() {
     if (isset($this->originalPrefix)) {
       drupal_valid_test_ua($this->originalPrefix);
     }
+    else {
+      drupal_valid_test_ua(FALSE);
+    }
 
     // Restore original shutdown callbacks.
     $callbacks = &drupal_register_shutdown_function();
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 265012e..a17e64b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -17,6 +17,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\StreamWrapper\PublicStream;
+use Drupal\Core\Utility\Site;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -748,6 +749,10 @@ protected function setUp() {
       return FALSE;
     }
 
+    // After preparing the environment and changing the database prefix, we are
+    // in a valid test environment.
+    drupal_valid_test_ua($this->databasePrefix);
+
     // Set the 'simpletest_parent_profile' variable to add the parent profile's
     // search path to the child site's search paths.
     // @see drupal_system_listing()
@@ -781,26 +786,16 @@ protected function setUp() {
     $this->settingsSet('file_public_path', $this->public_files_directory);
     // Execute the non-interactive installer.
     require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
-    $this->settingsSet('cache', array('default' => 'cache.backend.memory'));
+
+    Site::setUpTest(DRUPAL_ROOT, $this->siteDirectory);
+
     $parameters = $this->installParameters();
     install_drupal($parameters);
 
-    // Set the install_profile so that web requests to the requests to the child
-    // site have the correct profile.
-    $settings = array(
-      'settings' => array(
-        'install_profile' => (object) array(
-          'value' => $this->profile,
-          'required' => TRUE,
-        ),
-      ),
-    );
-    $this->writeSettings($settings);
     // Override install profile in Settings to so the correct profile is used by
     // tests.
     $this->settingsSet('install_profile', $this->profile);
 
-    $this->settingsSet('cache', array());
     $this->rebuildContainer();
 
     // Restore the original Simpletest batch.
@@ -863,6 +858,7 @@ protected function setUp() {
    * @see install_state_defaults()
    */
   protected function installParameters() {
+    // The prefix is prepared in TestBase::changeDatabasePrefix() already.
     $connection_info = Database::getConnectionInfo();
     $parameters = array(
       'interactive' => FALSE,
@@ -1026,6 +1022,7 @@ protected function tearDown() {
       $this->kernel->shutdown();
     }
     parent::tearDown();
+    Site::tearDownTest();
 
     // Ensure that internal logged in variable and cURL options are reset.
     $this->loggedInUser = FALSE;
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index bd50676..ba3e9d5 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -367,7 +367,7 @@ function simpletest_last_test_get($test_id) {
  *
  * @param $test_id
  *   The test ID to which the log relates.
- * @param $prefix
+ * @param $database_prefix
  *   The database prefix to which the log relates.
  * @param $test_class
  *   The test class to which the log relates.
@@ -377,8 +377,8 @@ function simpletest_last_test_get($test_id) {
  * @return
  *   Found any entries in log.
  */
-function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALSE) {
-  $log = 'public://' . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/error.log';
+function simpletest_log_read($test_id, $database_prefix, $test_class, $during_test = FALSE) {
+  $log = 'sites/simpletest/' . substr($database_prefix, 10) . '/error.log';
   $found = FALSE;
   if (file_exists($log)) {
     foreach (file($log) as $line) {
@@ -632,14 +632,12 @@ function simpletest_clean_database() {
  */
 function simpletest_clean_temporary_directories() {
   $count = 0;
-  if (is_dir('public://simpletest')) {
-    $files = scandir('public://simpletest');
+  if (is_dir('sites/simpletest')) {
+    $files = scandir('sites/simpletest');
     foreach ($files as $file) {
-      $path = 'public://simpletest/' . $file;
-      if (is_dir($path) && (is_numeric($file) || strpos($file, 'config_simpletest') !== FALSE)) {
-        file_unmanaged_delete_recursive($path, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
-        $count++;
-      }
+      $path = 'sites/simpletest/' . $file;
+      file_unmanaged_delete_recursive($path, array('Drupal\simpletest\TestBase', 'filePreDeleteCallback'));
+      $count++;
     }
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php
index 7fd19c5..2cef1a8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\system\Tests\File;
+use Drupal\Core\Utility\Site;
 
 /**
  * Directory related tests.
@@ -23,7 +24,7 @@ public static function getInfo() {
    * Test local directory handling functions.
    */
   function testFileCheckLocalDirectoryHandling() {
-    $directory = conf_path() . '/files';
+    $directory = Site::getPath('files');
 
     // Check a new recursively created local directory for correct file system
     // permissions.
diff --git a/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php
index ef84796..ee0426a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\system\Tests\File;
+use Drupal\Core\Utility\Site;
 
 /**
  * Tests that files can not be written using ReadOnlyStreamWrapper functions.
@@ -46,7 +47,7 @@ function tearDown() {
   function testWriteFunctions() {
     // Generate a test file
     $filename = $this->randomName();
-    $filepath = conf_path() . '/files/' . $filename;
+    $filepath = Site::getPath('files/' . $filename);
     file_put_contents($filepath, $filename);
 
     // Generate a read-only stream wrapper instance
@@ -89,7 +90,7 @@ function testWriteFunctions() {
 
     // Test the mkdir() function by attempting to create a directory.
     $dirname = $this->randomName();
-    $dir = conf_path() . '/files/' . $dirname;
+    $dir = Site::getPath('files/' . $dirname);
     $readonlydir = $this->scheme . '://' . $dirname;
     $this->assertFalse(@drupal_mkdir($readonlydir, 0775, 0), 'Unable to create directory with read-only stream wrapper.');
     // Create a temporary directory for testing purposes
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/SettingsRewriteTest.php b/core/modules/system/lib/Drupal/system/Tests/System/SettingsRewriteTest.php
index 74c080d..6256f21 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/SettingsRewriteTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/SettingsRewriteTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\System;
 
+use Drupal\Core\Utility\Site;
 use Drupal\simpletest\UnitTestBase;
 
 /**
@@ -104,7 +105,7 @@ function testDrupalRewriteSettings() {
       ),
     );
     foreach ($tests as $test) {
-      $filename = settings()->get('file_public_path', conf_path() . '/files') . '/mock_settings.php';
+      $filename = settings()->get('file_public_path', Site::getPath('files')) . '/mock_settings.php';
       file_put_contents(DRUPAL_ROOT . '/' . $filename, "<?php\n" . $test['original'] . "\n");
       drupal_rewrite_settings($test['settings'], $filename);
       $this->assertEqual(file_get_contents(DRUPAL_ROOT . '/' . $filename), "<?php\n" . $test['expected'] . "\n");
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 4fd03af..0058c65 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -9,6 +9,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Language\Language;
 use Drupal\Core\StreamWrapper\PublicStream;
+use Drupal\Core\Utility\Site;
 
 /**
  * Implements hook_requirements().
@@ -229,12 +230,12 @@ function system_requirements($phase) {
   // Test configuration files and directory for writability.
   if ($phase == 'runtime') {
     $conf_errors = array();
-    $conf_path = conf_path();
+    $conf_path = Site::getPath();
     if (!drupal_verify_install_file($conf_path, FILE_NOT_WRITABLE, 'dir')) {
       $conf_errors[] = t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array('%file' => $conf_path));
     }
     foreach (array('settings.php', 'settings.local.php') as $conf_file) {
-      $full_path = $conf_path . '/' . $conf_file;
+      $full_path = Site::getPath($conf_file);
       if (file_exists($full_path) && !drupal_verify_install_file($full_path, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
         $conf_errors[] = t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", array('%file' => $full_path));
       }
@@ -327,9 +328,8 @@ function system_requirements($phase) {
     }
     else {
       // If we are installing Drupal, the settings.php file might not exist yet
-      // in the intended conf_path() directory, so don't require it. The
-      // conf_path() cache must also be reset in this case.
-      $directories[] = conf_path(FALSE, TRUE) . '/files';
+      // in the intended site directory, so don't require it.
+      $directories[] = Site::getPath('files');
     }
     if (!empty($conf['system.file']['path.private'])) {
       $directories[] = $conf['system.file']['path.private'];
@@ -355,7 +355,7 @@ function system_requirements($phase) {
     $requirements['config directories'] = array(
       'title' => t('Configuration directories'),
       'value' => t('Not present'),
-      'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => conf_path() . '/settings.php')),
+      'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => Site::getPath('settings.php'))),
       'severity' => REQUIREMENT_ERROR,
     );
   }
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 19c0dc1..1ea7052 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -38,6 +38,7 @@
 
 use Drupal\Core\Updater\Updater;
 use Drupal\Core\FileTransfer\Local;
+use Drupal\Core\Utility\Site;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
@@ -470,7 +471,7 @@ function update_manager_update_ready_form_submit($form, &$form_state) {
     // trying to install the code, there's no need to prompt for FTP/SSH
     // credentials. Instead, we instantiate a Drupal\Core\FileTransfer\Local and
     // invoke update_authorize_run_update() directly.
-    if (fileowner($project_real_location) == fileowner(conf_path())) {
+    if (fileowner($project_real_location) == fileowner(Site::getPath())) {
       module_load_include('inc', 'update', 'update.authorize');
       $filetransfer = new Local(DRUPAL_ROOT);
       update_authorize_run_update($filetransfer, $updates);
@@ -748,7 +749,7 @@ function update_manager_install_form_submit($form, &$form_state) {
   // trying to install the code, there's no need to prompt for FTP/SSH
   // credentials. Instead, we instantiate a Drupal\Core\FileTransfer\Local and
   // invoke update_authorize_run_install() directly.
-  if (fileowner($project_real_location) == fileowner(conf_path())) {
+  if (fileowner($project_real_location) == fileowner(Site::getPath())) {
     module_load_include('inc', 'update', 'update.authorize');
     $filetransfer = new Local(DRUPAL_ROOT);
     call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
@@ -947,7 +948,7 @@ function update_manager_local_transfers_allowed() {
   // the configuration directory to determine if local transfers will be
   // allowed.
   $temporary_file = drupal_tempnam('temporary://', 'update_');
-  $local_transfers_allowed = fileowner($temporary_file) === fileowner(conf_path());
+  $local_transfers_allowed = fileowner($temporary_file) === fileowner(Site::getPath());
 
   // Clean up. If this fails, we can ignore it (since this is just a temporary
   // file anyway).
diff --git a/sites/example.sites.php b/sites/example.sites.php
deleted file mode 100644
index 2b00151..0000000
--- a/sites/example.sites.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-/**
- * @file
- * Configuration file for Drupal's multi-site directory aliasing feature.
- *
- * This file allows you to define a set of aliases that map hostnames, ports, and
- * pathnames to configuration directories in the sites directory. These aliases
- * are loaded prior to scanning for directories, and they are exempt from the
- * normal discovery rules. See default.settings.php to view how Drupal discovers
- * the configuration directory when no alias is found.
- *
- * Aliases are useful on development servers, where the domain name may not be
- * the same as the domain of the live server. Since Drupal stores file paths in
- * the database (files, system table, etc.) this will ensure the paths are
- * correct when the site is deployed to a live server.
- *
- * To use this file, copy and rename it such that its path plus filename is
- * 'sites/sites.php'. If you don't need to use multi-site directory aliasing,
- * then you can safely ignore this file, and Drupal will ignore it too.
- *
- * Aliases are defined in an associative array named $sites. The array is
- * written in the format: '<port>.<domain>.<path>' => 'directory'. As an
- * example, to map http://www.drupal.org:8080/mysite/test to the configuration
- * directory sites/example.com, the array should be defined as:
- * @code
- * $sites = array(
- *   '8080.www.drupal.org.mysite.test' => 'example.com',
- * );
- * @endcode
- * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or
- * an Apache Alias directive that points to the Drupal root containing
- * index.php. An alias could also be created for a subdomain. See the
- * @link http://drupal.org/documentation/install online Drupal installation guide @endlink
- * for more information on setting up domains, subdomains, and subdirectories.
- *
- * The following examples look for a site configuration in sites/example.com:
- * @code
- * URL: http://dev.drupal.org
- * $sites['dev.drupal.org'] = 'example.com';
- *
- * URL: http://localhost/example
- * $sites['localhost.example'] = 'example.com';
- *
- * URL: http://localhost:8080/example
- * $sites['8080.localhost.example'] = 'example.com';
- *
- * URL: http://www.drupal.org:8080/mysite/test/
- * $sites['8080.www.drupal.org.mysite.test'] = 'example.com';
- * @endcode
- *
- * @see default.settings.php
- * @see conf_path()
- * @see http://drupal.org/documentation/install/multi-site
- */
