Secure Apache configuration for WordPress & SSL

Apache runs nearly 50% of all active websites
Apache runs nearly 50% of all active websites

Recently I moved the hosting for from a regular hosted platform called WPWebhost to my own Virtual machine on digitalOcean. The results have been great, but the migration process was a bit tedious and took some effort.

I thought I’d share my Apache configurations, so that if you’re thinking of hosting your own WordPress site on an SSL server, you’ll at least have a solid base to start off from. I’m by no means an expert here, but this is what makes sense to me, and if you have any feedback please let me know in the comments.

So let’s start.

If you install wordpress from the one-click install on digitalOcean, by default you get an Ubuntu Linux instance with Apache2 installed. Apache2 has two configurations file:




By default, the second file is optional and probably doesn’t exist, but my preference was to create it, and keep the virtual host definitions here, while storing the general apache settings in the apache2.conf file.

The contents of each file can be downloaded here. For now, I’ll go through the key elements in each to ensure we have a safe configuration.

1. Hide Apaches sensitive information

ServerSignature Off
ServerTokens Prod

By setting ServerSignature to ‘Off’ and ServerTokens to ‘Prod’, you’re essentially telling Apache to not reveal its version number or other essential information to the outside world. True, this is somewhat security through obscurity, but the less information the bad guys know, the less likely they are to attack you.

A common attack pattern is and attacker will take an already known exploit and then search the web for vulnerable servers on Shodan or just automating a process of request information from a bunch of IPs. Once they determined the version of software you’re running they can then determine if you’re vulnerable (and then they exploit you) or if you’re patched (in which case they move on).

If the attackers are unable to determine the version of software you’re running you’ll be in much better shape.

2. Ensure Apache isn’t run as root.


Apache needs to be run as a user, and by default the DigitalOcean image runs it as www-data, which is the same user as WordPress. What this means is that if Apache were ever compromised it still won’t be able to reconfigure itself because only root is able to change the configuration files (make sure the configuration files have a 0644 permissions and are owned by root).

You always have the option of running Apache under a totally different user, so that even WordPress and Apache are isolated, but I think this is good enough.

*the user information is stored in /etc/apache2/envvars

3. Restrict access to non-www folders

<Directory />
 Order Deny,Allow
 Deny from all
 Options None
 AllowOverride None
 deny from all

And then in the 000-default.conf file:

 <Directory /var/www/>
 Options Indexes FollowSymLinks MultiViews
 AllowOverride All
 Order allow,deny
 allow from all

These 2 snippets of code ensure that only files in the /var/www/ directory is served, and restricts access to all other directories. Of course depending on your implementation ‘/var/www/‘ could be any directory you determine to be your wordpress installation.

Limiting access from web users, to only those folders you designate for web access isn’t just good practice, it’s good security 🙂

4. Re-direct non-SSL traffic to SSL

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

My blog is an SSL/TLS blog and this directive found inside the Virtualhost *:80 re-directs all traffic from port 80 to port 443 and https.

There are other ways to do this, and you could also run this in the .htaccess file for wordpress,but I try to avoid using the .htaccess file for anything other than apache configurations that wordpress plug-ins need to modify.

A general rule of thumb though is to remove the .htaccess file entirely, which makes it much easier, since nothing in the web accessible folders can change apache configurations. Another less secure way is to change the owner of .htaccess to root, and change it back only when changes are needed (which shouldn’t be too often).

5. Setup SSL ‘correctly’

SSLEngine on 
SSLProtocol all -SSLv2 -SSLv3 
SSLHonorCipherOrder on 

This one is a bit tricky, but there’s a lot of debate as to what is the ‘correct’  SSL implementation, and the controversy is focused on the Ciphersuite.

You see in order to be secure, it’s recommended you turn off all vulnerable protocols and Ciphers. Which makes perfect sense.

Turning of SSL3 is a no-brainer, but there’s a debate about the use of RC4 in the CipherSuite as well as the best priority ciphers. The example above is what I took from the Mozilla Foundation which removes support for RC4, utilizes Perfect Forward Secrecy for all but the oldest browsers, and scored me an ‘A’ in my SSLLabs test (sweeet!!)

But, there’s a whole chunk of people out there who are running antiquated browsers on antiquated Operating systems, like Internet Explorer 6 on Windows XP. If you want to reach everyone, you can’t be fully secure–and if you want to be fully secure, you’ll have to deny entry to some. These trade-offs shouldn’t be made lightly and you’ll have to evaluate them based on your own personal considerations.

6. Setup Basic Auth for wp-admin

 <DirectoryMatch ^.*/wp-admin/>
 AuthType Basic
 AuthName "Restricted Area"
 AuthUserFile /etc/apache2/.htpasswd
 Require valid-user

The snippet above, found in the apache2.conf file is used to authenticate users access to anything in the /wp-admin section of WordPress. This is an Apache level authentication, and will be authenticated against a list of Apache users found in the .htpasswd file (from the example above). Note this isn’t authenticated against root or www-data, those are OS users. More info here.

While this isn’t 2FA (since both factors are username/passwords), because 2 applications would be authenticating access to the wp-admin section (i.e. WordPress and Apache), it provides some solid security as most WordPress exploits would be limited without access to wp-admin, and that’s the most likely attack vector on the WordPress site. In other words, in order for an attacker to gain admin privileges on your WordPress site, they’d need to crack both WordPress and Apache.

That being said this is a pain for most users, and the pain may not commensurate with the security it gives, but I use it.

7. HTTP Strict Transport Security

#Header add Strict-Transport-Security "max-age=3600"

I commented out this, since I’m still putting changes on my blog. HSTS is a double-edge sword so you must be careful.What HSTS will do is tell the users browser that your site will continue using SSL/TLS for the next x seconds, where x is the max-age parameter of the configuration. (*the highest possible value is 2 years long, and SSLLabs recommends at least 180 days)

If the browser ever detects that your site is not using SSL/TLS within this time it will prompt and error and not allow the user to view the site. Resetting the setting on the users end is quite tedious, and possibly beyond the capability of most users. Essentially once you set this value to something like 180 days or more, you’ll be forcing yourself to use SSL/TLS damn near forever, and if you ever lost the ability to serve up an SSL/TLS connection you’ll be unable to reach your readers any more–period.

8. Give me feedback

If you’re an Apache guru, or just a web-master

extro-di-naire, please leave me comments where you think the security could be improved. Otherwise these are the configurations I run on my website, and hopefully they can help you with yours.

Add comment

Astound us with your intelligence