Preparation

Besides all standard system requirements like PHP (>=7.3), a web server like Apache or Ngnix, and a database (e.g., MySQL), you need to have composer installed on your local machine. If you haven't, take a look at the installation instructions on the official site.

Download Drupal 9 via composer

Since Drupal 8.8.0, there is an official composer template to download the Drupal core and all its dependencies. So, it's not recommended to use the inofficial composer drupal-project anymore. There are a few differences between them both, but in the end, it's just about the (not) installed vendor packages. Open your terminal and let composer do the work.

$ composer create-project drupal/recommended-project YOUR_DIR

This composer command will download the core and all dependencies into YOUR_DIR. It'll also configure some stuff you'll need in your composer.json.

Use Drush to install Drupal

Now that is everything in place you have to install Drupal. One way is the install script, which will start if you visit your site URL like myproject.local. I prefer to use Drush – the Drupal shell. The new recommended-projectdoesn't include drush by default, so we have to require it.

$ cd YOUR_DIR
$ composer require drush/drush:^10

We will use the standard installation profile, feel free to choose whatever fits your needs. You also need to have your database and related credentials ready.

$ drush site-install standard \
  --db-url='mysql://[DB_USER]:[DB_PASS]@[DB_HOST]:[DB_PORT]/[DB_NAME]' \
  --account-name=ADMIN-NAME --account-pass=YOUR-PW \
  --site-name=WEBSITE-NAME \
  --site-mail=WEBSITE@MAIL.COM \

Adjust (development) settings

I assume we're setting up Drupal for local development stuff here, but of course, you can adjust these settings for production or staging environments.

$ chmod +w web/sites/default
$ mkdir web/sites/default/settings
$ cd web/sites/default
$ cp settings.php settings/settings.shared.php
$ chmod 644 settings/settings.shared.php

First, we make the sites/default directory writeable and create a new subfolder sites/default/settings. After that, we copy the settings.php generated while the installation process to this new folder and call it settings.shared.php. Why? Because we want to split our settings into two separate files so that we can easily change environment settings. Another way of doing this would be to use an .env file. Feel free to choose any method.

Next, we're going to replace all content within the standard settings.php and include our newly generated settings.shared.php.

/web/sites/default/settings.php

<?php

include __DIR__ . '/settings/settings.shared.php';

In our shared settings file, add the settings for trusted_host_patterns (for security reasons).

/web/sites/default/settings/settings.shared.php

<?php
// ... Tons of lines before
// ...
$settings['trusted_host_patterns'] = [
  '^localhost$',
  '^127.0.0.1$',
  'example\.local$',
  'staging\.example\.com$',
  'example\.com$',
];

Next, we need to include the local settings file, which we will create after that.

// ... At the BOTTOM of settings.shared.php
if (file_exists($app_root . '/' . $site_path . '/settings/settings.local.php')) {
  include $app_root . '/' . $site_path . '/settings/settings.local.php';
}
$ cd ../..
$ cp sites/example.settings.local.php sites/default/settings/settings.local.php

Now, move your local database settings array from /web/sites/default/settings/settings.shared.php to our new /web/sites/default/settings/settings.local.php.

/web/sites/default/settings/settings.local.php

<?php
 $databases['default']['default'] = [
   'database' => 'YOUR-DB-NAME',
   'username' => 'YOUR-DB-USER',
   'password' => 'YOUR-USER-PASSWORD',
   'prefix' => '',
   'host' => 'localhost',
   'port' => '3306',
   'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
   'driver' => 'mysql',
];

For local development, you need to include your development.services.yml file, turn off render and page caching, enable verbose error logging, and disable JavaScript and CSS preprocessing. To do so, add these lines below your database array.

// ... Database array ...

// Load development service file
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';

// Disable caches
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['page'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';

// Enable verbose error logging
$config['system.logging']['error_level'] = 'verbose';

// Disable CSS and JS preprocessing
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;

Now we need to disable the Twig caching via the included /web/sites/default/development.services.yml. Your file should look like this:

parameters:
  http.response.debug_cacheability_headers: true
  twig.config:
    debug: true
    auto_reload: true
services:
  cache.backend.null:
    class: Drupal\Core\Cache\NullBackendFactory

It's time to clear the Drupal cache to be sure our new settings will be applied!

$ drush cr

Now your Drupal 9 installation should be ready, and all settings should be suitable to start local development. But caution! You need to do two more things to secure your installation!

First, give your files directory and your settings.php the right permissions:

$ chmod go-w sites/default/settings.php
$ chmod go-w sites/default

And as always, never commit a settings file to your git repository! So add our new local settings file to the .gitignore in the root directory.

# Ignore configuration files that may contain sensitive information.
/web/sites/*/settings/settings.local.php