Protecting Drupal's fleshy underbelly with .htaccess

In this article, I’m going to show you a few methods to separate your public site from the vulnerable parts of your administration area. What you need is an effective way to keep your site locked and secure, and protected from attacks, while still leaving your site editable for trusted users.

Methods for securing the admin section of your site

One of the things that is often overlooked when setting up and securing a Drupal site is the administrative sections. Sure, Drupal protects these paths with access controls but you can do a lot more to protect your site, especially if your site doesn’t require public login.

If the public has no business accessing /user, they shouldn’t be able to. This path is an attack vector for denial of service (DDoS), brute force password guessing, and it drastically increases attack surface of the site.

Public/administrative separation has the additional benefit of protecting against some types of XSS and CSRF.

A typical server setup for Drupal might look something like this.

typical Drupal server infrastructure

This diagram shows how public traffic and your administrators/content editors access the site from the same paths and web servers. For example, your public site is and your administrators/content editors login to site via

Don’t get me wrong, this is a tried and true method and serves the majority of the use cases out there. But we can do better. Your content administrators/content editors don’t need to be logging into the public site.

alternative Drupal server infrastructure

This diagram shows the administration edit server locked behind a secure DMZ firewall. I like this setup since now you have separated your public side and your administrative side. But how do you go about it?

Set up rewrite rules for .htaccess

On your public web servers run an .htaccess rule similar to the rule below. (If you are using Drupal 6, you should drop the dash.) There are a couple of caveats to be aware of, so you may need to tweak the rule to remove cron.php or xmlrpc.php.

RewriteRule ^(scripts|profile|includes|cron\.php|install\.php|update\.php|xmlrpc\.php|filter($|/)|user($|/)|admin($|/)) - [F,L]

This rewrite rule will trigger a 403 for a request to some of the sensitive areas of your Drupal site. For instance, will now return 404. On the administrative server, you can just drop the rewrite rule or add a RewriteCond for a specific hostname or IP address. Check this article out if you are interested in learning more about .htaccess or mod_rewrite.

RewriteCond %{REMOTE_ADDR} !^123\.45\.67\.8[0-9]$
RewriteRule ^(scripts|profile|includes|cron\.php|install\.php|update\.php|xmlrpc\.php|filter($|/)|user($|/)|admin($|/)) - [F,L]

or maybe even using a specific hostname to access the administrative side:

RewriteCond %{HTTP_HOST} !^ # or some other obfuscated path
RewriteRule ^(scripts|profile|includes|cron\.php|install\.php|update\.php|xmlrpc\.php|filter($|/)|user($|/)|admin($|/)) - [F,L]

In fact, with a RewriteCond you don’t need to have a completely separate administrative server.

alternative Drupal server infrastructure

Now you have public/administrative separation without the extra cost and overhead of maintaining another web server.

It’s a small .htaccess configuration, but it drastically increases the security of your site.

Attend our DrupalCon course on Drupal Security

Speaking of security, if you’re going to DrupalCon Portland and want to learn more about Drupal security (and meet me, Cash, and Ben) sign up for our pre-conference training.

Originally published on