diff --git a/core/core.services.yml b/core/core.services.yml
index 5959c44..3ce5a43 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -136,7 +136,7 @@ services:
     arguments: ['@database', '@cache_tags.invalidator.checksum']
   cache.backend.apcu:
     class: Drupal\Core\Cache\ApcuBackendFactory
-    arguments: ['@app.root', '@cache_tags.invalidator.checksum']
+    arguments: ['@app.root', '@site.path', '@cache_tags.invalidator.checksum']
   cache.backend.php:
     class: Drupal\Core\Cache\PhpBackendFactory
     arguments: ['@cache_tags.invalidator.checksum']
@@ -550,6 +550,17 @@ services:
     class: Drupal\Core\AppRootFactory
     arguments: ['@kernel']
     public: false
+  site.path:
+    class: SplString
+    factory_service: 'site.path.factory'
+    factory_method: 'getForRequestStack'
+    arguments: ['@request_stack']
+    tags:
+      - { name: parameter_service }
+  site.path.factory:
+    class: Drupal\Core\SitePathFactory
+    arguments: ['@app.root']
+    public: false
   controller_resolver:
     class: Drupal\Core\Controller\ControllerResolver
     arguments: ['@class_resolver']
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index d858875..b7de5d7 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -313,7 +313,9 @@ function install_begin_request($class_loader, &$install_state) {
     exit;
   }
 
-  $site_path = DrupalKernel::findSitePath($request, FALSE);
+  // @todo: Come up with a better way to figure out DRUPAL_ROOT.
+  $site_path_factory = new SitePathFactory(DRUPAL_ROOT);
+  $site_path = $site_path_factory->findSitePath($request, FALSE);
   Settings::initialize(dirname(dirname(__DIR__)), $site_path, $class_loader);
 
   // Ensure that procedural dependencies are loaded as early as possible,
@@ -361,7 +363,7 @@ function install_begin_request($class_loader, &$install_state) {
 
   // Determine whether base system services are ready to operate.
   $install_state['config_verified'] = install_ensure_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_ensure_config_directory(CONFIG_STAGING_DIRECTORY);
-  $install_state['database_verified'] = install_verify_database_settings();
+  $install_state['database_verified'] = install_verify_database_settings($site_path);
   $install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified'];
 
   // Install factory tables only after checking the database.
@@ -1066,11 +1068,17 @@ function install_verify_completed_task() {
 
 /**
  * Verifies that settings.php specifies a valid database connection.
+ *
+ * @param string $site_path
+ *  The site path.
+ *
+ * @return bool
+ *  TRUE if there are no database errors.
  */
-function install_verify_database_settings() {
+function install_verify_database_settings($site_path) {
   if ($database = Database::getConnectionInfo()) {
     $database = $database['default'];
-    $settings_file = './' . conf_path(FALSE) . '/settings.php';
+    $settings_file = './' . $site_path . '/settings.php';
     $errors = install_database_errors($database, $settings_file);
     if (empty($errors)) {
       return TRUE;
@@ -1891,8 +1899,9 @@ function install_check_translations($langcode, $server_pattern) {
   $readable = FALSE;
   $writable = FALSE;
   // @todo: Make this configurable.
-  $files_directory = conf_path() . '/files';
-  $translations_directory = conf_path() . '/files/translations';
+  $conf_path = \Drupal::service('site.path');
+  $files_directory =  $conf_path . '/files';
+  $translations_directory = $conf_path . '/files/translations';
   $translations_directory_exists = FALSE;
   $translation_available = FALSE;
   $online = FALSE;
@@ -2070,7 +2079,7 @@ function install_check_requirements($install_state) {
   foreach ($default_files as $default_file_info) {
     $readable = FALSE;
     $writable = FALSE;
-    $conf_path = './' . conf_path(FALSE);
+    $conf_path = './' . \Drupal::service('site.path');
     $file = $conf_path . "/{$default_file_info['file']}";
     $default_file = "./sites/default/{$default_file_info['file_default']}";
     $exists = FALSE;
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 7e0e32e..e301dee 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -197,7 +197,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 = \Drupal::service('site.path') . '/settings.php';
   }
   // Build list of setting names and insert the values into the global namespace.
   $variable_names = array();
@@ -470,13 +470,13 @@ function drupal_install_config_directories() {
   $config_directories_hash = Crypt::randomBytesBase64(55);
   if (empty($config_directories[CONFIG_ACTIVE_DIRECTORY])) {
     $settings['config_directories'][CONFIG_ACTIVE_DIRECTORY] = (object) [
-      'value' => conf_path() . '/files/config_' . $config_directories_hash . '/active',
+      'value' => \Drupal::service('site.path') . '/files/config_' . $config_directories_hash . '/active',
       'required' => TRUE,
     ];
   }
   if (empty($config_directories[CONFIG_STAGING_DIRECTORY])) {
     $settings['config_directories'][CONFIG_STAGING_DIRECTORY] = (object) [
-      'value' => conf_path() . '/files/config_' . $config_directories_hash . '/staging',
+      'value' => \Drupal::service('site.path') . '/files/config_' . $config_directories_hash . '/staging',
       'required' => TRUE,
     ];
   }
diff --git a/core/includes/utility.inc b/core/includes/utility.inc
index ff65dc8..4a94357 100644
--- a/core/includes/utility.inc
+++ b/core/includes/utility.inc
@@ -9,6 +9,7 @@
 use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\DrupalKernel;
+use Drupal\Core\SitePathFactory;
 use Symfony\Component\HttpFoundation\Request;
 use Composer\Autoload\ClassLoader;
 
@@ -35,7 +36,10 @@ function drupal_rebuild(ClassLoader $class_loader, Request $request) {
 
   // Bootstrap up to where caches exist and clear them.
   $kernel = new DrupalKernel('prod', $class_loader);
-  $kernel->setSitePath(DrupalKernel::findSitePath($request));
+  // @todo: Come up with a better way to figure out DRUPAL_ROOT.
+  $site_path_factory = new SitePathFactory(DRUPAL_ROOT);
+  $site_path = $site_path_factory->getForRequest($request);
+  $kernel->setSitePath($site_path_factory());
   $kernel->prepareLegacyRequest($request);
 
   foreach (Cache::getBins() as $bin) {
diff --git a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
index bbc4e3d..f8814fc 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackendFactory.php
@@ -30,11 +30,13 @@ class ApcuBackendFactory implements CacheFactoryInterface {
    *
    * @param string $root
    *   The app root.
+   * @param string $site_path
+   *   The site path.
    * @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
    *   The cache tags checksum provider.
    */
-  public function __construct($root, CacheTagsChecksumInterface $checksum_provider) {
-    $this->sitePrefix = Crypt::hashBase64($root . '/' . conf_path());
+  public function __construct($root, $site_path, CacheTagsChecksumInterface $checksum_provider) {
+    $this->sitePrefix = Crypt::hashBase64($root . '/' . $site_path);
     $this->checksumProvider = $checksum_provider;
   }
 
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 89d4069..68324b2 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
@@ -48,7 +48,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) . '/files/.ht.sqlite';
+    $default_database = \Drupal::service('site.path') . '/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 557dfd1..d578b24 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -224,8 +224,9 @@ public static function createFromRequest(Request $request, $class_loader, $envir
     static::bootEnvironment();
 
     // Get our most basic settings setup.
-    $site_path = static::findSitePath($request);
-    $kernel->setSitePath($site_path);
+    // @todo: Come up with a better way to figure out DRUPAL_ROOT.
+    $site_path_factory = new SitePathFactory(DRUPAL_ROOT);
+    $site_path = $site_path_factory->getForRequest($request);
     Settings::initialize(dirname($core_root), $site_path, $class_loader);
 
     // Initialize our list of trusted HTTP Host headers to protect against
@@ -285,98 +286,6 @@ public function __construct($environment, $class_loader, $allow_dumping = TRUE)
   }
 
   /**
-   * Returns the appropriate site directory for a request.
-   *
-   * Once the kernel has been created DrupalKernelInterface::getSitePath() is
-   * preferred since it gets the statically cached result of this method.
-   *
-   * Site directories contain all site specific code. This includes settings.php
-   * for bootstrap level configuration, file configuration stores, public file
-   * storage and site specific modules and themes.
-   *
-   * Finds a matching site 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 'sites/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 sites directory, 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 \Symfony\Component\HttpFoundation\Request $request
-   *   The current request.
-   * @param bool $require_settings
-   *   Only 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 directory.
-   *
-   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
-   *   In case the host name in the request is invalid.
-   *
-   * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
-   * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
-   * @see default.settings.php
-   * @see example.sites.php
-   */
-  public static function findSitePath(Request $request, $require_settings = TRUE) {
-    if (static::validateHostname($request) === FALSE) {
-      throw new BadRequestHttpException();
-    }
-
-    // Check for a simpletest override.
-    if ($test_prefix = drupal_valid_test_ua()) {
-      return 'sites/simpletest/' . substr($test_prefix, 10);
-    }
-
-    // Determine whether multi-site functionality is enabled.
-    if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
-      return 'sites/default';
-    }
-
-    // Otherwise, use find the site path using the request.
-    $script_name = $request->server->get('SCRIPT_NAME');
-    if (!$script_name) {
-      $script_name = $request->server->get('SCRIPT_FILENAME');
-    }
-    $http_host = $request->getHost();
-
-    $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';
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function setSitePath($path) {
diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
index 4681977..a976ccc 100644
--- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
+++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\Core\Extension;
 
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Discovers available extensions in the filesystem.
@@ -152,8 +154,14 @@ public function scan($type, $include_tests = NULL) {
       $searchdirs[static::ORIGIN_PARENT_SITE] = $parent_site;
     }
 
-    // Search the site-specific directory.
-    $searchdirs[static::ORIGIN_SITE] = conf_path();
+    // Find the site-specific directory to search. Kernel service is not always
+    // available at this point, but is preferred, when available.
+    if (\Drupal::hasService('kernel')) {
+      $searchdirs[static::ORIGIN_SITE] = \Drupal::service('site.path');
+    }
+    else {
+      $searchdirs[static::ORIGIN_SITE] = DrupalKernel::findSitePath(Request::createFromGlobals());
+    }
 
     // Unless an explicit value has been passed, manually check whether we are
     // in a test environment, in which case test extensions must be included.
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index 0354e25..b0b2efb 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -21,6 +21,13 @@
 class SiteConfigureForm extends ConfigFormBase {
 
   /**
+   * The site path.
+   *
+   * @var string
+   */
+  protected $sitePath;
+
+  /**
    * The user storage.
    *
    * @var \Drupal\user\UserStorageInterface
@@ -60,6 +67,8 @@ class SiteConfigureForm extends ConfigFormBase {
    *
    * @param string $root
    *   The app root.
+   * @param string $site_path
+   *   The site path.
    * @param \Drupal\user\UserStorageInterface $user_storage
    *   The user storage.
    * @param \Drupal\Core\State\StateInterface $state
@@ -69,8 +78,9 @@ class SiteConfigureForm extends ConfigFormBase {
    * @param \Drupal\Core\Locale\CountryManagerInterface $country_manager
    *   The country manager.
    */
-  public function __construct($root, UserStorageInterface $user_storage, StateInterface $state, ModuleInstallerInterface $module_installer, CountryManagerInterface $country_manager) {
+  public function __construct($root, $site_path, UserStorageInterface $user_storage, StateInterface $state, ModuleInstallerInterface $module_installer, CountryManagerInterface $country_manager) {
     $this->root = $root;
+    $this->sitePath = $site_path;
     $this->userStorage = $user_storage;
     $this->state = $state;
     $this->moduleInstaller = $module_installer;
@@ -83,6 +93,7 @@ public function __construct($root, UserStorageInterface $user_storage, StateInte
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('app.root'),
+      $container->get('site.path'),
       $container->get('entity.manager')->getStorage('user'),
       $container->get('state'),
       $container->get('module_installer'),
@@ -115,7 +126,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Configure site');
 
     // Warn about settings.php permissions risk
-    $settings_dir = conf_path();
+    $settings_dir = $this->sitePath;
     $settings_file = $settings_dir . '/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
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
index 8cf65c9..30509ce 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a form to configure and rewrite settings.php.
@@ -18,6 +19,32 @@
 class SiteSettingsForm extends FormBase {
 
   /**
+   * The site path.
+   *
+   * @var string
+   */
+  protected $sitePath;
+
+  /**
+   * Constructs a new SiteSettingsForm.
+   *
+   * @param string $site_path
+   *   The site path.
+   */
+  public function __construct($site_path) {
+    $this->sitePath = $site_path;
+}
+
+  /**
+    * {@inheritdoc}
+    */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('site.path')
+    );
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getFormId() {
@@ -28,7 +55,7 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $conf_path = './' . conf_path(FALSE);
+    $conf_path = './' . $this->sitePath;
     $settings_file = $conf_path . '/settings.php';
 
     $form['#title'] = $this->t('Database configuration');
diff --git a/core/lib/Drupal/Core/Site/Settings.php b/core/lib/Drupal/Core/Site/Settings.php
index a48946a..0da0eb6 100644
--- a/core/lib/Drupal/Core/Site/Settings.php
+++ b/core/lib/Drupal/Core/Site/Settings.php
@@ -116,7 +116,6 @@ public static function initialize($app_root, $site_path, &$class_loader) {
     $config = array();
     $databases = array();
 
-    // Make conf_path() available as local variable in settings.php.
     if (is_readable($app_root . '/' . $site_path . '/settings.php')) {
       require $app_root . '/' . $site_path . '/settings.php';
     }
diff --git a/core/lib/Drupal/Core/SitePathFactory.php b/core/lib/Drupal/Core/SitePathFactory.php
new file mode 100644
index 0000000..d39568f
--- /dev/null
+++ b/core/lib/Drupal/Core/SitePathFactory.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\SitePathFactory.
+ */
+
+namespace Drupal\Core;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Gets the site path from the kernel.
+ */
+class SitePathFactory {
+
+  /**
+   * The app root directory.
+   *
+   * @var SplString
+   */
+  protected $appRoot;
+
+  /**
+   * Constructs an SitePathFactory instance.
+   *
+   * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
+   *   The Drupal kernel.
+   */
+  public function __construct($app_root) {
+    $this->appRoot = $app_root;
+  }
+
+  /**
+   * Generate a site path based on a request object.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request.
+   *
+   * @return \SplString
+   *   The site path.
+   */
+  public function getForRequest(Request $request) {
+    return new \SplString($this->findSitePath($request));
+  }
+
+  /**
+   * Generate a site path based on a request stack.
+   *
+   * This method exists so that we can create the site path as a service using
+   * existing services. Since we have @request_stack and not @request, we have
+   * to get the current request from the stack.
+   *
+   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
+   *   The request.
+   *
+   * @return \SplString
+   *   The site path.
+   */
+  public function getForRequestStack(RequestStack $request_stack) {
+    $request = $request_stack->getCurrentRequest();
+    return $this->getForRequest($request);
+  }
+
+  /**
+   * Returns the appropriate site directory for a request.
+   *
+   * Once the kernel has been created DrupalKernelInterface::getSitePath() is
+   * preferred since it gets the statically cached result of this method.
+   *
+   * Site directories contain all site specific code. This includes settings.php
+   * for bootstrap level configuration, file configuration stores, public file
+   * storage and site specific modules and themes.
+   *
+   * Finds a matching site 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 'sites/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 sites directory, 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 \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param bool $require_settings
+   *   Only 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 directory.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   *   In case the host name in the request is invalid.
+   *
+   * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
+   * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
+   * @see default.settings.php
+   * @see example.sites.php
+   */
+  public function findSitePath(Request $request, $require_settings = TRUE) {
+    if (static::validateHostname($request) === FALSE) {
+      throw new BadRequestHttpException();
+    }
+
+    // Check for a simpletest override.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      return 'sites/simpletest/' . substr($test_prefix, 10);
+    }
+
+    // Determine whether multi-site functionality is enabled.
+    if (!file_exists($this->app_root . '/sites/sites.php')) {
+      return 'sites/default';
+    }
+
+    // Otherwise, use find the site path using the request.
+    $script_name = $request->server->get('SCRIPT_NAME');
+    if (!$script_name) {
+      $script_name = $request->server->get('SCRIPT_FILENAME');
+    }
+    $http_host = $request->getHost();
+
+    $sites = array();
+    include $this->app_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($this->app_root . '/sites/' . $sites[$dir])) {
+          $dir = $sites[$dir];
+        }
+        if (file_exists($this->app_root . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists($this->app_root . '/sites/' . $dir))) {
+          return "sites/$dir";
+        }
+      }
+    }
+    return 'sites/default';
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
index e2b78ec..c18e880 100644
--- a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
+++ b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php
@@ -8,7 +8,9 @@
 namespace Drupal\Core\StreamWrapper;
 
 use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Defines a Drupal public (public://) stream wrapper class.
@@ -61,8 +63,15 @@ 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');
-    return $base_path;
+    // Find the site path. Kernel service is not always available at this point,
+    // but is preferred, when available.
+    if (\Drupal::hasService('kernel')) {
+      $site_path = \Drupal::service('site.path');
+    }
+    else {
+      $site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
+    }
+    return Settings::get('file_public_path', $site_path . '/files');
   }
 
 }
diff --git a/core/modules/file/tests/file_test/src/StreamWrapper/DummyReadOnlyStreamWrapper.php b/core/modules/file/tests/file_test/src/StreamWrapper/DummyReadOnlyStreamWrapper.php
index 99cf3e8..cb8a6aa 100644
--- a/core/modules/file/tests/file_test/src/StreamWrapper/DummyReadOnlyStreamWrapper.php
+++ b/core/modules/file/tests/file_test/src/StreamWrapper/DummyReadOnlyStreamWrapper.php
@@ -31,7 +31,7 @@ public function getDescription() {
   }
 
   function getDirectoryPath() {
-    return conf_path() . '/files';
+    return \Drupal::service('site.path') . '/files';
   }
 
   /**
diff --git a/core/modules/file/tests/file_test/src/StreamWrapper/DummyStreamWrapper.php b/core/modules/file/tests/file_test/src/StreamWrapper/DummyStreamWrapper.php
index 2ed31d0..b2b6900 100644
--- a/core/modules/file/tests/file_test/src/StreamWrapper/DummyStreamWrapper.php
+++ b/core/modules/file/tests/file_test/src/StreamWrapper/DummyStreamWrapper.php
@@ -31,7 +31,7 @@ public function getDescription() {
   }
 
   function getDirectoryPath() {
-    return conf_path() . '/files';
+    return \Drupal::service('site.path') . '/files';
   }
 
   /**
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 81aadf5..c401316 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -15,7 +15,8 @@
 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';
+    $conf_path = \Drupal::service('site.path');
+    $directory = $conf_path . '/files/translations';
     \Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save();
   }
   file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index bd611f4..5da7fab 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\Variable;
+use Drupal\Core\SitePathFactory;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DrupalKernel;
@@ -181,8 +182,9 @@ protected function setUp() {
     $class_loader = require DRUPAL_ROOT . '/autoload.php';
     $this->kernel = new DrupalKernel('testing', $class_loader, FALSE);
     $request = Request::create('/');
-    $site_path = DrupalKernel::findSitePath($request);
-    $this->kernel->setSitePath($site_path);
+    // @todo: Come up with a better way to figure out DRUPAL_ROOT.
+    $site_path_factory = new SitePathFactory(DRUPAL_ROOT);
+    $site_path = $site_path_factory->getForRequest($request);
     if (file_exists($directory . '/settings.testing.php')) {
       Settings::initialize(DRUPAL_ROOT, $site_path, $class_loader);
     }
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 9a38774..8bb7536 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1140,7 +1140,8 @@ private function prepareEnvironment() {
     }
 
     // Backup current in-memory configuration.
-    $this->originalSite = conf_path();
+    $site_path = \Drupal::service('site.path');
+    $this->originalSite = $site_path;
     $this->originalSettings = Settings::getAll();
     $this->originalConfig = $GLOBALS['config'];
     // @todo Remove all remnants of $GLOBALS['conf'].
@@ -1155,7 +1156,7 @@ private 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_path . '/files');
     $this->originalProfile = drupal_get_profile();
     $this->originalUser = isset($user) ? clone $user : NULL;
 
@@ -1225,7 +1226,6 @@ private function prepareEnvironment() {
     // After preparing the environment and changing the database prefix, we are
     // in a valid test environment.
     drupal_valid_test_ua($this->databasePrefix);
-    conf_path(FALSE, TRUE);
 
     // Reset settings.
     new Settings(array(
@@ -1339,7 +1339,6 @@ private function restoreEnvironment() {
     else {
       drupal_valid_test_ua(FALSE);
     }
-    conf_path(TRUE, TRUE);
 
     // Restore original shutdown callbacks.
     $callbacks = &drupal_register_shutdown_function();
diff --git a/core/modules/simpletest/src/Tests/SimpleTestTest.php b/core/modules/simpletest/src/Tests/SimpleTestTest.php
index c650eef..2514d9d 100644
--- a/core/modules/simpletest/src/Tests/SimpleTestTest.php
+++ b/core/modules/simpletest/src/Tests/SimpleTestTest.php
@@ -161,6 +161,7 @@ function stubTest() {
     // @see drupal_generate_test_ua();
     $key_file = DRUPAL_ROOT . '/sites/simpletest/' . substr($this->databasePrefix, 10) . '/.htkey';
     $private_key = Crypt::randomBytesBase64(55);
+    $site_path = $this->container->get('site.path');
     file_put_contents($key_file, $private_key);
 
     // This causes the first of the fifteen passes asserted in
@@ -192,7 +193,7 @@ function stubTest() {
 
     // These cause the eleventh to fourteenth of the fifteen passes asserted in
     // confirmStubResults().
-    $this->assertTrue(file_exists(conf_path() . '/settings.testing.php'));
+    $this->assertTrue(file_exists($site_path . '/settings.testing.php'));
     // Check the settings.testing.php file got included.
     $this->assertTrue(function_exists('simpletest_test_stub_settings_function'));
     // Check that the test-specific service file got loaded.
diff --git a/core/modules/system/src/Tests/File/DirectoryTest.php b/core/modules/system/src/Tests/File/DirectoryTest.php
index 0822063..50d498a 100644
--- a/core/modules/system/src/Tests/File/DirectoryTest.php
+++ b/core/modules/system/src/Tests/File/DirectoryTest.php
@@ -19,7 +19,8 @@ class DirectoryTest extends FileTestBase {
    * Test local directory handling functions.
    */
   function testFileCheckLocalDirectoryHandling() {
-    $directory = conf_path() . '/files';
+    $site_path = $this->container->get('site.path');
+    $directory = $site_path . '/files';
 
     // Check a new recursively created local directory for correct file system
     // permissions.
diff --git a/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php b/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
index 242a378..d4e7e31 100644
--- a/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
+++ b/core/modules/system/src/Tests/File/ReadOnlyStreamWrapperTest.php
@@ -34,7 +34,8 @@ class ReadOnlyStreamWrapperTest extends FileTestBase {
   function testReadOnlyBehavior() {
     // Generate a test file
     $filename = $this->randomMachineName();
-    $filepath = conf_path() . '/files/' . $filename;
+    $site_path = $this->container->get('site.path');
+    $filepath = $site_path . '/files/' . $filename;
     file_put_contents($filepath, $filename);
 
     // Generate a read-only stream wrapper instance
@@ -79,7 +80,7 @@ function testReadOnlyBehavior() {
 
     // Test the mkdir() function by attempting to create a directory.
     $dirname = $this->randomMachineName();
-    $dir = conf_path() . '/files/' . $dirname;
+    $dir = $site_path . '/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/src/Tests/Installer/InstallerExistingSettingsTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsTest.php
index 25be1ef..ffda15b 100644
--- a/core/modules/system/src/Tests/Installer/InstallerExistingSettingsTest.php
+++ b/core/modules/system/src/Tests/Installer/InstallerExistingSettingsTest.php
@@ -9,6 +9,8 @@
 
 use Drupal\simpletest\InstallerTestBase;
 use Drupal\Core\Database\Database;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Tests the installer with an existing settings file.
@@ -48,14 +50,23 @@ protected function setUp() {
       'required' => TRUE,
     );
 
+    // Find the site path. Kernel service is not always available at this point,
+    // but is preferred, when available.
+    if (\Drupal::hasService('kernel')) {
+      $conf_path = \Drupal::service('site.path');
+    }
+    else {
+      $conf_path = DrupalKernel::findSitePath(Request::createFromGlobals());
+    }
+
     // Pre-configure config directories.
     $this->settings['config_directories'] = array(
       CONFIG_ACTIVE_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_active',
+        'value' => $conf_path . '/files/config_active',
         'required' => TRUE,
       ),
       CONFIG_STAGING_DIRECTORY => (object) array(
-        'value' => conf_path() . '/files/config_staging',
+        'value' => $conf_path . '/files/config_staging',
         'required' => TRUE,
       ),
     );
diff --git a/core/modules/system/src/Tests/System/SettingsRewriteTest.php b/core/modules/system/src/Tests/System/SettingsRewriteTest.php
index 70b4043..1446cbd 100644
--- a/core/modules/system/src/Tests/System/SettingsRewriteTest.php
+++ b/core/modules/system/src/Tests/System/SettingsRewriteTest.php
@@ -21,6 +21,7 @@ class SettingsRewriteTest extends KernelTestBase {
    */
   function testDrupalRewriteSettings() {
     include_once \Drupal::root() . '/core/includes/install.inc';
+    $site_path = $this->container->get('site.path');
     $tests = array(
       array(
         'original' => '$no_index_value_scalar = TRUE;',
@@ -99,7 +100,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_path . '/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");
@@ -117,7 +118,7 @@ function testDrupalRewriteSettings() {
       'expected' => '$no_index = true;'
     );
     // Make an empty file.
-    $filename = Settings::get('file_public_path', conf_path() . '/files') . '/mock_settings.php';
+    $filename = Settings::get('file_public_path', $site_path . '/files') . '/mock_settings.php';
     file_put_contents(\Drupal::root() . '/' . $filename, "");
 
     // Write the setting to the file.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index f1e6612..98b3d95 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -10,11 +10,13 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Url;
 use Drupal\Core\Database\Database;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PrivateStream;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\system\SystemRequirements;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Implements hook_requirements().
@@ -250,7 +252,14 @@ function system_requirements($phase) {
   // Test configuration files and directory for writability.
   if ($phase == 'runtime') {
     $conf_errors = array();
-    $conf_path = conf_path();
+    // Find the site path. Kernel service is not always available at this point,
+    // but is preferred, when available.
+    if (\Drupal::hasService('kernel')) {
+      $conf_path = \Drupal::service('site.path');
+    }
+    else {
+      $conf_path = DrupalKernel::findSitePath(Request::createFromGlobals());
+    }
     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));
     }
@@ -391,7 +400,9 @@ function system_requirements($phase) {
     else {
       // If we are installing Drupal, the settings.php file might not exist yet
       // in the intended site directory, so don't require it.
-      $directories[] = conf_path(FALSE) . '/files';
+      $request = Request::createFromGlobals();
+      $conf_path = DrupalKernel::findSitePath($request);
+      $directories[] = $conf_path . '/files';
     }
     if ($file_private_path = Settings::get('file_private_path')) {
       $directories[] = $file_private_path;
@@ -418,7 +429,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' => $conf_path . '/settings.php')),
       'severity' => REQUIREMENT_ERROR,
     );
   }
diff --git a/core/modules/update/src/Form/UpdateManagerInstall.php b/core/modules/update/src/Form/UpdateManagerInstall.php
index 43d1f62..1703ab3 100644
--- a/core/modules/update/src/Form/UpdateManagerInstall.php
+++ b/core/modules/update/src/Form/UpdateManagerInstall.php
@@ -34,16 +34,26 @@ class UpdateManagerInstall extends FormBase {
   protected $root;
 
   /**
+   * The site path.
+   *
+   * @var string
+   */
+  protected $sitePath;
+
+  /**
    * Constructs a new UpdateManagerInstall.
    *
    * @param string $root
    *   The app root.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param string $site_path
+   *   The site path.
    */
-  public function __construct($root, ModuleHandlerInterface $module_handler) {
+  public function __construct($root, ModuleHandlerInterface $module_handler, $site_path) {
     $this->root = $root;
     $this->moduleHandler = $module_handler;
+    $this->sitePath = $site_path;
   }
 
   /**
@@ -59,7 +69,8 @@ public function getFormID() {
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('app.root'),
-      $container->get('module_handler')
+      $container->get('module_handler'),
+      $container->get('site.path')
     );
   }
 
@@ -217,7 +228,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     // 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($this->sitePath)) {
       $this->moduleHandler->loadInclude('update', 'inc', 'update.authorize');
       $filetransfer = new Local($this->root);
       call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
diff --git a/core/modules/update/src/Form/UpdateReady.php b/core/modules/update/src/Form/UpdateReady.php
index 8e106fe..ba1e12f 100644
--- a/core/modules/update/src/Form/UpdateReady.php
+++ b/core/modules/update/src/Form/UpdateReady.php
@@ -42,6 +42,13 @@ class UpdateReady extends FormBase {
   protected $state;
 
   /**
+   * The Site path.
+   *
+   * @var string
+   */
+   protected $sitePath;
+
+  /**
    * Constructs a new UpdateReady object.
    *
    * @param string $root
@@ -50,11 +57,14 @@ class UpdateReady extends FormBase {
    *   The object that manages enabled modules in a Drupal installation.
    * @param \Drupal\Core\State\StateInterface $state
    *   The state key value store.
+   * @param string $site_path
+   *   The site path.
    */
-  public function __construct($root, ModuleHandlerInterface $module_handler, StateInterface $state) {
+  public function __construct($root, ModuleHandlerInterface $module_handler, StateInterface $state, $site_path) {
     $this->root = $root;
     $this->moduleHandler = $module_handler;
     $this->state = $state;
+    $this->sitePath = $site_path;
   }
 
   /**
@@ -71,7 +81,8 @@ public static function create(ContainerInterface $container) {
     return new static(
       $container->get('app.root'),
       $container->get('module_handler'),
-      $container->get('state')
+      $container->get('state'),
+      $container->get('site.path')
     );
   }
 
@@ -142,7 +153,7 @@ public function submitForm(array &$form, FormStateInterface $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($this->sitePath)) {
         $this->moduleHandler->loadInclude('update', 'inc', 'update.authorize');
         $filetransfer = new Local($this->root);
         update_authorize_run_update($filetransfer, $updates);
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 0c7b0af..a863a56 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -306,7 +306,8 @@ 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());
+  $conf_path = \Drupal::service('site.path');
+  $local_transfers_allowed = fileowner($temporary_file) === fileowner($conf_path);
 
   // Clean up. If this fails, we can ignore it (since this is just a temporary
   // file anyway).
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 3783d0a..9349f7b 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -48,7 +48,7 @@
  * sites/8080.www.drupal.org.mysite.test/.
  *
  * @see example.sites.php
- * @see conf_path()
+ * @see \Drupal\Core\DrupalKernel::getSitePath()
  *
  * In addition to customizing application settings through variables in
  * settings.php, you can create a services.yml file in the same directory to
