Advertising sustains the DA. Ads are hidden for members. Join today

Security in Drupal

Moving all PHP files out of the docroot

Last updated on
21 February 2025

This documentation needs review. See "Help improve this page" in the sidebar.

Traditionally all Drupal core, vendor and module PHP files are in the webserver accessible document root folder. This is a security weakness because Remote Code Execution vulnerabilities are found all the time when random PHP files are directly accessible. For example Drupal 8.2.7 had to fix a vulnerability in the vendor directory where a library shipped a PHP file exploitable by directly accessing it.

It is possible to run a Drupal 8 site with a clean docroot folder that does not contain code files and is therefore a lot more secure by default.

Core patch for image styles

To make image style generation work apply the image style system patch.

Directory setup

Assuming you have a Drupal 8 folder like this:

drupal-8
- core
- index.php
- modules
- profiles
- sites
- themes
- vendor

Create a new folder "docroot" in your Drupal 8 folder, so it looks like this:

drupal-8
- core
- docroot
- index.php
- modules
- profiles
- sites
- themes
- vendor

docroot will be the new folder that the webserver points to.

Webserver config change

Point your webserver config to the new docroot subfolder.
Apache example:

<VirtualHost *:80>
        ServerAlias drupal-8.localhost
        DocumentRoot /home/klausi/workspace/drupal-8/docroot
        <Directory "/home/klausi/workspace/drupal-8/docroot">
                Options FollowSymLinks
                AllowOverride All
                Require all granted
        </Directory>
</VirtualHost>

Nginx example:

server {
        server_name drupal-8.localhost;
        root /home/klausi/workspace/drupal-8/docroot;
        # Other config options here ...
}

index.php and robots.txt in docroot

Create a small index.php file in the docroot folder that will just include the index.php file from Drupal core:

chdir('..');
require 'index.php';

Create links for robots.txt (and .htaccess if using Apache) in the docroot folder:

cd docroot
ln -s ../robots.txt
ln -s ../.htaccess

Public files directory

Create a folder for public files in docroot/files. It must be writeable by the webserver.

mkdir docroot/files

Edit your settings.php file (usually sites/default/settings.php) and set the following:

$settings['file_public_path'] = 'docroot/files';
// Replace http://drupal-8.localhost with your site's URL or $base_url if you have defined that.
$settings['file_public_base_url'] = 'http://drupal-8.localhost/files';

rsync script to mirror asset files

Since Drupal core and modules ship with JavaScript, CSS and image files we need to copy those to the webserver accessible docroot with a script like this placed in the old document root:

#!/bin/bash

SYNC_FOLDERS="core libraries modules profiles themes"

for DIR in $SYNC_FOLDERS; do
  rsync -mr --include='*.'{js,css,svg,png,jpg,jpeg,ico} --include='*/' --exclude='*' $DIR/ docroot/$DIR/
done

Execute this script every time you do a deployment. It can be part of your deployment script that runs git pull, composer install and drush updb for example.

Conclusion

Congratulations! You have now a much more secure Drupal 8 installation that has zero code files in the publicly accessible document root.

Help improve this page

Page status: Needs review

You can: