Install and Secure your Drupal website
Introduction
Drupal is a robust, open-source content management system (CMS) favored for building complex websites and web applications. Its modular architecture, coupled with a vast ecosystem of add-on modules, offers unparalleled flexibility and customization. However, like any sophisticated web application, Drupal demands careful configuration and security hardening to mitigate potential vulnerabilities.
This comprehensive guide provides a step-by-step walkthrough of installing Drupal 10 from scratch within a Linux environment. It further delves into essential security measures designed to lock down access and safeguard against common web exploits. By the end of this guide, you’ll have a fully functional Drupal site, primed for development and fortified with a solid security foundation.
Prerequisites
Before embarking on the Drupal installation, ensure your Linux server meets the following prerequisites:
- A running Linux server (Ubuntu, Debian, CentOS, or Red Hat are common choices).
- Sufficient server resources (RAM and CPU) based on your expected traffic.
- Root or sudo privileges.
- Basic command-line knowledge.
Also, make sure you have an available domain or subdomain that points to your server’s IP address.
Log in as a non-root user with sudo privileges to perform the installation.
Step 1 – Install LAMP Stack
Drupal relies on the Linux, Apache, MySQL/MariaDB, PHP (LAMP) stack to operate. Execute the following commands to install these essential components:
$ sudo apt update
$ sudo apt install apache2 mariadb-server php php-mysql php-json php-gd php-mbstring php-xml php-curl
Install other required PHP extensions:
$ sudo apt install php-zip php-soap php-gd
Enable Apache modules needed by Drupal:
$ sudo a2enmod rewrite headers env dir mime
Secure MySQL installation:
$ sudo mysql_secure_installation
Start MySQL and Apache services:
$ sudo systemctl start mysql
$ sudo systemctl start apache2
Check that Apache is running properly by accessing your server’s domain or IP address in your browser. You should see the default Apache page.
Step 2 – Download Drupal
First, navigate to the Drupal downloads page and get the latest Drupal 10 release:
$ cd /tmp
$ wget https://www.drupal.org/download-latest/tar.gz
Extract the tar.gz file into the Apache web root directory:
$ sudo tar -xvf drupal-10*.tar.gz -C /var/www/html
The extracted directory will be named something like drupal-10.1.6
. Rename it to simply drupal
:
$ sudo mv /var/www/html/drupal-10.1.6 /var/www/html/drupal
Set ownership to the web server user:
$ sudo chown -R www-data:www-data /var/www/html/drupal
Adjust file permissions:
$ sudo chmod -R 775 /var/www/html/drupal
Drupal 10 files are now in place and ready for installation.
Step 3 – Create MySQL Database
Log in to MySQL prompt:
$ mysql -u root -p
Create a database and user for Drupal:
CREATE DATABASE drupal10db;
CREATE USER 'drupal10user'@'localhost' IDENTIFIED BY 'DBpa55word';
GRANT ALL ON drupal10db.* TO 'drupal10user'@'localhost';
exit
Replace ‘DBpa55word’ with a secure password.
This creates a dedicated DB user with full privileges for Drupal database.
Step 4 – Configure Apache Virtual Host
Create Drupal virtual host config:
$ sudo nano /etc/apache2/sites-available/drupal10.conf
Add the following, updating paths/domains as needed:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot "/var/www/drupal10/web"
ServerName drupal10.example.com
<Directory /var/www/drupal10/web>
Options FollowSymlinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/drupal10-error.log
CustomLog ${APACHE_LOG_DIR}/drupal10-access.log combined
</VirtualHost>
Enable the new virtual host and restart Apache:
$ sudo a2ensite drupal10.conf
$ sudo systemctl restart apache2
Step 5 – Install Drupal
Access your domain in a web browser and start Drupal 10 installation.
Select language then choose Standard installation profile.
On the Verify requirements page, ensure all items are checked. Resolve any issues listed.
For the database configuration use the MySQL database, user, and password created earlier.
IMPORTANT: Disable sending usage statistics to contribute Drupal improvements. This helps protect privacy.
Create a site name, default admin user, and strong password.
Wait for installation to complete then log in with the admin user.
The base Drupal site is now installed and ready for development!
Step 6 – Configure Security Settings
After installation, it’s important to review security-related settings and apply best practices to lock down Drupal.
In Administration sidebar, go to Configuration > System > Basic site settings then under Front page content set homepage to be a blank page.
Still under System, go to Cron and enable Cron handling. This is needed for scheduled tasks.
Under Content authoring section, go to Text formats and configure
- Limit HTML tags allowed in text formats.
- Enable HTML filtering.
This helps prevent XSS issues when allowing users to post content.
Next, under Media, disable the Local files source. Instead, configure cloud storage for uploads like S3 or equivalent.
Under Configuration > Media > File system, set the Default download method to Privately accessible files.
For higher security, in Configuration > Media settings set Public file system path to private://
This prevents accessing uploaded file paths directly through the site URL.
In Configuration > System > File system ensure the sites/default/files Public file system path is set to private://
This prevents accessing site file assets directly through the site URL.
Under Configuration > System > Logging and errors enable verbose Database logging, Failed login attempts and Page not found errors.
Still under Logging and errors, click Clean URLs Ensure “Enable clean URLs” checkbox is ticked. This improves SEO
Scroll down to Bandwidth optimization section and enable the following:
- Aggregate CSS files.
- Aggregate JavaScript files.
This reduces requests and improves performance.
In Configuration > SEO start by setting a site Default front page title, Default
Under Search engine optimization tick the checkbox for “Generate meta tags” Enable clean URLs and the globe favicon.
For social media, configure Facebook and Twitter options.
In Configuration > System > PHP set Uploads directory outside web root to sites/default/files/private
This prevents accessing uploaded files directly through URL path.
Set Max POST size and Max file upload size to align with site requirements.
Important: To apply the above changes either:
- Clear all caches via admin interface
- Run
drush cr
via command line.
This will clear caches and rebuild routes for the changes to take effect.
Step 7 – Review Permissions
Since Drupal requires write access to certain directories, permissions should be properly configured based on least privilege principles.
Check write permissions are set only on required directories:
$ sudo chown -R www-data:www-data /var/www/drupal10/web/sites/default
$ sudo find /var/www/drupal10/web/sites/default -type d -exec chmod 775 {} ;
$ sudo find /var/www/drupal10/web/sites/default -type f -exec chmod 664 {} ;
Set recommended file system permissions:
$ sudo find /var/www/drupal10/web -type d -exec chmod 755 {} ;
$ sudo find /var/www/drupal10/web -type f -exec chmod 644 {} ;
Secure the settings.php file:
$ sudo chmod 444 /var/www/drupal10/web/sites/default/settings.php
Constant review of file permissions is important to avoid insecure defaults.
Step 8 – Secure The Database
Since the database stores sensitive data, take precautions to prevent data loss or breaches:
- Use strong database passwords.
- Restrict database access to authorized users/IP addresses.
- Encrypt database connections.
Follow backups best practices:
- Automated daily/weekly backups.
- Offsite storage of backups.
- Test restoration process.
This protects against data loss from user errors, system crashes or ransomware attacks.
Step 9 – Secure The Web Server
Since Apache server will be Internet-facing it requires robust protections:
Disable unused modules to reduce attack surface area:
$ sudo a2dismod status actions alias autoindex
Configure mod_security Web Application Firewall (WAF) to filter traffic:
$ sudo apt install modsecurity libapache2-mod-security2
$ sudo nano /etc/modsecurity/modsecurity.conf
Enable mod_security rules engine:
SecRuleEngine On
Proxy traffic via a Web Application Firewall (WAF) for deep package inspection:
$ sudo apt install mod_security crudini
$ crudini --set /etc/modsecurity/modsecurity.conf
owasp.crs components.response.body_access false
$ sudo systemctl restart apache2
Use HTTPS with a valid SSL certificate to enable encryption. Redirect all traffic to HTTPS version.
Harden the site with additional security headers:
$ sudo nano /etc/apache2/sites-available/drupal10.conf
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
Header set X-Content-Type-Options "nosniff"
Header set Referrer-Policy "same-origin"
Header always append X-Frame-Options SAMEORIGIN
Save file and restart Apache.
This helps guard against common XSS, clickjacking and MIME attacks.
For performance, enable browser caching of static assets:
<FilesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|webp|js|css|swf)(.gz)?$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
604800 seconds = 1 week. This avoids re-downloading unchanged assets.
Monitor site traffic logs for anomalies indicating attacks. Implement log analysis and alerting.
Stay up to date on Drupal security advisories and apply latest patches.
Step 10 – Automate Drupal Cron
Cron manages scheduled tasks like caching, updates, data optimization.
Option 1 – Run cron manually
Enable crontab access for web server user:
$ sudo crontab -u www-data -e
Add cron entry:
* * * * * /usr/bin/php /var/www/drupal10/web/core/scripts/cron.sh >> /var/www/drupal10/cron.log
Option 2 – Automated cron
Use Drupal Queue Cron module to trigger cron without sys admin access
$ composer require drupal/queue_cron
$ drush en -y queue_cron
Adjust cron settings in Drupal UI at admin/config/system/cron.
Option 3 – Use system cron daemon
$ sudo systemctl edit cron
Paste:
[Service]
User=www-data
Save and exit.
$ sudo systemctl restart cron
This runs cron jobs as web server user.
Adjust cron settings in Drupal UI at admin/config/system/cron.
Step 11 – Ongoing Maintenance
Set up regular tasks to ensure long term security:
- Apply security updates promptly.
- Monitor logs for suspicious activity.
- Review user permissions.
- Test backups regularly.
- Keep software up to date.
Conclusion
With these steps, you now have a secure Drupal 10 installation tuned for performance, with protections against common vulnerabilities.
Be sure to follow security best practices moving forward to ensure your Drupal site remains hardened over time. Enable logging/monitoring and apply a “defense in depth” strategy with multiple layers of security.
Stay vigilant about emerging threats by following Drupal security advisories. Automate patches to ensure you don’t miss critical updates.
With ongoing hardening and proactive maintenance, you can confidently build out your Drupal functionality while keeping the backend locked down from intruders.
Alternative Solutions
While the guide presents a comprehensive approach to securing a Drupal website, alternative strategies can further enhance its security posture. Here are two different ways to solve the problem of securing a Drupal installation, offering different approaches and potential benefits:
1. Containerization with Docker and Automated Security Updates
Instead of directly installing Drupal on the server, leverage containerization with Docker. This approach isolates the Drupal application and its dependencies within a container, enhancing security and simplifying deployment.
Explanation:
Docker containers provide a sandboxed environment, limiting the impact of potential vulnerabilities within the Drupal application. Furthermore, using a Docker image based on a security-focused Linux distribution (like Alpine Linux) minimizes the attack surface.
The key to security with this approach lies in automated image updates. You can use tools like Docker Hub’s automated builds or other CI/CD pipelines to automatically rebuild and deploy your Drupal container whenever a new security patch is released for the base image or Drupal itself.
Code Example (Docker Compose):
version: "3.8"
services:
drupal:
image: drupal:10-php8.2-apache-alpine #Use an alpine version of the drupal image
ports:
- "80:80"
volumes:
- drupal_modules:/var/www/html/modules
- drupal_themes:/var/www/html/themes
- drupal_sites:/var/www/html/sites
environment:
- DRUPAL_DB_HOST=db
- DRUPAL_DB_NAME=drupal
- DRUPAL_DB_USER=drupal
- DRUPAL_DB_PASS=password
depends_on:
- db
db:
image: mariadb:10.11
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=drupal
- MYSQL_USER=drupal
- MYSQL_PASSWORD=password
volumes:
- drupal_data:/var/lib/mysql
volumes:
drupal_modules:
drupal_themes:
drupal_sites:
drupal_data:
Benefits:
- Isolation: Limits the impact of security breaches.
- Reproducibility: Ensures consistent deployment across environments.
- Simplified Updates: Automated builds streamline security patching.
- Rollbacks: Easy rollback to previous versions in case of issues.
2. Implementing a Content Security Policy (CSP)
A Content Security Policy (CSP) is an HTTP response header that allows you to control the resources that the browser is allowed to load for your Drupal website. This is a powerful defense against Cross-Site Scripting (XSS) attacks.
Explanation:
By defining a CSP, you explicitly whitelist the origins from which your Drupal site can load resources like scripts, stylesheets, images, and fonts. Any attempt to load resources from an unauthorized origin will be blocked by the browser. This significantly reduces the risk of XSS attacks, as malicious scripts injected into your site will be prevented from executing if their origin is not whitelisted in the CSP.
Code Example (modifying Drupal’s .htaccess or Virtual Host configuration):
In your Apache virtual host configuration file (e.g., /etc/apache2/sites-available/drupal10.conf
), add the following header:
<VirtualHost *:80>
# ... other configurations ...
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';"
# ... other configurations ...
</VirtualHost>
Explanation of the CSP directive:
default-src 'self'
: By default, only allow resources from the same origin as the Drupal site.script-src 'self' 'unsafe-inline' https://www.google-analytics.com
: Allow scripts from the same origin and inline scripts (use with caution, consider using nonces instead) and from Google Analytics.style-src 'self' 'unsafe-inline'
: Allow stylesheets from the same origin and inline styles (same caution as inline scripts).img-src 'self' data:
: Allow images from the same origin and data URIs (base64 encoded images).font-src 'self'
: Allow fonts from the same origin.
Important Considerations:
- Testing: Start with a report-only CSP (
Content-Security-Policy-Report-Only
) to monitor violations without blocking resources. - Specificity: Tailor the CSP to your specific site’s needs, whitelisting only the necessary origins.
- Nonces/Hashes: For greater security, use nonces or hashes for inline scripts and styles instead of
'unsafe-inline'
. - Module Compatibility: Some Drupal modules might require specific CSP configurations.
Benefits:
- Strong XSS Protection: Significantly reduces the risk of XSS attacks.
- Granular Control: Allows fine-grained control over resource loading.
- Improved Security Posture: Enhances overall website security.
By combining these alternative solutions with the comprehensive steps outlined in the original guide, you can create a highly secure and resilient Drupal website. Remember that security is an ongoing process, and regular monitoring, updates, and adjustments are crucial to maintaining a robust defense against emerging threats.