Secure WordPress site using htaccess

Here I am going to show you how to secure your WordPress content management site using .htaccess file. .htaccess file is a very ancient and one of the most powerful configuration files that controls the Web Server settings which runs your website. The powerful .htaccess file has the ability to control access of the www’s (World Wide Web) HTTP (Hyper Text Transfer Protocol) using Password Protection, Error Page Redirects, 301 Redirects, URL rewrites etc.

There is already a .htaccess file inside the WordPress’s root directory and the typical wordpress .htaccess file looks similar to the following:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

So please be careful while you add more directives to the existing .htaccess file. Do not break wordpress based functionalities by editing between #BEGIN WordPress and # END WordPress.

You may also like to read Top twenty htaccess security directives.

The essential directives can be added to the .htaccess file as shown below. If I don’t mention Apache version for any directive then the directive will work for both Apache 2.2 and 2.4 versions.

1. Prevent .htaccess file itself from external access using the following directive. You don’t need to create separate .htaccess file for this.

For Apache 2.2 use following directive:

<Files .htaccess>
 order deny,allow
 deny from all
</Files>

For Apache 2.4 use following directive:

<Files .htaccess>
 Require all denied
</Files>

2. Protect your wp-config file because it contains various configurations for site files as well as database details. You don’t need to create separate .htaccess file for this.

For Apache 2.2 use following directive:

<Files wp-config.php>
 order deny,allow
 deny from all
</Files>

For Apache 2.4 use following directive:

<Files wp-config.php>
 Require all denied
</Files>

3. Prevent directory browsing. The following directive will not allow anyone to browse the directory in the browser. Suppose you have a project directory structure like application/config and a user wants to see what are the files inside the directory config. So user will type a URL in the browser something like https://www.example.com/application/config and user will be able to see all the files inside the config directory.

To prevent such kind of thing we need the following directive. You don’t need to create separate .htaccess file for this.

Options All -Indexes

4. Hotlinking refers to linking directly to non-html objects on other servers, such as images, movie, css, zip, pdf files etc. This can greatly impact bandwidth usage. Hotlink protection can save you lots of bandwidth by preventing other sites from displaying your non-html. You don’t need to create separate .htaccess file for this. Make sure you replace the example.com by your actual domain name.

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)example.com/.*$ [NC]
RewriteRule \.(gif|jpg|jpeg|jpe|png|bmp|zip|rar|mp3|flv|swf|xml|php|png|css|pdf)$ - [F]

5. Do not display server signature when an error occurs in the requested URL. You don’t need to create separate .htaccess file for this. By knowing the version of the server hackers may exploit your server.

ServerSignature Off

6. Stop spam – a form of spamdexing done by posting random comments, copied material, or promotion of commercial services. Spammers use bots to post comments on blogs and they come from nowhere. You don’t need to create separate .htaccess file for this.

RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER} !.*example.com.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]

7. You can restrict the access to the wp-admin directory only to your IP address or from certain IP addresses. If there is no .htaccess file in the wp-admin directory, create one and upload it to the wp-admin directory and add the below line to it.

If you want to restrict from only one IP address:

For Apache 2.2,

order deny, allow
deny from all
allow from x.x.x.x

For Apache 2.4,

Require ip x.x.x.x

Replace x.x.x.x with actual IP address.

If you want to restrict from multiple IP addresses:

For Apache 2.2,

order deny, allow
deny from all
allow from x.x.x.x
allow from y.y.y.y
allow from z.z.z.z

For Apache 2.4,

Require ip x.x.x.x
Require ip y.y.y.y
Require ip z.z.z.z

where x.x.x.x, y.y.y.y or z.z.z.z should be replaced by actual IP addresses.

8. The wp-content folder contains images, themes, plug-ins etc. and it’s a very important folder because apart from media files it contains sensitive .php files to which external access should be prevented. Create a separate .htaccess file and put the it under wp-content directory with the below content.

For Apache 2.2,

order deny,allow
deny from all
<files ~ ".(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$">
allow from all
</files>

For Apache 2.4,

<files ~ ".(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$">
	Require all granted
</files>

9. Sometimes you don’t need to protect the whole directory instead you can protect individual file so in this case you can use following directive.

For example, if you want to protect the file ‘abc’. You don’t need to create separate .htaccess file for this.

For Apache 2.2,

<files abc>
   order allow,deny
   deny from all
</files>

For Apache 2.4,

<files abc>
	Require all denied
</files>

10. Cache Certain file types, saving bandwidth and decreasing load times. You don’t need to create separate .htaccess file for this. These are static files and changes in these files are very rare.

# 1 YEAR
<FilesMatch "\.(ico)$">
	Header set Cache-Control "max-age=29030400, public"
</FilesMatch>

# 1 MONTH
<FilesMatch "\.(jpg|jpeg|png|gif|swf|css|js)$">
	Header set Cache-Control "max-age=2689743, public"
</FilesMatch>

# 2 DAYS
<FilesMatch "\.(xml|txt|html|php)$">
	Header set Cache-Control "max-age=172800, proxy-revalidate"
</FilesMatch>

11. Removes trailing slash from URL. It prevents SEO duplicate content issue. You don’t need to create separate .htaccess file for this and you can put under the root project’s .htaccess file.

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [L,R=301]

12. Restrict access to Include only files under wp-includes directory. You don’t need to create separate .htaccess file for this.

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteRule ^wp-admin/includes/ - [F,L]
	RewriteRule !^wp-includes/ - [S=3]
	RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
	RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
	RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

13. Restrict access to wordpress admin area. create a new .htaccess file and put it under wp-admin directory with the following content.

If you want to allow from only one IP address.

For Apache 2.2,

<Limit GET POST PUT>
	order deny,allow
	deny from all
	allow from x.x.x.x
</Limit>

For Apache 2.4,

<Limit GET POST PUT>
	Require ip x.x.x.x
</Limit>

If you want to allow from multiple IP addresses.

For Apache 2.2,

<Limit GET POST PUT>
	order deny, allow
	Allow from x.x.x.x
	Allow from y.y.y.y
	Allow from z.z.z.z
	deny from all
</Limit>

For Apache 2.4,

<Limit GET POST PUT>
	Require ip x.x.x.x
	Require ip y.y.y.y
	Require ip z.z.z.z
</Limit>

where x.x.x.x, y.y.y.y or z.z.z.z should be replaced by actual IP addresses.

14. The following code helps prevent executable scripts like .pl, .cgi or .php scripts from being executed when requested by a browser. This instructs the Web Server to treat them as text files instead of executables. The result is they will be displayed as plain text inside the browser window.

<FilesMatch "\.(php|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
     ForceType text/plain
</FilesMatch>

That’s all. You can also check Top 20 security directives for htaccess for additional security implementation.

Leave a Comment