Drupal Server Security

This article assumes you’ve decided to try hosting on your own - casting aside the professional, Drupal-specialized hosting of companies like Acquia or Pantheon. This chapter will apply whether you’ve decided to host hardware in your own building or configure a virtual machine with a cloud host like Linode or DigitalOcean.

Note, Acquia and Pantheon have invested thousands of hours and millons of dollars to create an infrastructure for high availability, security, and other enterprise jargon. I haven’t worked for either company, and I suspect if I had, I wouldn’t be allowed to sell all their secrets in this book. This chapter covers a base of configuration that will harden your hosting environment to protect against most popular vulnerability scanning tools and cracking attempts by professional auditors. It also only tries to frame configuration instructions in the frame of a Debian server environment.

General rules

As a general principle, as few software packages should be installed and enabled as are necessary. Your web application server should not double as a mail server, Tor router, NTP host, OpenVPN anonymizer, or IRC proxy.

Following this principle also means following some less-obvious details, like not using CPanel or PLESK for server configuration or phpMyAdmin for database administration. Using tools of these sorts creates additional security attack vectors - they increase the attack surface area.

I’m amused by configuration advice to create iptables rules for a local firewall. I think a better policy is to not run software you don’t want the Internet to access. In the cases where you do want filters, most Drupal-related software has alternative configurations for access control.


Use a program like denyhosts or fail2ban if you expose your SSH service to the general Internet.


Generate strong private keys for authenticating to SSH.

ssh-keygen -t ecdsa -b 521
ssh-keygen -t rsa -b 15360


Hard-code .htaccess file locations

The default configuration of the default-ssl file sets AllowOverride to None. Many Apache configuration recommendations say to change the None to All. I’ve done that myself and did for years.

When you change AllowOverride to All, Apache scans through all the subdirectories in your Drupal installation looking for .htaccess files to override security settings on a per-directory basis. The full directory scan on every page request is wasteful for both page load times and server resources. The locations of .htaccess files are predictable - one at /var/www/ and the other for private file uploads like /var/private.

Leave your AllowOverride setting at the default, but create a new Include file to point to specific .htaccess file locations. Your new configuration file at /etc/apache2/conf.d/htaccess.conf can make specific inclusions for .htaccess file locations. Not only should it add some speed to each page request, but it keeps a rouge .htaccess file from modifying your directory controls outside your knowledge.


<Directory /var/www>
  Include /var/www/.htaccess
<Directory /var/www/sites/default/files>
  Include /var/www/sites/default/files/.htaccess
<Directory /var/private>
  Include /var/private/.htaccess

Classic Graphics scripted their software deployments and provided their deploy-site script on GitHub. It contains a segment at the bottom, after code is rsynced to scan various www directories for .htaccess files and add them to the Apache configuration as an automatic process during deployments.

Disable Options

The default configuration at /etc/apache/sites-available/default

 <Directory /var/www/>
-  Options Indexes FollowSymLinks MultiViews
+  Options -Indexes FollowSymLinks -MultiViews
   AllowOverride None
   Order allow,deny
   allow from all
   <Files ~ "^install.php">
     Order deny,allow
     Deny from all

 Include htaccess.d/

Remove Apache signature

Minimize the information Apache reveals about itself.


ServerTokens Prod
ServerSignature Off
TraceEnable Off



short_open_tag = Off
expose_php = Off
html_errors = Off


Patch settings.php for MySQL SSL connection information


MySQL can require connections to use SSL on a per-account basis. By using SSL, connections to MySQL would require an additional certificate pair to connect to a remote database.

Ideally, the database would also be protected behind an additional firewall layer.




See also