Drupal Installation and Setup
Drupal is installed via Composer — no manual ZIP downloads. This is a mandatory requirement from Drupal 9+: without Composer, you can't properly update the core and modules.
Server Requirements
- PHP 8.2+ with extensions:
pdo_pgsqlorpdo_mysql,gd,intl,mbstring,xml,json,opcache - PostgreSQL 14+ or MySQL 8.0+ / MariaDB 10.6+
- Composer 2.x
- Nginx or Apache
Recommended PHP settings (php.ini):
memory_limit = 256M
max_execution_time = 60
upload_max_filesize = 32M
post_max_size = 32M
opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 10000
Creating a Project
composer create-project drupal/recommended-project:^10 my-site
cd my-site
# Essential tools
composer require drush/drush
Directory structure after installation:
my-site/
├── composer.json
├── composer.lock
├── config/
│ └── sync/ # configuration in YAML
├── vendor/
└── web/ # document root
├── core/
├── modules/
│ ├── contrib/ # downloaded modules
│ └── custom/ # your code
├── profiles/
├── themes/
│ ├── contrib/
│ └── custom/
└── sites/
└── default/
├── settings.php
└── files/ # uploaded files
Server document root should point to web/, not the project root.
Database Setup
# PostgreSQL
createuser -P drupal
createdb -O drupal drupal
# MySQL
mysql -u root -e "CREATE DATABASE drupal; CREATE USER drupal@localhost IDENTIFIED BY 'password'; GRANT ALL ON drupal.* TO drupal@localhost;"
Installation via Drush (without web installer)
./vendor/bin/drush site:install standard \
--account-name=admin \
--account-pass='StrongPassword123!' \
[email protected] \
--site-name="My Site" \
[email protected] \
--locale=en \
--db-url="pgsql://drupal:password@localhost/drupal" \
--no-interaction
The standard option — basic profile with the most commonly used modules. There's also minimal (bare core) and demo_umami (demo content for getting acquainted).
settings.php Configuration
// web/sites/default/settings.php
// Configuration directory (outside document root — important for security)
$settings['config_sync_directory'] = '../config/sync';
// Trusted hosts — mandatory for production
$settings['trusted_host_patterns'] = [
'^example\.com$',
'^www\.example\.com$',
];
// Disable error display on production
$config['system.logging']['error_level'] = 'hide';
// Hash salt — generated on install, never change after
$settings['hash_salt'] = 'generated-value-from-secrets';
// Private file directory (not accessible via web)
$settings['file_private_path'] = '../private';
For local development and production, export different settings to settings.local.php:
// settings.php — at the end of file
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}
// settings.local.php — don't commit to git
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
$settings['extension_discovery_scan_tests'] = FALSE;
Nginx Configuration
server {
listen 80;
server_name example.com www.example.com;
root /var/www/my-site/web;
index index.php;
# Drupal clean URLs
location / {
try_files $uri /index.php?$query_string;
}
# Deny access to system files
location ~ (^|/)\. {
return 403;
}
location ~ ^/sites/.*/private/ {
return 403;
}
location ~ ^/sites/[^/]+/files/.*\.php$ {
deny all;
}
# PHP
location ~ '\.php$|^/update.php' {
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 300;
}
# Static files
location ~* \.(jpg|jpeg|gif|png|webp|svg|css|js|ico|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri @drupal;
}
location @drupal {
rewrite ^/(.*)$ /index.php?q=$1 last;
}
}
Base Modules After Installation
# Enable core modules
drush en \
language locale content_translation \
path pathauto token \
views views_ui \
field_ui block_content \
menu_link_content \
-y
# Contrib modules
composer require drupal/admin_toolbar drupal/metatag drupal/redirect drupal/pathauto
drush en admin_toolbar admin_toolbar_tools metatag redirect -y
Updating Drupal
# Check available updates
composer outdated drupal/*
# Update core
composer update drupal/core-recommended drupal/core-composer-scaffold --with-all-dependencies
# Apply database updates
drush updatedb --no-interaction
drush cache:rebuild
Timelines
Clean installation, server setup, basic modules, initial configuration: 1 day. With existing content migration and multilingual setup: 2–3 days.







